_multidict_py.py 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242
  1. import enum
  2. import functools
  3. import reprlib
  4. import sys
  5. from array import array
  6. from collections.abc import (
  7. ItemsView,
  8. Iterable,
  9. Iterator,
  10. KeysView,
  11. Mapping,
  12. ValuesView,
  13. )
  14. from dataclasses import dataclass
  15. from typing import (
  16. TYPE_CHECKING,
  17. Any,
  18. ClassVar,
  19. Generic,
  20. NoReturn,
  21. Optional,
  22. TypeVar,
  23. Union,
  24. cast,
  25. overload,
  26. )
  27. from ._abc import MDArg, MultiMapping, MutableMultiMapping, SupportsKeys
  28. if sys.version_info >= (3, 11):
  29. from typing import Self
  30. else:
  31. from typing_extensions import Self
  32. class istr(str):
  33. """Case insensitive str."""
  34. __is_istr__ = True
  35. __istr_identity__: Optional[str] = None
  36. _V = TypeVar("_V")
  37. _T = TypeVar("_T")
  38. _SENTINEL = enum.Enum("_SENTINEL", "sentinel")
  39. sentinel = _SENTINEL.sentinel
  40. _version = array("Q", [0])
  41. class _Iter(Generic[_T]):
  42. __slots__ = ("_size", "_iter")
  43. def __init__(self, size: int, iterator: Iterator[_T]):
  44. self._size = size
  45. self._iter = iterator
  46. def __iter__(self) -> Self:
  47. return self
  48. def __next__(self) -> _T:
  49. return next(self._iter)
  50. def __length_hint__(self) -> int:
  51. return self._size
  52. class _ViewBase(Generic[_V]):
  53. def __init__(
  54. self,
  55. md: "MultiDict[_V]",
  56. ):
  57. self._md = md
  58. def __len__(self) -> int:
  59. return len(self._md)
  60. class _ItemsView(_ViewBase[_V], ItemsView[str, _V]):
  61. def __contains__(self, item: object) -> bool:
  62. if not isinstance(item, (tuple, list)) or len(item) != 2:
  63. return False
  64. key, value = item
  65. try:
  66. identity = self._md._identity(key)
  67. except TypeError:
  68. return False
  69. hash_ = hash(identity)
  70. for slot, idx, e in self._md._keys.iter_hash(hash_):
  71. if e.identity == identity and value == e.value:
  72. return True
  73. return False
  74. def __iter__(self) -> _Iter[tuple[str, _V]]:
  75. return _Iter(len(self), self._iter(self._md._version))
  76. def _iter(self, version: int) -> Iterator[tuple[str, _V]]:
  77. for e in self._md._keys.iter_entries():
  78. if version != self._md._version:
  79. raise RuntimeError("Dictionary changed during iteration")
  80. yield self._md._key(e.key), e.value
  81. @reprlib.recursive_repr()
  82. def __repr__(self) -> str:
  83. lst = []
  84. for e in self._md._keys.iter_entries():
  85. lst.append(f"'{e.key}': {e.value!r}")
  86. body = ", ".join(lst)
  87. return f"<{self.__class__.__name__}({body})>"
  88. def _parse_item(
  89. self, arg: Union[tuple[str, _V], _T]
  90. ) -> Optional[tuple[int, str, str, _V]]:
  91. if not isinstance(arg, tuple):
  92. return None
  93. if len(arg) != 2:
  94. return None
  95. try:
  96. identity = self._md._identity(arg[0])
  97. return (hash(identity), identity, arg[0], arg[1])
  98. except TypeError:
  99. return None
  100. def _tmp_set(self, it: Iterable[_T]) -> set[tuple[str, _V]]:
  101. tmp = set()
  102. for arg in it:
  103. item = self._parse_item(arg)
  104. if item is None:
  105. continue
  106. else:
  107. tmp.add((item[1], item[3]))
  108. return tmp
  109. def __and__(self, other: Iterable[Any]) -> set[tuple[str, _V]]:
  110. ret = set()
  111. try:
  112. it = iter(other)
  113. except TypeError:
  114. return NotImplemented
  115. for arg in it:
  116. item = self._parse_item(arg)
  117. if item is None:
  118. continue
  119. hash_, identity, key, value = item
  120. for slot, idx, e in self._md._keys.iter_hash(hash_):
  121. e.hash = -1
  122. if e.identity == identity and e.value == value:
  123. ret.add((e.key, e.value))
  124. self._md._keys.restore_hash(hash_)
  125. return ret
  126. def __rand__(self, other: Iterable[_T]) -> set[_T]:
  127. ret = set()
  128. try:
  129. it = iter(other)
  130. except TypeError:
  131. return NotImplemented
  132. for arg in it:
  133. item = self._parse_item(arg)
  134. if item is None:
  135. continue
  136. hash_, identity, key, value = item
  137. for slot, idx, e in self._md._keys.iter_hash(hash_):
  138. if e.identity == identity and e.value == value:
  139. ret.add(arg)
  140. break
  141. return ret
  142. def __or__(self, other: Iterable[_T]) -> set[Union[tuple[str, _V], _T]]:
  143. ret: set[Union[tuple[str, _V], _T]] = set(self)
  144. try:
  145. it = iter(other)
  146. except TypeError:
  147. return NotImplemented
  148. for arg in it:
  149. item: Optional[tuple[int, str, str, _V]] = self._parse_item(arg)
  150. if item is None:
  151. ret.add(arg)
  152. continue
  153. hash_, identity, key, value = item
  154. for slot, idx, e in self._md._keys.iter_hash(hash_):
  155. if e.identity == identity and e.value == value: # pragma: no branch
  156. break
  157. else:
  158. ret.add(arg)
  159. return ret
  160. def __ror__(self, other: Iterable[_T]) -> set[Union[tuple[str, _V], _T]]:
  161. try:
  162. ret: set[Union[tuple[str, _V], _T]] = set(other)
  163. except TypeError:
  164. return NotImplemented
  165. tmp = self._tmp_set(ret)
  166. for e in self._md._keys.iter_entries():
  167. if (e.identity, e.value) not in tmp:
  168. ret.add((e.key, e.value))
  169. return ret
  170. def __sub__(self, other: Iterable[_T]) -> set[Union[tuple[str, _V], _T]]:
  171. ret: set[Union[tuple[str, _V], _T]] = set()
  172. try:
  173. it = iter(other)
  174. except TypeError:
  175. return NotImplemented
  176. tmp = self._tmp_set(it)
  177. for e in self._md._keys.iter_entries():
  178. if (e.identity, e.value) not in tmp:
  179. ret.add((e.key, e.value))
  180. return ret
  181. def __rsub__(self, other: Iterable[_T]) -> set[_T]:
  182. ret: set[_T] = set()
  183. try:
  184. it = iter(other)
  185. except TypeError:
  186. return NotImplemented
  187. for arg in it:
  188. item = self._parse_item(arg)
  189. if item is None:
  190. ret.add(arg)
  191. continue
  192. hash_, identity, key, value = item
  193. for slot, idx, e in self._md._keys.iter_hash(hash_):
  194. if e.identity == identity and e.value == value: # pragma: no branch
  195. break
  196. else:
  197. ret.add(arg)
  198. return ret
  199. def __xor__(self, other: Iterable[_T]) -> set[Union[tuple[str, _V], _T]]:
  200. try:
  201. rgt = set(other)
  202. except TypeError:
  203. return NotImplemented
  204. ret: set[Union[tuple[str, _V], _T]] = self - rgt
  205. ret |= rgt - self
  206. return ret
  207. __rxor__ = __xor__
  208. def isdisjoint(self, other: Iterable[tuple[str, _V]]) -> bool:
  209. for arg in other:
  210. item = self._parse_item(arg)
  211. if item is None:
  212. continue
  213. hash_, identity, key, value = item
  214. for slot, idx, e in self._md._keys.iter_hash(hash_):
  215. if e.identity == identity and e.value == value: # pragma: no branch
  216. return False
  217. return True
  218. class _ValuesView(_ViewBase[_V], ValuesView[_V]):
  219. def __contains__(self, value: object) -> bool:
  220. for e in self._md._keys.iter_entries():
  221. if e.value == value:
  222. return True
  223. return False
  224. def __iter__(self) -> _Iter[_V]:
  225. return _Iter(len(self), self._iter(self._md._version))
  226. def _iter(self, version: int) -> Iterator[_V]:
  227. for e in self._md._keys.iter_entries():
  228. if version != self._md._version:
  229. raise RuntimeError("Dictionary changed during iteration")
  230. yield e.value
  231. @reprlib.recursive_repr()
  232. def __repr__(self) -> str:
  233. lst = []
  234. for e in self._md._keys.iter_entries():
  235. lst.append(repr(e.value))
  236. body = ", ".join(lst)
  237. return f"<{self.__class__.__name__}({body})>"
  238. class _KeysView(_ViewBase[_V], KeysView[str]):
  239. def __contains__(self, key: object) -> bool:
  240. if not isinstance(key, str):
  241. return False
  242. identity = self._md._identity(key)
  243. hash_ = hash(identity)
  244. for slot, idx, e in self._md._keys.iter_hash(hash_):
  245. if e.identity == identity: # pragma: no branch
  246. return True
  247. return False
  248. def __iter__(self) -> _Iter[str]:
  249. return _Iter(len(self), self._iter(self._md._version))
  250. def _iter(self, version: int) -> Iterator[str]:
  251. for e in self._md._keys.iter_entries():
  252. if version != self._md._version:
  253. raise RuntimeError("Dictionary changed during iteration")
  254. yield self._md._key(e.key)
  255. def __repr__(self) -> str:
  256. lst = []
  257. for e in self._md._keys.iter_entries():
  258. lst.append(f"'{e.key}'")
  259. body = ", ".join(lst)
  260. return f"<{self.__class__.__name__}({body})>"
  261. def __and__(self, other: Iterable[object]) -> set[str]:
  262. ret = set()
  263. try:
  264. it = iter(other)
  265. except TypeError:
  266. return NotImplemented
  267. for key in it:
  268. if not isinstance(key, str):
  269. continue
  270. identity = self._md._identity(key)
  271. hash_ = hash(identity)
  272. for slot, idx, e in self._md._keys.iter_hash(hash_):
  273. if e.identity == identity: # pragma: no branch
  274. ret.add(e.key)
  275. break
  276. return ret
  277. def __rand__(self, other: Iterable[_T]) -> set[_T]:
  278. ret = set()
  279. try:
  280. it = iter(other)
  281. except TypeError:
  282. return NotImplemented
  283. for key in it:
  284. if not isinstance(key, str):
  285. continue
  286. if key in self._md:
  287. ret.add(key)
  288. return cast(set[_T], ret)
  289. def __or__(self, other: Iterable[_T]) -> set[Union[str, _T]]:
  290. ret: set[Union[str, _T]] = set(self)
  291. try:
  292. it = iter(other)
  293. except TypeError:
  294. return NotImplemented
  295. for key in it:
  296. if not isinstance(key, str):
  297. ret.add(key)
  298. continue
  299. if key not in self._md:
  300. ret.add(key)
  301. return ret
  302. def __ror__(self, other: Iterable[_T]) -> set[Union[str, _T]]:
  303. try:
  304. ret: set[Union[str, _T]] = set(other)
  305. except TypeError:
  306. return NotImplemented
  307. tmp = set()
  308. for key in ret:
  309. if not isinstance(key, str):
  310. continue
  311. identity = self._md._identity(key)
  312. tmp.add(identity)
  313. for e in self._md._keys.iter_entries():
  314. if e.identity not in tmp:
  315. ret.add(e.key)
  316. return ret
  317. def __sub__(self, other: Iterable[object]) -> set[str]:
  318. ret = set(self)
  319. try:
  320. it = iter(other)
  321. except TypeError:
  322. return NotImplemented
  323. for key in it:
  324. if not isinstance(key, str):
  325. continue
  326. identity = self._md._identity(key)
  327. hash_ = hash(identity)
  328. for slot, idx, e in self._md._keys.iter_hash(hash_):
  329. if e.identity == identity: # pragma: no branch
  330. ret.discard(e.key)
  331. break
  332. return ret
  333. def __rsub__(self, other: Iterable[_T]) -> set[_T]:
  334. try:
  335. ret: set[_T] = set(other)
  336. except TypeError:
  337. return NotImplemented
  338. for key in other:
  339. if not isinstance(key, str):
  340. continue
  341. if key in self._md:
  342. ret.discard(key) # type: ignore[arg-type]
  343. return ret
  344. def __xor__(self, other: Iterable[_T]) -> set[Union[str, _T]]:
  345. try:
  346. rgt = set(other)
  347. except TypeError:
  348. return NotImplemented
  349. ret: set[Union[str, _T]] = self - rgt # type: ignore[assignment]
  350. ret |= rgt - self
  351. return ret
  352. __rxor__ = __xor__
  353. def isdisjoint(self, other: Iterable[object]) -> bool:
  354. for key in other:
  355. if not isinstance(key, str):
  356. continue
  357. if key in self._md:
  358. return False
  359. return True
  360. class _CSMixin:
  361. _ci: ClassVar[bool] = False
  362. def _key(self, key: str) -> str:
  363. return key
  364. def _identity(self, key: str) -> str:
  365. if isinstance(key, str):
  366. return key
  367. else:
  368. raise TypeError("MultiDict keys should be either str or subclasses of str")
  369. class _CIMixin:
  370. _ci: ClassVar[bool] = True
  371. def _key(self, key: str) -> str:
  372. if type(key) is istr:
  373. return key
  374. else:
  375. return istr(key)
  376. def _identity(self, key: str) -> str:
  377. if isinstance(key, istr):
  378. ret = key.__istr_identity__
  379. if ret is None:
  380. ret = key.lower()
  381. key.__istr_identity__ = ret
  382. return ret
  383. if isinstance(key, str):
  384. return key.lower()
  385. else:
  386. raise TypeError("MultiDict keys should be either str or subclasses of str")
  387. def estimate_log2_keysize(n: int) -> int:
  388. # 7 == HT_MINSIZE - 1
  389. return (((n * 3 + 1) // 2) | 7).bit_length()
  390. @dataclass
  391. class _Entry(Generic[_V]):
  392. hash: int
  393. identity: str
  394. key: str
  395. value: _V
  396. @dataclass
  397. class _HtKeys(Generic[_V]): # type: ignore[misc]
  398. LOG_MINSIZE: ClassVar[int] = 3
  399. MINSIZE: ClassVar[int] = 8
  400. PREALLOCATED_INDICES: ClassVar[dict[int, array]] = { # type: ignore[type-arg]
  401. log2_size: array(
  402. "b" if log2_size < 8 else "h", (-1 for i in range(1 << log2_size))
  403. )
  404. for log2_size in range(3, 10)
  405. }
  406. log2_size: int
  407. usable: int
  408. indices: array # type: ignore[type-arg] # in py3.9 array is not generic
  409. entries: list[Optional[_Entry[_V]]]
  410. @functools.cached_property
  411. def nslots(self) -> int:
  412. return 1 << self.log2_size
  413. @functools.cached_property
  414. def mask(self) -> int:
  415. return self.nslots - 1
  416. if sys.implementation.name != "pypy":
  417. def __sizeof__(self) -> int:
  418. return (
  419. object.__sizeof__(self)
  420. + sys.getsizeof(self.indices)
  421. + sys.getsizeof(self.entries)
  422. )
  423. @classmethod
  424. def new(cls, log2_size: int, entries: list[Optional[_Entry[_V]]]) -> Self:
  425. size = 1 << log2_size
  426. usable = (size << 1) // 3
  427. if log2_size < 10:
  428. indices = cls.PREALLOCATED_INDICES[log2_size].__copy__()
  429. elif log2_size < 16:
  430. indices = array("h", (-1 for i in range(size)))
  431. elif log2_size < 32:
  432. indices = array("l", (-1 for i in range(size)))
  433. else: # pragma: no cover # don't test huge multidicts
  434. indices = array("q", (-1 for i in range(size)))
  435. ret = cls(
  436. log2_size=log2_size,
  437. usable=usable,
  438. indices=indices,
  439. entries=entries,
  440. )
  441. return ret
  442. def clone(self) -> "_HtKeys[_V]":
  443. entries = [
  444. _Entry(e.hash, e.identity, e.key, e.value) if e is not None else None
  445. for e in self.entries
  446. ]
  447. return _HtKeys(
  448. log2_size=self.log2_size,
  449. usable=self.usable,
  450. indices=self.indices.__copy__(),
  451. entries=entries,
  452. )
  453. def build_indices(self, update: bool) -> None:
  454. mask = self.mask
  455. indices = self.indices
  456. for idx, e in enumerate(self.entries):
  457. assert e is not None
  458. hash_ = e.hash
  459. if update:
  460. if hash_ == -1:
  461. hash_ = hash(e.identity)
  462. else:
  463. assert hash_ != -1
  464. i = hash_ & mask
  465. perturb = hash_ & sys.maxsize
  466. while indices[i] != -1:
  467. perturb >>= 5
  468. i = mask & (i * 5 + perturb + 1)
  469. indices[i] = idx
  470. def find_empty_slot(self, hash_: int) -> int:
  471. mask = self.mask
  472. indices = self.indices
  473. i = hash_ & mask
  474. perturb = hash_ & sys.maxsize
  475. ix = indices[i]
  476. while ix != -1:
  477. perturb >>= 5
  478. i = (i * 5 + perturb + 1) & mask
  479. ix = indices[i]
  480. return i
  481. def iter_hash(self, hash_: int) -> Iterator[tuple[int, int, _Entry[_V]]]:
  482. mask = self.mask
  483. indices = self.indices
  484. entries = self.entries
  485. i = hash_ & mask
  486. perturb = hash_ & sys.maxsize
  487. ix = indices[i]
  488. while ix != -1:
  489. if ix != -2:
  490. e = entries[ix]
  491. if e.hash == hash_:
  492. yield i, ix, e
  493. perturb >>= 5
  494. i = (i * 5 + perturb + 1) & mask
  495. ix = indices[i]
  496. def del_idx(self, hash_: int, idx: int) -> None:
  497. mask = self.mask
  498. indices = self.indices
  499. i = hash_ & mask
  500. perturb = hash_ & sys.maxsize
  501. ix = indices[i]
  502. while ix != idx:
  503. perturb >>= 5
  504. i = (i * 5 + perturb + 1) & mask
  505. ix = indices[i]
  506. indices[i] = -2
  507. def iter_entries(self) -> Iterator[_Entry[_V]]:
  508. return filter(None, self.entries)
  509. def restore_hash(self, hash_: int) -> None:
  510. mask = self.mask
  511. indices = self.indices
  512. entries = self.entries
  513. i = hash_ & mask
  514. perturb = hash_ & sys.maxsize
  515. ix = indices[i]
  516. while ix != -1:
  517. if ix != -2:
  518. entry = entries[ix]
  519. if entry.hash == -1:
  520. entry.hash = hash_
  521. perturb >>= 5
  522. i = (i * 5 + perturb + 1) & mask
  523. ix = indices[i]
  524. class MultiDict(_CSMixin, MutableMultiMapping[_V]):
  525. """Dictionary with the support for duplicate keys."""
  526. __slots__ = ("_keys", "_used", "_version")
  527. def __init__(self, arg: MDArg[_V] = None, /, **kwargs: _V):
  528. self._used = 0
  529. v = _version
  530. v[0] += 1
  531. self._version = v[0]
  532. if not kwargs:
  533. md = None
  534. if isinstance(arg, MultiDictProxy):
  535. md = arg._md
  536. elif isinstance(arg, MultiDict):
  537. md = arg
  538. if md is not None and md._ci is self._ci:
  539. self._from_md(md)
  540. return
  541. it = self._parse_args(arg, kwargs)
  542. log2_size = estimate_log2_keysize(cast(int, next(it)))
  543. if log2_size > 17: # pragma: no cover
  544. # Don't overallocate really huge keys space in init
  545. log2_size = 17
  546. self._keys: _HtKeys[_V] = _HtKeys.new(log2_size, [])
  547. self._extend_items(cast(Iterator[_Entry[_V]], it))
  548. def _from_md(self, md: "MultiDict[_V]") -> None:
  549. # Copy everything as-is without compacting the new multidict,
  550. # otherwise it requires reindexing
  551. self._keys = md._keys.clone()
  552. self._used = md._used
  553. @overload
  554. def getall(self, key: str) -> list[_V]: ...
  555. @overload
  556. def getall(self, key: str, default: _T) -> Union[list[_V], _T]: ...
  557. def getall(
  558. self, key: str, default: Union[_T, _SENTINEL] = sentinel
  559. ) -> Union[list[_V], _T]:
  560. """Return a list of all values matching the key."""
  561. identity = self._identity(key)
  562. hash_ = hash(identity)
  563. res = []
  564. restore = []
  565. for slot, idx, e in self._keys.iter_hash(hash_):
  566. if e.identity == identity: # pragma: no branch
  567. res.append(e.value)
  568. e.hash = -1
  569. restore.append(idx)
  570. if res:
  571. entries = self._keys.entries
  572. for idx in restore:
  573. entries[idx].hash = hash_ # type: ignore[union-attr]
  574. return res
  575. if not res and default is not sentinel:
  576. return default
  577. raise KeyError("Key not found: %r" % key)
  578. @overload
  579. def getone(self, key: str) -> _V: ...
  580. @overload
  581. def getone(self, key: str, default: _T) -> Union[_V, _T]: ...
  582. def getone(
  583. self, key: str, default: Union[_T, _SENTINEL] = sentinel
  584. ) -> Union[_V, _T]:
  585. """Get first value matching the key.
  586. Raises KeyError if the key is not found and no default is provided.
  587. """
  588. identity = self._identity(key)
  589. hash_ = hash(identity)
  590. for slot, idx, e in self._keys.iter_hash(hash_):
  591. if e.identity == identity: # pragma: no branch
  592. return e.value
  593. if default is not sentinel:
  594. return default
  595. raise KeyError("Key not found: %r" % key)
  596. # Mapping interface #
  597. def __getitem__(self, key: str) -> _V:
  598. return self.getone(key)
  599. @overload
  600. def get(self, key: str, /) -> Union[_V, None]: ...
  601. @overload
  602. def get(self, key: str, /, default: _T) -> Union[_V, _T]: ...
  603. def get(self, key: str, default: Union[_T, None] = None) -> Union[_V, _T, None]:
  604. """Get first value matching the key.
  605. If the key is not found, returns the default (or None if no default is provided)
  606. """
  607. return self.getone(key, default)
  608. def __iter__(self) -> Iterator[str]:
  609. return iter(self.keys())
  610. def __len__(self) -> int:
  611. return self._used
  612. def keys(self) -> KeysView[str]:
  613. """Return a new view of the dictionary's keys."""
  614. return _KeysView(self)
  615. def items(self) -> ItemsView[str, _V]:
  616. """Return a new view of the dictionary's items *(key, value) pairs)."""
  617. return _ItemsView(self)
  618. def values(self) -> _ValuesView[_V]:
  619. """Return a new view of the dictionary's values."""
  620. return _ValuesView(self)
  621. def __eq__(self, other: object) -> bool:
  622. if not isinstance(other, Mapping):
  623. return NotImplemented
  624. if isinstance(other, MultiDictProxy):
  625. return self == other._md
  626. if isinstance(other, MultiDict):
  627. lft = self._keys
  628. rht = other._keys
  629. if self._used != other._used:
  630. return False
  631. for e1, e2 in zip(lft.iter_entries(), rht.iter_entries()):
  632. if e1.identity != e2.identity or e1.value != e2.value:
  633. return False
  634. return True
  635. if self._used != len(other):
  636. return False
  637. for k, v in self.items():
  638. nv = other.get(k, sentinel)
  639. if v != nv:
  640. return False
  641. return True
  642. def __contains__(self, key: object) -> bool:
  643. if not isinstance(key, str):
  644. return False
  645. identity = self._identity(key)
  646. hash_ = hash(identity)
  647. for slot, idx, e in self._keys.iter_hash(hash_):
  648. if e.identity == identity: # pragma: no branch
  649. return True
  650. return False
  651. @reprlib.recursive_repr()
  652. def __repr__(self) -> str:
  653. body = ", ".join(f"'{e.key}': {e.value!r}" for e in self._keys.iter_entries())
  654. return f"<{self.__class__.__name__}({body})>"
  655. if sys.implementation.name != "pypy":
  656. def __sizeof__(self) -> int:
  657. return object.__sizeof__(self) + sys.getsizeof(self._keys)
  658. def __reduce__(self) -> tuple[type[Self], tuple[list[tuple[str, _V]]]]:
  659. return (self.__class__, (list(self.items()),))
  660. def add(self, key: str, value: _V) -> None:
  661. identity = self._identity(key)
  662. hash_ = hash(identity)
  663. self._add_with_hash(_Entry(hash_, identity, key, value))
  664. self._incr_version()
  665. def copy(self) -> Self:
  666. """Return a copy of itself."""
  667. cls = self.__class__
  668. return cls(self)
  669. __copy__ = copy
  670. def extend(self, arg: MDArg[_V] = None, /, **kwargs: _V) -> None:
  671. """Extend current MultiDict with more values.
  672. This method must be used instead of update.
  673. """
  674. it = self._parse_args(arg, kwargs)
  675. newsize = self._used + cast(int, next(it))
  676. self._resize(estimate_log2_keysize(newsize), False)
  677. self._extend_items(cast(Iterator[_Entry[_V]], it))
  678. def _parse_args(
  679. self,
  680. arg: MDArg[_V],
  681. kwargs: Mapping[str, _V],
  682. ) -> Iterator[Union[int, _Entry[_V]]]:
  683. identity_func = self._identity
  684. if arg:
  685. if isinstance(arg, MultiDictProxy):
  686. arg = arg._md
  687. if isinstance(arg, MultiDict):
  688. yield len(arg) + len(kwargs)
  689. if self._ci is not arg._ci:
  690. for e in arg._keys.iter_entries():
  691. identity = identity_func(e.key)
  692. yield _Entry(hash(identity), identity, e.key, e.value)
  693. else:
  694. for e in arg._keys.iter_entries():
  695. yield _Entry(e.hash, e.identity, e.key, e.value)
  696. if kwargs:
  697. for key, value in kwargs.items():
  698. identity = identity_func(key)
  699. yield _Entry(hash(identity), identity, key, value)
  700. else:
  701. if hasattr(arg, "keys"):
  702. arg = cast(SupportsKeys[_V], arg)
  703. arg = [(k, arg[k]) for k in arg.keys()]
  704. if kwargs:
  705. arg = list(arg)
  706. arg.extend(list(kwargs.items()))
  707. try:
  708. yield len(arg) + len(kwargs) # type: ignore[arg-type]
  709. except TypeError:
  710. yield 0
  711. for pos, item in enumerate(arg):
  712. if not len(item) == 2:
  713. raise ValueError(
  714. f"multidict update sequence element #{pos}"
  715. f"has length {len(item)}; 2 is required"
  716. )
  717. identity = identity_func(item[0])
  718. yield _Entry(hash(identity), identity, item[0], item[1])
  719. else:
  720. yield len(kwargs)
  721. for key, value in kwargs.items():
  722. identity = identity_func(key)
  723. yield _Entry(hash(identity), identity, key, value)
  724. def _extend_items(self, items: Iterable[_Entry[_V]]) -> None:
  725. for e in items:
  726. self._add_with_hash(e)
  727. self._incr_version()
  728. def clear(self) -> None:
  729. """Remove all items from MultiDict."""
  730. self._used = 0
  731. self._keys = _HtKeys.new(_HtKeys.LOG_MINSIZE, [])
  732. self._incr_version()
  733. # Mapping interface #
  734. def __setitem__(self, key: str, value: _V) -> None:
  735. identity = self._identity(key)
  736. hash_ = hash(identity)
  737. found = False
  738. for slot, idx, e in self._keys.iter_hash(hash_):
  739. if e.identity == identity: # pragma: no branch
  740. if not found:
  741. e.key = key
  742. e.value = value
  743. e.hash = -1
  744. found = True
  745. self._incr_version()
  746. elif e.hash != -1: # pragma: no branch
  747. self._del_at(slot, idx)
  748. if not found:
  749. self._add_with_hash(_Entry(hash_, identity, key, value))
  750. else:
  751. self._keys.restore_hash(hash_)
  752. def __delitem__(self, key: str) -> None:
  753. found = False
  754. identity = self._identity(key)
  755. hash_ = hash(identity)
  756. for slot, idx, e in self._keys.iter_hash(hash_):
  757. if e.identity == identity: # pragma: no branch
  758. self._del_at(slot, idx)
  759. found = True
  760. if not found:
  761. raise KeyError(key)
  762. else:
  763. self._incr_version()
  764. @overload
  765. def setdefault(
  766. self: "MultiDict[Union[_T, None]]", key: str, default: None = None
  767. ) -> Union[_T, None]: ...
  768. @overload
  769. def setdefault(self, key: str, default: _V) -> _V: ...
  770. def setdefault(self, key: str, default: Union[_V, None] = None) -> Union[_V, None]: # type: ignore[misc]
  771. """Return value for key, set value to default if key is not present."""
  772. identity = self._identity(key)
  773. hash_ = hash(identity)
  774. for slot, idx, e in self._keys.iter_hash(hash_):
  775. if e.identity == identity: # pragma: no branch
  776. return e.value
  777. self.add(key, default) # type: ignore[arg-type]
  778. return default
  779. @overload
  780. def popone(self, key: str) -> _V: ...
  781. @overload
  782. def popone(self, key: str, default: _T) -> Union[_V, _T]: ...
  783. def popone(
  784. self, key: str, default: Union[_T, _SENTINEL] = sentinel
  785. ) -> Union[_V, _T]:
  786. """Remove specified key and return the corresponding value.
  787. If key is not found, d is returned if given, otherwise
  788. KeyError is raised.
  789. """
  790. identity = self._identity(key)
  791. hash_ = hash(identity)
  792. for slot, idx, e in self._keys.iter_hash(hash_):
  793. if e.identity == identity: # pragma: no branch
  794. value = e.value
  795. self._del_at(slot, idx)
  796. self._incr_version()
  797. return value
  798. if default is sentinel:
  799. raise KeyError(key)
  800. else:
  801. return default
  802. # Type checking will inherit signature for pop() if we don't confuse it here.
  803. if not TYPE_CHECKING:
  804. pop = popone
  805. @overload
  806. def popall(self, key: str) -> list[_V]: ...
  807. @overload
  808. def popall(self, key: str, default: _T) -> Union[list[_V], _T]: ...
  809. def popall(
  810. self, key: str, default: Union[_T, _SENTINEL] = sentinel
  811. ) -> Union[list[_V], _T]:
  812. """Remove all occurrences of key and return the list of corresponding
  813. values.
  814. If key is not found, default is returned if given, otherwise
  815. KeyError is raised.
  816. """
  817. found = False
  818. identity = self._identity(key)
  819. hash_ = hash(identity)
  820. ret = []
  821. for slot, idx, e in self._keys.iter_hash(hash_):
  822. if e.identity == identity: # pragma: no branch
  823. found = True
  824. ret.append(e.value)
  825. self._del_at(slot, idx)
  826. self._incr_version()
  827. if not found:
  828. if default is sentinel:
  829. raise KeyError(key)
  830. else:
  831. return default
  832. else:
  833. return ret
  834. def popitem(self) -> tuple[str, _V]:
  835. """Remove and return an arbitrary (key, value) pair."""
  836. if self._used <= 0:
  837. raise KeyError("empty multidict")
  838. pos = len(self._keys.entries) - 1
  839. entry = self._keys.entries.pop()
  840. while entry is None:
  841. pos -= 1
  842. entry = self._keys.entries.pop()
  843. ret = self._key(entry.key), entry.value
  844. self._keys.del_idx(entry.hash, pos)
  845. self._used -= 1
  846. self._incr_version()
  847. return ret
  848. def update(self, arg: MDArg[_V] = None, /, **kwargs: _V) -> None:
  849. """Update the dictionary, overwriting existing keys."""
  850. it = self._parse_args(arg, kwargs)
  851. newsize = self._used + cast(int, next(it))
  852. log2_size = estimate_log2_keysize(newsize)
  853. if log2_size > 17: # pragma: no cover
  854. # Don't overallocate really huge keys space in update,
  855. # duplicate keys could reduce the resulting anount of entries
  856. log2_size = 17
  857. if log2_size > self._keys.log2_size:
  858. self._resize(log2_size, False)
  859. try:
  860. self._update_items(cast(Iterator[_Entry[_V]], it))
  861. finally:
  862. self._post_update()
  863. def _update_items(self, items: Iterator[_Entry[_V]]) -> None:
  864. for entry in items:
  865. found = False
  866. hash_ = entry.hash
  867. identity = entry.identity
  868. for slot, idx, e in self._keys.iter_hash(hash_):
  869. if e.identity == identity: # pragma: no branch
  870. if not found:
  871. found = True
  872. e.key = entry.key
  873. e.value = entry.value
  874. e.hash = -1
  875. else:
  876. self._del_at_for_upd(e)
  877. if not found:
  878. self._add_with_hash_for_upd(entry)
  879. def _post_update(self) -> None:
  880. keys = self._keys
  881. indices = keys.indices
  882. entries = keys.entries
  883. for slot in range(keys.nslots):
  884. idx = indices[slot]
  885. if idx >= 0:
  886. e2 = entries[idx]
  887. assert e2 is not None
  888. if e2.key is None:
  889. entries[idx] = None
  890. indices[slot] = -2
  891. self._used -= 1
  892. if e2.hash == -1:
  893. e2.hash = hash(e2.identity)
  894. self._incr_version()
  895. def merge(self, arg: MDArg[_V] = None, /, **kwargs: _V) -> None:
  896. """Merge into the dictionary, adding non-existing keys."""
  897. it = self._parse_args(arg, kwargs)
  898. newsize = self._used + cast(int, next(it))
  899. log2_size = estimate_log2_keysize(newsize)
  900. if log2_size > 17: # pragma: no cover
  901. # Don't overallocate really huge keys space in update,
  902. # duplicate keys could reduce the resulting anount of entries
  903. log2_size = 17
  904. if log2_size > self._keys.log2_size:
  905. self._resize(log2_size, False)
  906. try:
  907. self._merge_items(cast(Iterator[_Entry[_V]], it))
  908. finally:
  909. self._post_update()
  910. def _merge_items(self, items: Iterator[_Entry[_V]]) -> None:
  911. for entry in items:
  912. hash_ = entry.hash
  913. identity = entry.identity
  914. for slot, idx, e in self._keys.iter_hash(hash_):
  915. if e.identity == identity: # pragma: no branch
  916. break
  917. else:
  918. self._add_with_hash_for_upd(entry)
  919. def _incr_version(self) -> None:
  920. v = _version
  921. v[0] += 1
  922. self._version = v[0]
  923. def _resize(self, log2_newsize: int, update: bool) -> None:
  924. oldkeys = self._keys
  925. newentries = self._used
  926. if len(oldkeys.entries) == newentries:
  927. entries = oldkeys.entries
  928. else:
  929. entries = [e for e in oldkeys.entries if e is not None]
  930. newkeys: _HtKeys[_V] = _HtKeys.new(log2_newsize, entries)
  931. newkeys.usable -= newentries
  932. newkeys.build_indices(update)
  933. self._keys = newkeys
  934. def _add_with_hash(self, entry: _Entry[_V]) -> None:
  935. if self._keys.usable <= 0:
  936. self._resize((self._used * 3 | _HtKeys.MINSIZE - 1).bit_length(), False)
  937. keys = self._keys
  938. slot = keys.find_empty_slot(entry.hash)
  939. keys.indices[slot] = len(keys.entries)
  940. keys.entries.append(entry)
  941. self._incr_version()
  942. self._used += 1
  943. keys.usable -= 1
  944. def _add_with_hash_for_upd(self, entry: _Entry[_V]) -> None:
  945. if self._keys.usable <= 0:
  946. self._resize((self._used * 3 | _HtKeys.MINSIZE - 1).bit_length(), True)
  947. keys = self._keys
  948. slot = keys.find_empty_slot(entry.hash)
  949. keys.indices[slot] = len(keys.entries)
  950. entry.hash = -1
  951. keys.entries.append(entry)
  952. self._incr_version()
  953. self._used += 1
  954. keys.usable -= 1
  955. def _del_at(self, slot: int, idx: int) -> None:
  956. self._keys.entries[idx] = None
  957. self._keys.indices[slot] = -2
  958. self._used -= 1
  959. def _del_at_for_upd(self, entry: _Entry[_V]) -> None:
  960. entry.key = None # type: ignore[assignment]
  961. entry.value = None # type: ignore[assignment]
  962. class CIMultiDict(_CIMixin, MultiDict[_V]):
  963. """Dictionary with the support for duplicate case-insensitive keys."""
  964. class MultiDictProxy(_CSMixin, MultiMapping[_V]):
  965. """Read-only proxy for MultiDict instance."""
  966. __slots__ = ("_md",)
  967. _md: MultiDict[_V]
  968. def __init__(self, arg: Union[MultiDict[_V], "MultiDictProxy[_V]"]):
  969. if not isinstance(arg, (MultiDict, MultiDictProxy)):
  970. raise TypeError(
  971. f"ctor requires MultiDict or MultiDictProxy instance, not {type(arg)}"
  972. )
  973. if isinstance(arg, MultiDictProxy):
  974. self._md = arg._md
  975. else:
  976. self._md = arg
  977. def __reduce__(self) -> NoReturn:
  978. raise TypeError(f"can't pickle {self.__class__.__name__} objects")
  979. @overload
  980. def getall(self, key: str) -> list[_V]: ...
  981. @overload
  982. def getall(self, key: str, default: _T) -> Union[list[_V], _T]: ...
  983. def getall(
  984. self, key: str, default: Union[_T, _SENTINEL] = sentinel
  985. ) -> Union[list[_V], _T]:
  986. """Return a list of all values matching the key."""
  987. if default is not sentinel:
  988. return self._md.getall(key, default)
  989. else:
  990. return self._md.getall(key)
  991. @overload
  992. def getone(self, key: str) -> _V: ...
  993. @overload
  994. def getone(self, key: str, default: _T) -> Union[_V, _T]: ...
  995. def getone(
  996. self, key: str, default: Union[_T, _SENTINEL] = sentinel
  997. ) -> Union[_V, _T]:
  998. """Get first value matching the key.
  999. Raises KeyError if the key is not found and no default is provided.
  1000. """
  1001. if default is not sentinel:
  1002. return self._md.getone(key, default)
  1003. else:
  1004. return self._md.getone(key)
  1005. # Mapping interface #
  1006. def __getitem__(self, key: str) -> _V:
  1007. return self.getone(key)
  1008. @overload
  1009. def get(self, key: str, /) -> Union[_V, None]: ...
  1010. @overload
  1011. def get(self, key: str, /, default: _T) -> Union[_V, _T]: ...
  1012. def get(self, key: str, default: Union[_T, None] = None) -> Union[_V, _T, None]:
  1013. """Get first value matching the key.
  1014. If the key is not found, returns the default (or None if no default is provided)
  1015. """
  1016. return self._md.getone(key, default)
  1017. def __iter__(self) -> Iterator[str]:
  1018. return iter(self._md.keys())
  1019. def __len__(self) -> int:
  1020. return len(self._md)
  1021. def keys(self) -> KeysView[str]:
  1022. """Return a new view of the dictionary's keys."""
  1023. return self._md.keys()
  1024. def items(self) -> ItemsView[str, _V]:
  1025. """Return a new view of the dictionary's items *(key, value) pairs)."""
  1026. return self._md.items()
  1027. def values(self) -> _ValuesView[_V]:
  1028. """Return a new view of the dictionary's values."""
  1029. return self._md.values()
  1030. def __eq__(self, other: object) -> bool:
  1031. return self._md == other
  1032. def __contains__(self, key: object) -> bool:
  1033. return key in self._md
  1034. @reprlib.recursive_repr()
  1035. def __repr__(self) -> str:
  1036. body = ", ".join(f"'{k}': {v!r}" for k, v in self.items())
  1037. return f"<{self.__class__.__name__}({body})>"
  1038. def copy(self) -> MultiDict[_V]:
  1039. """Return a copy of itself."""
  1040. return MultiDict(self._md)
  1041. class CIMultiDictProxy(_CIMixin, MultiDictProxy[_V]):
  1042. """Read-only proxy for CIMultiDict instance."""
  1043. def __init__(self, arg: Union[MultiDict[_V], MultiDictProxy[_V]]):
  1044. if not isinstance(arg, (CIMultiDict, CIMultiDictProxy)):
  1045. raise TypeError(
  1046. "ctor requires CIMultiDict or CIMultiDictProxy instance"
  1047. f", not {type(arg)}"
  1048. )
  1049. super().__init__(arg)
  1050. def copy(self) -> CIMultiDict[_V]:
  1051. """Return a copy of itself."""
  1052. return CIMultiDict(self._md)
  1053. def getversion(md: Union[MultiDict[object], MultiDictProxy[object]]) -> int:
  1054. if isinstance(md, MultiDictProxy):
  1055. md = md._md
  1056. elif not isinstance(md, MultiDict):
  1057. raise TypeError("Parameter should be multidict or proxy")
  1058. return md._version