@@ -558,6 +558,8 @@ def values(self) -> _ValuesView[_V]:
558
558
def __eq__ (self , other : object ) -> bool :
559
559
if not isinstance (other , Mapping ):
560
560
return NotImplemented
561
+ if isinstance (other , MultiDictProxy ):
562
+ return self == other ._md
561
563
if isinstance (other , _Base ):
562
564
lft = self ._impl ._items
563
565
rht = other ._impl ._items
@@ -633,7 +635,9 @@ def _extend(
633
635
method : Callable [[list [tuple [str , str , _V ]]], None ],
634
636
) -> None :
635
637
if arg :
636
- if isinstance (arg , (MultiDict , MultiDictProxy )):
638
+ if isinstance (arg , MultiDictProxy ):
639
+ arg = arg ._md
640
+ if isinstance (arg , MultiDict ):
637
641
if self ._ci is not arg ._ci :
638
642
items = [(self ._title (k ), k , v ) for _ , k , v in arg ._impl ._items ]
639
643
else :
@@ -845,21 +849,98 @@ class CIMultiDict(_CIMixin, MultiDict[_V]):
845
849
"""Dictionary with the support for duplicate case-insensitive keys."""
846
850
847
851
848
- class MultiDictProxy (_CSMixin , _Base [_V ]):
852
+ class MultiDictProxy (_CSMixin , MultiMapping [_V ]):
849
853
"""Read-only proxy for MultiDict instance."""
854
+ _md : MultiDict [_V ]
850
855
851
856
def __init__ (self , arg : Union [MultiDict [_V ], "MultiDictProxy[_V]" ]):
852
857
if not isinstance (arg , (MultiDict , MultiDictProxy )):
853
858
raise TypeError (
854
859
"ctor requires MultiDict or MultiDictProxy instance"
855
860
f", not { type (arg )} "
856
861
)
857
-
858
- self ._impl = arg ._impl
862
+ if (isinstance (arg , MultiDictProxy )):
863
+ self ._md = arg ._md
864
+ else :
865
+ self ._md = arg
859
866
860
867
def __reduce__ (self ) -> NoReturn :
861
868
raise TypeError (f"can't pickle { self .__class__ .__name__ } objects" )
862
869
870
+ @overload
871
+ def getall (self , key : str ) -> list [_V ]: ...
872
+ @overload
873
+ def getall (self , key : str , default : _T ) -> Union [list [_V ], _T ]: ...
874
+ def getall (
875
+ self , key : str , default : Union [_T , _SENTINEL ] = sentinel
876
+ ) -> Union [list [_V ], _T ]:
877
+ """Return a list of all values matching the key."""
878
+ if default is not sentinel :
879
+ return self ._md .getall (key , default )
880
+ else :
881
+ return self ._md .getall (key )
882
+
883
+ @overload
884
+ def getone (self , key : str ) -> _V : ...
885
+ @overload
886
+ def getone (self , key : str , default : _T ) -> Union [_V , _T ]: ...
887
+ def getone (
888
+ self , key : str , default : Union [_T , _SENTINEL ] = sentinel
889
+ ) -> Union [_V , _T ]:
890
+ """Get first value matching the key.
891
+
892
+ Raises KeyError if the key is not found and no default is provided.
893
+ """
894
+ if default is not sentinel :
895
+ return self ._md .getone (key , default )
896
+ else :
897
+ return self ._md .getone (key )
898
+
899
+ # Mapping interface #
900
+
901
+ def __getitem__ (self , key : str ) -> _V :
902
+ return self .getone (key )
903
+
904
+ @overload
905
+ def get (self , key : str , / ) -> Union [_V , None ]: ...
906
+ @overload
907
+ def get (self , key : str , / , default : _T ) -> Union [_V , _T ]: ...
908
+ def get (self , key : str , default : Union [_T , None ] = None ) -> Union [_V , _T , None ]:
909
+ """Get first value matching the key.
910
+
911
+ If the key is not found, returns the default (or None if no default is provided)
912
+ """
913
+ return self ._md .getone (key , default )
914
+
915
+ def __iter__ (self ) -> Iterator [str ]:
916
+ return iter (self ._md .keys ())
917
+
918
+ def __len__ (self ) -> int :
919
+ return len (self ._md )
920
+
921
+ def keys (self ) -> KeysView [str ]:
922
+ """Return a new view of the dictionary's keys."""
923
+ return self ._md .keys ()
924
+
925
+ def items (self ) -> ItemsView [str , _V ]:
926
+ """Return a new view of the dictionary's items *(key, value) pairs)."""
927
+ return self ._md .items ()
928
+
929
+ def values (self ) -> _ValuesView [_V ]:
930
+ """Return a new view of the dictionary's values."""
931
+ return self ._md .values ()
932
+
933
+ def __eq__ (self , other : object ) -> bool :
934
+ return self ._md == other
935
+
936
+ def __contains__ (self , key : object ) -> bool :
937
+ return key in self ._md
938
+
939
+ @reprlib .recursive_repr ()
940
+ def __repr__ (self ) -> str :
941
+ body = ", " .join (f"'{ k } ': { v !r} " for k , v in self .items ())
942
+ return f"<{ self .__class__ .__name__ } ({ body } )>"
943
+
863
944
def copy (self ) -> MultiDict [_V ]:
864
945
"""Return a copy of itself."""
865
946
return MultiDict (self .items ())
@@ -875,14 +956,16 @@ def __init__(self, arg: Union[MultiDict[_V], MultiDictProxy[_V]]):
875
956
f", not { type (arg )} "
876
957
)
877
958
878
- self . _impl = arg . _impl
959
+ super (). __init__ ( arg )
879
960
880
961
def copy (self ) -> CIMultiDict [_V ]:
881
962
"""Return a copy of itself."""
882
963
return CIMultiDict (self .items ())
883
964
884
965
885
966
def getversion (md : Union [MultiDict [object ], MultiDictProxy [object ]]) -> int :
886
- if not isinstance (md , _Base ):
967
+ if isinstance (md , MultiDictProxy ):
968
+ md = md ._md
969
+ elif not isinstance (md , MultiDict ):
887
970
raise TypeError ("Parameter should be multidict or proxy" )
888
971
return md ._impl ._version
0 commit comments