11"""Test to_dict functionality for all multidict types."""
22
3- from typing import Any , Callable , Type
3+ from typing import Any , Callable , Type , Iterable
44from multidict import MultiMapping
55
6+
7+ from typing import Protocol
8+
9+
10+ from typing import Protocol , Type
11+ from multidict import MultiDict , CIMultiDict , MultiDictProxy , CIMultiDictProxy
12+
13+ class MultidictModule (Protocol ):
14+ MultiDict : Type [MultiDict [object ]]
15+ CIMultiDict : Type [CIMultiDict [object ]]
16+ MultiDictProxy : Type [MultiDictProxy [object ]]
17+ CIMultiDictProxy : Type [CIMultiDictProxy [object ]]
18+
19+ class DictFactory (Protocol ):
20+ def __call__ (self , arg : Iterable [tuple [str , object ]] | None = None ) -> MultiMapping [object ]: ...
21+
622import pytest
723
824from multidict import CIMultiDict , CIMultiDictProxy , MultiDict , MultiDictProxy
1127class BaseToDictTests :
1228 """Base tests for to_dict() method, inherited by all multidict type tests."""
1329
14- def test_to_dict_simple (self , cls : Callable [..., MultiMapping [ Any ]] ) -> None :
30+ def test_to_dict_simple (self , cls : DictFactory ) -> None :
1531 """Test basic conversion with unique keys."""
1632 d = cls ([("a" , 1 ), ("b" , 2 )])
1733 result = d .to_dict ()
1834 assert result == {"a" : [1 ], "b" : [2 ]}
1935
20- def test_to_dict_multi_values (self , cls : Callable [..., MultiMapping [ Any ]] ) -> None :
36+ def test_to_dict_multi_values (self , cls : DictFactory ) -> None :
2137 """Test grouping multiple values under the same key."""
2238 d = cls ([("a" , 1 ), ("b" , 2 ), ("a" , 3 )])
2339 result = d .to_dict ()
2440 assert result == {"a" : [1 , 3 ], "b" : [2 ]}
2541
26- def test_to_dict_empty (self , cls : Callable [..., MultiMapping [ Any ]] ) -> None :
42+ def test_to_dict_empty (self , cls : DictFactory ) -> None :
2743 """Test conversion of an empty multidict."""
2844 d = cls ()
2945 result = d .to_dict ()
3046 assert result == {}
3147
3248 def test_to_dict_returns_new_dict (
33- self , cls : Callable [..., MultiMapping [ Any ]]
49+ self , cls : DictFactory
3450 ) -> None :
3551 """Test that each call returns a new dictionary instance."""
3652 d = cls ([("a" , 1 )])
@@ -39,22 +55,22 @@ def test_to_dict_returns_new_dict(
3955 assert result1 == result2
4056 assert result1 is not result2
4157
42- def test_to_dict_list_is_fresh (self , cls : Callable [..., MultiMapping [ Any ]] ) -> None :
58+ def test_to_dict_list_is_fresh (self , cls : DictFactory ) -> None :
4359 """Test that value lists are independent between calls."""
4460 d = cls ([("a" , 1 )])
4561 result1 = d .to_dict ()
4662 result2 = d .to_dict ()
4763 assert result1 ["a" ] is not result2 ["a" ]
4864
4965 def test_to_dict_order_preservation (
50- self , cls : Callable [..., MultiMapping [ Any ]]
66+ self , cls : DictFactory
5167 ) -> None :
5268 """Test that value lists maintain insertion order."""
5369 d = cls ([("x" , 3 ), ("x" , 1 ), ("x" , 2 )])
5470 result = d .to_dict ()
5571 assert result ["x" ] == [3 , 1 , 2 ]
5672
57- def test_to_dict_large_data (self , cls : Callable [..., MultiMapping [ Any ]] ) -> None :
73+ def test_to_dict_large_data (self , cls : DictFactory ) -> None :
5874 """Test to_dict with a large number of entries for performance."""
5975 items = [(f"key{ i % 100 } " , i ) for i in range (10000 )]
6076 d = cls (items )
@@ -63,7 +79,7 @@ def test_to_dict_large_data(self, cls: Callable[..., MultiMapping[Any]]) -> None
6379 assert all (len (v ) == 100 for v in result .values ())
6480
6581 def test_to_dict_mixed_value_types (
66- self , cls : Callable [..., MultiMapping [ Any ]]
82+ self , cls : DictFactory
6783 ) -> None :
6884 """Test to_dict with mixed value types (str, int) to verify generic _V."""
6985 d = cls ([("a" , 1 ), ("a" , "two" ), ("b" , 3.14 )])
@@ -76,19 +92,19 @@ class TestMultiDictToDict(BaseToDictTests):
7692 """Tests for MultiDict.to_dict()."""
7793
7894 @pytest .fixture
79- def cls (self , multidict_module : Any ) -> Type [MultiDict [Any ]]:
80- return multidict_module .MultiDict # type: ignore[no-any-return]
95+ def cls (self , multidict_module : MultidictModule ) -> Type [MultiDict [object ]]:
96+ return multidict_module .MultiDict
8197
8298
8399class TestCIMultiDictToDict (BaseToDictTests ):
84100 """Tests for CIMultiDict.to_dict()."""
85101
86102 @pytest .fixture
87- def cls (self , multidict_module : Any ) -> Type [CIMultiDict [Any ]]:
88- return multidict_module .CIMultiDict # type: ignore[no-any-return]
103+ def cls (self , multidict_module : MultidictModule ) -> Type [CIMultiDict [object ]]:
104+ return multidict_module .CIMultiDict
89105
90106 def test_to_dict_case_insensitive_grouping (
91- self , cls : Callable [..., MultiMapping [ Any ]]
107+ self , cls : DictFactory
92108 ) -> None :
93109 """Test that case variants are grouped under the same key."""
94110 d = cls ([("A" , 1 ), ("a" , 2 ), ("B" , 3 )])
@@ -106,19 +122,19 @@ class TestMultiDictProxyToDict(BaseToDictTests):
106122 """Tests for MultiDictProxy.to_dict()."""
107123
108124 @pytest .fixture
109- def cls (self , multidict_module : Any ) -> Any :
110- def make_proxy (* args : Any , ** kwargs : Any ) -> MultiDictProxy [ Any ]:
111- md = multidict_module .MultiDict (* args , ** kwargs )
112- return multidict_module .MultiDictProxy (md ) # type: ignore[no-any-return]
125+ def cls (self , multidict_module : MultidictModule ) -> DictFactory :
126+ def make_proxy (arg : Iterable [ tuple [ str , object ]] | None = None ) -> MultiMapping [ object ]:
127+ md : MultiDict [ object ] = multidict_module .MultiDict (arg ) if arg else multidict_module . MultiDict ( )
128+ return multidict_module .MultiDictProxy (md )
113129
114130 return make_proxy
115131
116132 def test_to_dict_proxy_mutation_isolation (
117- self , cls : Callable [..., MultiMapping [ Any ]], multidict_module : Any
133+ self , cls : DictFactory , multidict_module : MultidictModule
118134 ) -> None :
119135 """Test that modifying returned dict does not affect the proxy."""
120- md = multidict_module .MultiDict ([("a" , 1 )])
121- proxy = multidict_module .MultiDictProxy (md )
136+ md : MultiDict [ object ] = multidict_module .MultiDict ([("a" , 1 )])
137+ proxy : MultiMapping [ object ] = multidict_module .MultiDictProxy (md )
122138 result = proxy .to_dict ()
123139 result ["a" ].append (999 )
124140 assert proxy .getall ("a" ) == [1 ]
@@ -128,15 +144,15 @@ class TestCIMultiDictProxyToDict(BaseToDictTests):
128144 """Tests for CIMultiDictProxy.to_dict()."""
129145
130146 @pytest .fixture
131- def cls (self , multidict_module : Any ) -> Any :
132- def make_proxy (* args : Any , ** kwargs : Any ) -> CIMultiDictProxy [ Any ]:
133- md = multidict_module .CIMultiDict (* args , ** kwargs )
134- return multidict_module .CIMultiDictProxy (md ) # type: ignore[no-any-return]
147+ def cls (self , multidict_module : MultidictModule ) -> DictFactory :
148+ def make_proxy (arg : Iterable [ tuple [ str , object ]] | None = None ) -> MultiMapping [ object ]:
149+ md : CIMultiDict [ object ] = multidict_module .CIMultiDict (arg ) if arg else multidict_module . CIMultiDict ( )
150+ return multidict_module .CIMultiDictProxy (md )
135151
136152 return make_proxy
137153
138154 def test_to_dict_case_insensitive_grouping (
139- self , cls : Callable [..., MultiMapping [ Any ]]
155+ self , cls : DictFactory
140156 ) -> None :
141157 """Test that case variants are grouped under the same key."""
142158 d = cls ([("A" , 1 ), ("a" , 2 ), ("B" , 3 )])
@@ -150,11 +166,11 @@ def test_to_dict_case_insensitive_grouping(
150166 assert result [key_b ] == [3 ]
151167
152168 def test_to_dict_proxy_mutation_isolation (
153- self , cls : Callable [..., MultiMapping [ Any ]], multidict_module : Any
169+ self , cls : DictFactory , multidict_module : MultidictModule
154170 ) -> None :
155171 """Test that modifying returned dict does not affect the proxy."""
156- md = multidict_module .CIMultiDict ([("a" , 1 )])
157- proxy = multidict_module .CIMultiDictProxy (md )
172+ md : CIMultiDict [ object ] = multidict_module .CIMultiDict ([("a" , 1 )])
173+ proxy : MultiMapping [ object ] = multidict_module .CIMultiDictProxy (md )
158174 result = proxy .to_dict ()
159175 result ["a" ].append (999 )
160176 assert proxy .getall ("a" ) == [1 ]
0 commit comments