codekingpro/portable-devtools
115k
1"""2requests.structures3~~~~~~~~~~~~~~~~~~~4 5Data structures that power Requests.6"""7 8from __future__ import annotations9 10from collections import OrderedDict11from collections.abc import Iterable, Iterator, Mapping12from typing import Any, Generic, TypeVar, overload13 14from .compat import MutableMapping15 16_VT = TypeVar("_VT")17_D = TypeVar("_D")18 19 20class CaseInsensitiveDict(MutableMapping[str, _VT], Generic[_VT]):21 """A case-insensitive ``dict``-like object.22 23 Implements all methods and operations of24 ``MutableMapping`` as well as dict's ``copy``. Also25 provides ``lower_items``.26 27 All keys are expected to be strings. The structure remembers the28 case of the last key to be set, and ``iter(instance)``,29 ``keys()``, ``items()``, ``iterkeys()``, and ``iteritems()``30 will contain case-sensitive keys. However, querying and contains31 testing is case insensitive::32 33 cid = CaseInsensitiveDict()34 cid['Accept'] = 'application/json'35 cid['aCCEPT'] == 'application/json' # True36 list(cid) == ['Accept'] # True37 38 For example, ``headers['content-encoding']`` will return the39 value of a ``'Content-Encoding'`` response header, regardless40 of how the header name was originally stored.41 42 If the constructor, ``.update``, or equality comparison43 operations are given keys that have equal ``.lower()``s, the44 behavior is undefined.45 """46 47 _store: OrderedDict[str, tuple[str, _VT]]48 49 def __init__(50 self,51 data: Mapping[str, _VT] | Iterable[tuple[str, _VT]] | None = None,52 **kwargs: _VT,53 ) -> None:54 self._store = OrderedDict()55 if data is None:56 data = {}57 self.update(data, **kwargs)58 59 def __setitem__(self, key: str, value: _VT) -> None:60 # Use the lowercased key for lookups, but store the actual61 # key alongside the value.62 self._store[key.lower()] = (key, value)63 64 def __getitem__(self, key: str) -> _VT:65 return self._store[key.lower()][1]66 67 def __delitem__(self, key: str) -> None:68 del self._store[key.lower()]69 70 def __iter__(self) -> Iterator[str]:71 return (casedkey for casedkey, _ in self._store.values())72 73 def __len__(self) -> int:74 return len(self._store)75 76 def lower_items(self) -> Iterator[tuple[str, _VT]]:77 """Like iteritems(), but with all lowercase keys."""78 return ((lowerkey, keyval[1]) for (lowerkey, keyval) in self._store.items())79 80 def __eq__(self, other: object) -> bool:81 if isinstance(other, Mapping):82 other_dict: CaseInsensitiveDict[Any] = CaseInsensitiveDict(other) # type: ignore[reportUnknownArgumentType]83 else:84 return NotImplemented85 # Compare insensitively86 return dict(self.lower_items()) == dict(other_dict.lower_items())87 88 # Copy is required89 def copy(self) -> CaseInsensitiveDict[_VT]:90 return CaseInsensitiveDict(self._store.values())91 92 def __repr__(self) -> str:93 return str(dict(self.items()))94 95 96class LookupDict(dict[str, _VT]):97 """Dictionary lookup object."""98 99 name: Any100 101 def __init__(self, name: Any = None) -> None:102 self.name = name103 super().__init__()104 105 def __repr__(self) -> str:106 return f"<lookup '{self.name}'>"107 108 def __getattr__(self, key: str) -> _VT | None:109 # We need this for type checkers to infer typing110 # on attribute access with status_codes.py111 if key in self.__dict__:112 return self.__dict__[key]113 else:114 raise AttributeError(115 f"'{type(self).__name__}' object has no attribute '{key}'"116 )117 118 def __getitem__(self, key: str) -> _VT | None: # type: ignore[override]119 # We allow fall-through here, so values default to None120 121 return self.__dict__.get(key, None)122 123 @overload124 def get(self, key: str, default: None = None) -> _VT | None: ...125 126 @overload127 def get(self, key: str, default: _D | _VT) -> _D | _VT: ...128 129 def get(self, key: str, default: _D | None = None) -> _VT | _D | None:130 return self.__dict__.get(key, default)131 