Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/django/utils/datastructures.py: 37%

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

178 statements  

1import copy 

2from collections.abc import Mapping 

3 

4 

5class OrderedSet: 

6 """ 

7 A set which keeps the ordering of the inserted items. 

8 """ 

9 

10 def __init__(self, iterable=None): 

11 self.dict = dict.fromkeys(iterable or ()) 

12 

13 def add(self, item): 

14 self.dict[item] = None 

15 

16 def remove(self, item): 

17 del self.dict[item] 

18 

19 def discard(self, item): 

20 try: 

21 self.remove(item) 

22 except KeyError: 

23 pass 

24 

25 def __iter__(self): 

26 return iter(self.dict) 

27 

28 def __reversed__(self): 

29 return reversed(self.dict) 

30 

31 def __contains__(self, item): 

32 return item in self.dict 

33 

34 def __bool__(self): 

35 return bool(self.dict) 

36 

37 def __len__(self): 

38 return len(self.dict) 

39 

40 def __repr__(self): 

41 data = repr(list(self.dict)) if self.dict else "" 

42 return f"{self.__class__.__qualname__}({data})" 

43 

44 

45class MultiValueDictKeyError(KeyError): 

46 pass 

47 

48 

49class MultiValueDict(dict): 

50 """ 

51 A subclass of dictionary customized to handle multiple values for the 

52 same key. 

53 

54 >>> d = MultiValueDict({'name': ['Adrian', 'Simon'], 'position': ['Developer']}) 

55 >>> d['name'] 

56 'Simon' 

57 >>> d.getlist('name') 

58 ['Adrian', 'Simon'] 

59 >>> d.getlist('doesnotexist') 

60 [] 

61 >>> d.getlist('doesnotexist', ['Adrian', 'Simon']) 

62 ['Adrian', 'Simon'] 

63 >>> d.get('lastname', 'nonexistent') 

64 'nonexistent' 

65 >>> d.setlist('lastname', ['Holovaty', 'Willison']) 

66 

67 This class exists to solve the irritating problem raised by cgi.parse_qs, 

68 which returns a list for every key, even though most web forms submit 

69 single name-value pairs. 

70 """ 

71 

72 def __init__(self, key_to_list_mapping=()): 

73 super().__init__(key_to_list_mapping) 

74 

75 def __repr__(self): 

76 return "<%s: %s>" % (self.__class__.__name__, super().__repr__()) 

77 

78 def __getitem__(self, key): 

79 """ 

80 Return the last data value for this key, or [] if it's an empty list; 

81 raise KeyError if not found. 

82 """ 

83 try: 

84 list_ = super().__getitem__(key) 

85 except KeyError: 

86 raise MultiValueDictKeyError(key) 

87 try: 

88 return list_[-1] 

89 except IndexError: 

90 return [] 

91 

92 def __setitem__(self, key, value): 

93 super().__setitem__(key, [value]) 

94 

95 def __copy__(self): 

96 return self.__class__([(k, v[:]) for k, v in self.lists()]) 

97 

98 def __deepcopy__(self, memo): 

99 result = self.__class__() 

100 memo[id(self)] = result 

101 for key, value in dict.items(self): 

102 dict.__setitem__( 

103 result, copy.deepcopy(key, memo), copy.deepcopy(value, memo) 

104 ) 

105 return result 

106 

107 def __getstate__(self): 

108 return {**self.__dict__, "_data": {k: self._getlist(k) for k in self}} 

109 

110 def __setstate__(self, obj_dict): 

111 data = obj_dict.pop("_data", {}) 

112 for k, v in data.items(): 

113 self.setlist(k, v) 

114 self.__dict__.update(obj_dict) 

115 

116 def get(self, key, default=None): 

117 """ 

118 Return the last data value for the passed key. If key doesn't exist 

119 or value is an empty list, return `default`. 

120 """ 

121 try: 

122 val = self[key] 

123 except KeyError: 

124 return default 

125 if val == []: 

126 return default 

127 return val 

128 

129 def _getlist(self, key, default=None, force_list=False): 

130 """ 

131 Return a list of values for the key. 

132 

133 Used internally to manipulate values list. If force_list is True, 

134 return a new copy of values. 

135 """ 

136 try: 

137 values = super().__getitem__(key) 

138 except KeyError: 

139 if default is None: 

140 return [] 

141 return default 

142 else: 

143 if force_list: 

144 values = list(values) if values is not None else None 

145 return values 

146 

147 def getlist(self, key, default=None): 

148 """ 

149 Return the list of values for the key. If key doesn't exist, return a 

150 default value. 

151 """ 

152 return self._getlist(key, default, force_list=True) 

153 

154 def setlist(self, key, list_): 

155 super().__setitem__(key, list_) 

156 

157 def setdefault(self, key, default=None): 

158 if key not in self: 

159 self[key] = default 

160 # Do not return default here because __setitem__() may store 

161 # another value -- QueryDict.__setitem__() does. Look it up. 

162 return self[key] 

163 

164 def setlistdefault(self, key, default_list=None): 

165 if key not in self: 

166 if default_list is None: 

167 default_list = [] 

168 self.setlist(key, default_list) 

169 # Do not return default_list here because setlist() may store 

170 # another value -- QueryDict.setlist() does. Look it up. 

171 return self._getlist(key) 

172 

173 def appendlist(self, key, value): 

174 """Append an item to the internal list associated with key.""" 

175 self.setlistdefault(key).append(value) 

