test_mutable_multidict.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. import string
  2. import sys
  3. import pytest
  4. class TestMutableMultiDict:
  5. @pytest.fixture
  6. def cls(self, _multidict):
  7. return _multidict.MultiDict
  8. @pytest.fixture
  9. def proxy_cls(self, _multidict):
  10. return _multidict.MultiDictProxy
  11. @pytest.fixture
  12. def istr(self, _multidict):
  13. return _multidict.istr
  14. def test_copy(self, cls):
  15. d1 = cls(key="value", a="b")
  16. d2 = d1.copy()
  17. assert d1 == d2
  18. assert d1 is not d2
  19. def test__repr__(self, cls):
  20. d = cls()
  21. assert str(d) == "<%s()>" % cls.__name__
  22. d = cls([("key", "one"), ("key", "two")])
  23. expected = "<%s('key': 'one', 'key': 'two')>" % cls.__name__
  24. assert str(d) == expected
  25. def test_getall(self, cls):
  26. d = cls([("key", "value1")], key="value2")
  27. assert len(d) == 2
  28. assert d.getall("key") == ["value1", "value2"]
  29. with pytest.raises(KeyError, match="some_key"):
  30. d.getall("some_key")
  31. default = object()
  32. assert d.getall("some_key", default) is default
  33. assert d.getall(key="some_key", default=default) is default
  34. def test_add(self, cls):
  35. d = cls()
  36. assert d == {}
  37. d["key"] = "one"
  38. assert d == {"key": "one"}
  39. assert d.getall("key") == ["one"]
  40. d["key"] = "two"
  41. assert d == {"key": "two"}
  42. assert d.getall("key") == ["two"]
  43. d.add("key", "one")
  44. assert 2 == len(d)
  45. assert d.getall("key") == ["two", "one"]
  46. d.add("foo", "bar")
  47. assert 3 == len(d)
  48. assert d.getall("foo") == ["bar"]
  49. def test_extend(self, cls):
  50. d = cls()
  51. assert d == {}
  52. d.extend([("key", "one"), ("key", "two")], key=3, foo="bar")
  53. assert d != {"key": "one", "foo": "bar"}
  54. assert 4 == len(d)
  55. itms = d.items()
  56. # we can't guarantee order of kwargs
  57. assert ("key", "one") in itms
  58. assert ("key", "two") in itms
  59. assert ("key", 3) in itms
  60. assert ("foo", "bar") in itms
  61. other = cls(bar="baz")
  62. assert other == {"bar": "baz"}
  63. d.extend(other)
  64. assert ("bar", "baz") in d.items()
  65. d.extend({"foo": "moo"})
  66. assert ("foo", "moo") in d.items()
  67. d.extend()
  68. assert 6 == len(d)
  69. with pytest.raises(TypeError):
  70. d.extend("foo", "bar")
  71. def test_extend_from_proxy(self, cls, proxy_cls):
  72. d = cls([("a", "a"), ("b", "b")])
  73. proxy = proxy_cls(d)
  74. d2 = cls()
  75. d2.extend(proxy)
  76. assert [("a", "a"), ("b", "b")] == list(d2.items())
  77. def test_clear(self, cls):
  78. d = cls([("key", "one")], key="two", foo="bar")
  79. d.clear()
  80. assert d == {}
  81. assert list(d.items()) == []
  82. def test_del(self, cls):
  83. d = cls([("key", "one"), ("key", "two")], foo="bar")
  84. assert list(d.keys()) == ["key", "key", "foo"]
  85. del d["key"]
  86. assert d == {"foo": "bar"}
  87. assert list(d.items()) == [("foo", "bar")]
  88. with pytest.raises(KeyError, match="key"):
  89. del d["key"]
  90. def test_set_default(self, cls):
  91. d = cls([("key", "one"), ("key", "two")], foo="bar")
  92. assert "one" == d.setdefault("key", "three")
  93. assert "three" == d.setdefault(key="otherkey", default="three")
  94. assert "otherkey" in d
  95. assert "three" == d["otherkey"]
  96. def test_popitem(self, cls):
  97. d = cls()
  98. d.add("key", "val1")
  99. d.add("key", "val2")
  100. assert ("key", "val1") == d.popitem()
  101. assert [("key", "val2")] == list(d.items())
  102. def test_popitem_empty_multidict(self, cls):
  103. d = cls()
  104. with pytest.raises(KeyError):
  105. d.popitem()
  106. def test_pop(self, cls):
  107. d = cls()
  108. d.add("key", "val1")
  109. d.add("key", "val2")
  110. assert "val1" == d.pop("key")
  111. assert {"key": "val2"} == d
  112. def test_pop2(self, cls):
  113. d = cls()
  114. d.add("key", "val1")
  115. d.add("key2", "val2")
  116. d.add("key", "val3")
  117. assert "val1" == d.pop("key")
  118. assert [("key2", "val2"), ("key", "val3")] == list(d.items())
  119. def test_pop_default(self, cls):
  120. d = cls(other="val")
  121. assert "default" == d.pop("key", "default")
  122. assert "default" == d.pop(key="key", default="default")
  123. assert "other" in d
  124. def test_pop_raises(self, cls):
  125. d = cls(other="val")
  126. with pytest.raises(KeyError, match="key"):
  127. d.pop("key")
  128. assert "other" in d
  129. def test_replacement_order(self, cls):
  130. d = cls()
  131. d.add("key1", "val1")
  132. d.add("key2", "val2")
  133. d.add("key1", "val3")
  134. d.add("key2", "val4")
  135. d["key1"] = "val"
  136. expected = [("key1", "val"), ("key2", "val2"), ("key2", "val4")]
  137. assert expected == list(d.items())
  138. def test_nonstr_key(self, cls):
  139. d = cls()
  140. with pytest.raises(TypeError):
  141. d[1] = "val"
  142. def test_istr_key(self, cls, istr):
  143. d = cls()
  144. d[istr("1")] = "val"
  145. assert type(list(d.keys())[0]) is istr
  146. def test_str_derived_key(self, cls):
  147. class A(str):
  148. pass
  149. d = cls()
  150. d[A("1")] = "val"
  151. assert type(list(d.keys())[0]) is A
  152. def test_istr_key_add(self, cls, istr):
  153. d = cls()
  154. d.add(istr("1"), "val")
  155. assert type(list(d.keys())[0]) is istr
  156. def test_str_derived_key_add(self, cls):
  157. class A(str):
  158. pass
  159. d = cls()
  160. d.add(A("1"), "val")
  161. assert type(list(d.keys())[0]) is A
  162. def test_popall(self, cls):
  163. d = cls()
  164. d.add("key1", "val1")
  165. d.add("key2", "val2")
  166. d.add("key1", "val3")
  167. ret = d.popall("key1")
  168. assert ["val1", "val3"] == ret
  169. assert {"key2": "val2"} == d
  170. def test_popall_default(self, cls):
  171. d = cls()
  172. assert "val" == d.popall("key", "val")
  173. assert "val" == d.popall(key="key", default="val")
  174. def test_popall_key_error(self, cls):
  175. d = cls()
  176. with pytest.raises(KeyError, match="key"):
  177. d.popall("key")
  178. def test_large_multidict_resizing(self, cls):
  179. SIZE = 1024
  180. d = cls()
  181. for i in range(SIZE):
  182. d["key" + str(i)] = i
  183. for i in range(SIZE - 1):
  184. del d["key" + str(i)]
  185. assert {"key" + str(SIZE - 1): SIZE - 1} == d
  186. class TestCIMutableMultiDict:
  187. @pytest.fixture
  188. def cls(self, _multidict):
  189. return _multidict.CIMultiDict
  190. @pytest.fixture
  191. def proxy_cls(self, _multidict):
  192. return _multidict.CIMultiDictProxy
  193. @pytest.fixture
  194. def istr(self, _multidict):
  195. return _multidict.istr
  196. def test_getall(self, cls):
  197. d = cls([("KEY", "value1")], KEY="value2")
  198. assert d != {"KEY": "value1"}
  199. assert len(d) == 2
  200. assert d.getall("key") == ["value1", "value2"]
  201. with pytest.raises(KeyError, match="some_key"):
  202. d.getall("some_key")
  203. def test_ctor(self, cls):
  204. d = cls(k1="v1")
  205. assert "v1" == d["K1"]
  206. assert ("k1", "v1") in d.items()
  207. def test_setitem(self, cls):
  208. d = cls()
  209. d["k1"] = "v1"
  210. assert "v1" == d["K1"]
  211. assert ("k1", "v1") in d.items()
  212. def test_delitem(self, cls):
  213. d = cls()
  214. d["k1"] = "v1"
  215. assert "K1" in d
  216. del d["k1"]
  217. assert "K1" not in d
  218. def test_copy(self, cls):
  219. d1 = cls(key="KEY", a="b")
  220. d2 = d1.copy()
  221. assert d1 == d2
  222. assert d1.items() == d2.items()
  223. assert d1 is not d2
  224. def test__repr__(self, cls):
  225. d = cls()
  226. assert str(d) == "<%s()>" % cls.__name__
  227. d = cls([("KEY", "one"), ("KEY", "two")])
  228. expected = "<%s('KEY': 'one', 'KEY': 'two')>" % cls.__name__
  229. assert str(d) == expected
  230. def test_add(self, cls):
  231. d = cls()
  232. assert d == {}
  233. d["KEY"] = "one"
  234. assert ("KEY", "one") in d.items()
  235. assert d == cls({"Key": "one"})
  236. assert d.getall("key") == ["one"]
  237. d["KEY"] = "two"
  238. assert ("KEY", "two") in d.items()
  239. assert d == cls({"Key": "two"})
  240. assert d.getall("key") == ["two"]
  241. d.add("KEY", "one")
  242. assert ("KEY", "one") in d.items()
  243. assert 2 == len(d)
  244. assert d.getall("key") == ["two", "one"]
  245. d.add("FOO", "bar")
  246. assert ("FOO", "bar") in d.items()
  247. assert 3 == len(d)
  248. assert d.getall("foo") == ["bar"]
  249. d.add(key="test", value="test")
  250. assert ("test", "test") in d.items()
  251. assert 4 == len(d)
  252. assert d.getall("test") == ["test"]
  253. def test_extend(self, cls):
  254. d = cls()
  255. assert d == {}
  256. d.extend([("KEY", "one"), ("key", "two")], key=3, foo="bar")
  257. assert 4 == len(d)
  258. itms = d.items()
  259. # we can't guarantee order of kwargs
  260. assert ("KEY", "one") in itms
  261. assert ("key", "two") in itms
  262. assert ("key", 3) in itms
  263. assert ("foo", "bar") in itms
  264. other = cls(Bar="baz")
  265. assert other == {"Bar": "baz"}
  266. d.extend(other)
  267. assert ("Bar", "baz") in d.items()
  268. assert "bar" in d
  269. d.extend({"Foo": "moo"})
  270. assert ("Foo", "moo") in d.items()
  271. assert "foo" in d
  272. d.extend()
  273. assert 6 == len(d)
  274. with pytest.raises(TypeError):
  275. d.extend("foo", "bar")
  276. def test_extend_from_proxy(self, cls, proxy_cls):
  277. d = cls([("a", "a"), ("b", "b")])
  278. proxy = proxy_cls(d)
  279. d2 = cls()
  280. d2.extend(proxy)
  281. assert [("a", "a"), ("b", "b")] == list(d2.items())
  282. def test_clear(self, cls):
  283. d = cls([("KEY", "one")], key="two", foo="bar")
  284. d.clear()
  285. assert d == {}
  286. assert list(d.items()) == []
  287. def test_del(self, cls):
  288. d = cls([("KEY", "one"), ("key", "two")], foo="bar")
  289. del d["key"]
  290. assert d == {"foo": "bar"}
  291. assert list(d.items()) == [("foo", "bar")]
  292. with pytest.raises(KeyError, match="key"):
  293. del d["key"]
  294. def test_set_default(self, cls):
  295. d = cls([("KEY", "one"), ("key", "two")], foo="bar")
  296. assert "one" == d.setdefault("key", "three")
  297. assert "three" == d.setdefault("otherkey", "three")
  298. assert "otherkey" in d
  299. assert ("otherkey", "three") in d.items()
  300. assert "three" == d["OTHERKEY"]
  301. def test_popitem(self, cls):
  302. d = cls()
  303. d.add("KEY", "val1")
  304. d.add("key", "val2")
  305. pair = d.popitem()
  306. assert ("KEY", "val1") == pair
  307. assert isinstance(pair[0], str)
  308. assert [("key", "val2")] == list(d.items())
  309. def test_popitem_empty_multidict(self, cls):
  310. d = cls()
  311. with pytest.raises(KeyError):
  312. d.popitem()
  313. def test_pop(self, cls):
  314. d = cls()
  315. d.add("KEY", "val1")
  316. d.add("key", "val2")
  317. assert "val1" == d.pop("KEY")
  318. assert {"key": "val2"} == d
  319. def test_pop_lowercase(self, cls):
  320. d = cls()
  321. d.add("KEY", "val1")
  322. d.add("key", "val2")
  323. assert "val1" == d.pop("key")
  324. assert {"key": "val2"} == d
  325. def test_pop_default(self, cls):
  326. d = cls(OTHER="val")
  327. assert "default" == d.pop("key", "default")
  328. assert "other" in d
  329. def test_pop_raises(self, cls):
  330. d = cls(OTHER="val")
  331. with pytest.raises(KeyError, match="KEY"):
  332. d.pop("KEY")
  333. assert "other" in d
  334. def test_extend_with_istr(self, cls, istr):
  335. us = istr("aBc")
  336. d = cls()
  337. d.extend([(us, "val")])
  338. assert [("aBc", "val")] == list(d.items())
  339. def test_copy_istr(self, cls, istr):
  340. d = cls({istr("Foo"): "bar"})
  341. d2 = d.copy()
  342. assert d == d2
  343. def test_eq(self, cls):
  344. d1 = cls(Key="val")
  345. d2 = cls(KEY="val")
  346. assert d1 == d2
  347. @pytest.mark.skipif(
  348. sys.implementation.name == "pypy",
  349. reason="getsizeof() is not implemented on PyPy",
  350. )
  351. def test_sizeof(self, cls):
  352. md = cls()
  353. s1 = sys.getsizeof(md)
  354. for i in string.ascii_lowercase:
  355. for j in string.ascii_uppercase:
  356. md[i + j] = i + j
  357. # multidict should be resized
  358. s2 = sys.getsizeof(md)
  359. assert s2 > s1
  360. @pytest.mark.skipif(
  361. sys.implementation.name == "pypy",
  362. reason="getsizeof() is not implemented on PyPy",
  363. )
  364. def test_min_sizeof(self, cls):
  365. md = cls()
  366. assert sys.getsizeof(md) < 1024
  367. def test_issue_620_items(self, cls):
  368. # https://github.com/aio-libs/multidict/issues/620
  369. d = cls({"a": "123, 456", "b": "789"})
  370. before_mutation_items = d.items()
  371. d["c"] = "000"
  372. # This causes an error on pypy.
  373. list(before_mutation_items)
  374. def test_issue_620_keys(self, cls):
  375. # https://github.com/aio-libs/multidict/issues/620
  376. d = cls({"a": "123, 456", "b": "789"})
  377. before_mutation_keys = d.keys()
  378. d["c"] = "000"
  379. # This causes an error on pypy.
  380. list(before_mutation_keys)
  381. def test_issue_620_values(self, cls):
  382. # https://github.com/aio-libs/multidict/issues/620
  383. d = cls({"a": "123, 456", "b": "789"})
  384. before_mutation_values = d.values()
  385. d["c"] = "000"
  386. # This causes an error on pypy.
  387. list(before_mutation_values)