Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/requests/structures.py: 64%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

55 statements  

1""" 

2requests.structures 

3~~~~~~~~~~~~~~~~~~~ 

4 

5Data structures that power Requests. 

6""" 

7 

8from __future__ import annotations 

9 

10from collections import OrderedDict 

11from collections.abc import Iterable, Iterator, Mapping 

12from typing import Any, Generic, TypeVar, overload 

13 

14from .compat import MutableMapping 

15 

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 of 

24 ``MutableMapping`` as well as dict's ``copy``. Also 

25 provides ``lower_items``. 

26 

27 All keys are expected to be strings. The structure remembers the 

28 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 contains 

31 testing is case insensitive:: 

32 

33 cid = CaseInsensitiveDict() 

34 cid['Accept'] = 'application/json' 

35 cid['aCCEPT'] == 'application/json' # True 

36 list(cid) == ['Accept'] # True 

37 

38 For example, ``headers['content-encoding']`` will return the 

39 value of a ``'Content-Encoding'`` response header, regardless 

40 of how the header name was originally stored. 

41 

42 If the constructor, ``.update``, or equality comparison 

43 operations are given keys that have equal ``.lower()``s, the 

44 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 actual 

61 # 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 NotImplemented 

85 # Compare insensitively 

86 return dict(self.lower_items()) == dict(other_dict.lower_items()) 

87 

88 # Copy is required 

89 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: Any 

100 

101 def __init__(self, name: Any = None) -> None: 

102 self.name = name 

103 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 typing 

110 # on attribute access with status_codes.py 

111 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 None 

120 

121 return self.__dict__.get(key, None) 

122 

123 @overload 

124 def get(self, key: str, default: None = None) -> _VT | None: ... 

125 

126 @overload 

127 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)