176 

177 def items(self): 

178 """ 

179 Yield (key, value) pairs, where value is the last item in the list 

180 associated with the key. 

181 """ 

182 for key in self: 

183 yield key, self[key] 

184 

185 def lists(self): 

186 """Yield (key, list) pairs.""" 

187 return iter(super().items()) 

188 

189 def values(self): 

190 """Yield the last value on every key list.""" 

191 for key in self: 

192 yield self[key] 

193 

194 def copy(self): 

195 """Return a shallow copy of this object.""" 

196 return copy.copy(self) 

197 

198 def update(self, *args, **kwargs): 

199 """Extend rather than replace existing key lists.""" 

200 if len(args) > 1: 

201 raise TypeError("update expected at most 1 argument, got %d" % len(args)) 

202 if args: 

203 arg = args[0] 

204 if isinstance(arg, MultiValueDict): 

205 for key, value_list in arg.lists(): 

206 self.setlistdefault(key).extend(value_list) 

207 else: 

208 if isinstance(arg, Mapping): 

209 arg = arg.items() 

210 for key, value in arg: 

211 self.setlistdefault(key).append(value) 

212 for key, value in kwargs.items(): 

213 self.setlistdefault(key).append(value) 

214 

215 def dict(self): 

216 """Return current object as a dict with singular values.""" 

217 return {key: self[key] for key in self} 

218 

219 

220class ImmutableList(tuple): 

221 """ 

222 A tuple-like object that raises useful errors when it is asked to mutate. 

223 

224 Example:: 

225 

226 >>> a = ImmutableList(range(5), warning="You cannot mutate this.") 

227 >>> a[3] = '4' 

228 Traceback (most recent call last): 

229 ... 

230 AttributeError: You cannot mutate this. 

231 """ 

232 

233 def __new__(cls, *args, warning="ImmutableList object is immutable.", **kwargs): 

234 self = tuple.__new__(cls, *args, **kwargs) 

235 self.warning = warning 

236 return self 

237 

238 def complain(self, *args, **kwargs): 

239 raise AttributeError(self.warning) 

240 

241 # All list mutation functions complain. 

242 __delitem__ = complain 

243 __delslice__ = complain 

244 __iadd__ = complain 

245 __imul__ = complain 

246 __setitem__ = complain 

247 __setslice__ = complain 

248 append = complain 

249 extend = complain 

250 insert = complain 

251 pop = complain 

252 remove = complain 

253 sort = complain 

254 reverse = complain 

255 

256 

257class DictWrapper(dict): 

258 """ 

259 Wrap accesses to a dictionary so that certain values (those starting with 

260 the specified prefix) are passed through a function before being returned. 

261 The prefix is removed before looking up the real value. 

262 

263 Used by the SQL construction code to ensure that values are correctly 

264 quoted before being used. 

265 """ 

266 

267 def __init__(self, data, func, prefix): 

268 super().__init__(data) 

269 self.func = func 

270 self.prefix = prefix 

271 

272 def __getitem__(self, key): 

273 """ 

274 Retrieve the real value after stripping the prefix string (if 

275 present). If the prefix is present, pass the value through self.func 

276 before returning, otherwise return the raw value. 

277 """ 

278 use_func = key.startswith(self.prefix) 

279 key = key.removeprefix(self.prefix) 

280 value = super().__getitem__(key) 

281 if use_func: 

282 return self.func(value) 

283 return value 

284 

285 

286class CaseInsensitiveMapping(Mapping): 

287 """ 

288 Mapping allowing case-insensitive key lookups. Original case of keys is 

289 preserved for iteration and string representation. 

290 

291 Example:: 

292 

293 >>> ci_map = CaseInsensitiveMapping({'name': 'Jane'}) 

294 >>> ci_map['Name'] 

295 Jane 

296 >>> ci_map['NAME'] 

297 Jane 

298 >>> ci_map['name'] 

299 Jane 

300 >>> ci_map # original case preserved 

301 {'name': 'Jane'} 

302 """ 

303 

304 def __init__(self, data): 

305 self._store = {k.lower(): (k, v) for k, v in self._unpack_items(data)} 

306 

307 def __getitem__(self, key): 

308 return self._store[key.lower()][1] 

309 

310 def __len__(self): 

311 return len(self._store) 

312 

313 def __eq__(self, other): 

314 return isinstance(other, Mapping) and { 

315 k.lower(): v for k, v in self.items() 

316 } == {k.lower(): v for k, v in other.items()} 

317 

318 def __iter__(self): 

319 return (original_key for original_key, value in self._store.values()) 

320 

321 def __repr__(self): 

322 return repr({key: value for key, value in self._store.values()}) 

323 

324 def copy(self): 

325 return self 

326 

327 @staticmethod 

328 def _unpack_items(data): 

329 # Explicitly test for dict first as the common case for performance, 

330 # avoiding abc's __instancecheck__ and _abc_instancecheck for the 

331 # general Mapping case. 

332 if isinstance(data, (dict, Mapping)): 

333 yield from data.items() 

334 return 

335 for i, elem in enumerate(data): 

336 if len(elem) != 2: 

337 raise ValueError( 

338 "dictionary update sequence element #{} has length {}; " 

339 "2 is required.".format(i, len(elem)) 

340 ) 

341 if not isinstance(elem[0], str): 

342 raise ValueError( 

343 "Element key %r invalid, only strings are allowed" % elem[0] 

344 ) 

345 yield elem