Source code for webargs.multidictproxy

import typing
from import Mapping

import marshmallow as ma

[docs] class MultiDictProxy(Mapping): """ A proxy object which wraps multidict types along with a matching schema Whenever a value is looked up, it is checked against the schema to see if there is a matching field where `is_multiple` is True. If there is, then the data should be loaded as a list or tuple. In all other cases, __getitem__ proxies directly to the input multidict. """ def __init__( self, multidict, schema: ma.Schema, known_multi_fields: typing.Tuple[typing.Type, ...] = ( ma.fields.List, ma.fields.Tuple, ), ): = multidict self.known_multi_fields = known_multi_fields self.multiple_keys = self._collect_multiple_keys(schema) def _is_multiple(self, field: ma.fields.Field) -> bool: """Return whether or not `field` handles repeated/multi-value arguments.""" # fields which set `is_multiple = True/False` will have the value selected, # otherwise, we check for explicit criteria is_multiple_attr = getattr(field, "is_multiple", None) if is_multiple_attr is not None: return is_multiple_attr return isinstance(field, self.known_multi_fields) def _collect_multiple_keys(self, schema: ma.Schema): result = set() for name, field in schema.fields.items(): if not self._is_multiple(field): continue result.add(field.data_key if field.data_key is not None else name) return result def __getitem__(self, key): val =, ma.missing) if val is ma.missing or key not in self.multiple_keys: return val if hasattr(, "getlist"): return if hasattr(, "getall"): return if isinstance(val, (list, tuple)): return val if val is None: return None return [val] def __str__(self): # str(proxy) proxies to str( return str( def __repr__(self): return ( f"MultiDictProxy(data={!r}, multiple_keys={self.multiple_keys!r})" ) def __delitem__(self, key): del[key] def __setitem__(self, key, value):[key] = value def __getattr__(self, name): return getattr(, name) def __iter__(self): for x in iter( # special case for header dicts which produce an iterator of tuples # instead of an iterator of strings if isinstance(x, tuple): yield x[0] else: yield x def __contains__(self, x): return x in def __len__(self): return len( def __eq__(self, other): return == other def __ne__(self, other): return != other