[docs]classMultiDictProxy(MutableMapping):""" 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:MutableMapping,schema:ma.Schema,known_multi_fields:tuple[type,...]=(ma.fields.List,ma.fields.Tuple,),):self.data=multidictself.known_multi_fields=known_multi_fieldsself.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 criteriais_multiple_attr=getattr(field,"is_multiple",None)ifis_multiple_attrisnotNone:returnis_multiple_attrreturnisinstance(field,self.known_multi_fields)def_collect_multiple_keys(self,schema:ma.Schema)->set[str]:result=set()forname,fieldinschema.fields.items():ifnotself._is_multiple(field):continueresult.add(field.data_keyiffield.data_keyisnotNoneelsename)returnresultdef__getitem__(self,key:str)->typing.Any:val=self.data.get(key,ma.missing)ifvalisma.missingorkeynotinself.multiple_keys:returnvalifhasattr(self.data,"getlist"):returnself.data.getlist(key)ifhasattr(self.data,"getall"):returnself.data.getall(key)ifisinstance(val,(list,tuple)):returnvalifvalisNone:returnNonereturn[val]def__str__(self)->str:# str(proxy) proxies to str(proxy.data)returnstr(self.data)def__repr__(self)->str:return(f"MultiDictProxy(data={self.data!r}, multiple_keys={self.multiple_keys!r})")def__delitem__(self,key:str)->None:delself.data[key]def__setitem__(self,key:str,value:typing.Any)->None:self.data[key]=valuedef__getattr__(self,name:str)->typing.Any:returngetattr(self.data,name)def__iter__(self)->typing.Iterator[str]:forxiniter(self.data):# special case for header dicts which produce an iterator of tuples# instead of an iterator of stringsifisinstance(x,tuple):yieldx[0]else:yieldxdef__contains__(self,x:object)->bool:returnxinself.datadef__len__(self)->int:returnlen(self.data)def__eq__(self,other:object)->bool:returnself.data==otherdef__ne__(self,other:object)->bool:returnself.data!=other