Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/utils/datastructures.py: 60%

177 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

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 == []: 125 ↛ 126line 125 didn't jump to line 126, because the condition on line 125 was never true

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: 166 ↛ 168line 166 didn't jump to line 168, because the condition on line 166 was never false

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: 200 ↛ 201line 200 didn't jump to line 201, because the condition on line 200 was never true

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

202 if args: 202 ↛ 212line 202 didn't jump to line 212, because the condition on line 202 was never false

203 arg = args[0] 

204 if isinstance(arg, MultiValueDict): 204 ↛ 208line 204 didn't jump to line 208, because the condition on line 204 was never false

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(): 212 ↛ 213line 212 didn't jump to line 213, because the loop on line 212 never started

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 if use_func: 279 ↛ 280line 279 didn't jump to line 280, because the condition on line 279 was never true

280 key = key[len(self.prefix) :] 

281 value = super().__getitem__(key) 

282 if use_func: 282 ↛ 283line 282 didn't jump to line 283, because the condition on line 282 was never true

283 return self.func(value) 

284 return value 

285 

286 

287def _destruct_iterable_mapping_values(data): 

288 for i, elem in enumerate(data): 

289 if len(elem) != 2: 

290 raise ValueError( 

291 "dictionary update sequence element #{} has " 

292 "length {}; 2 is required.".format(i, len(elem)) 

293 ) 

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

295 raise ValueError( 

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

297 ) 

298 yield tuple(elem) 

299 

300 

301class CaseInsensitiveMapping(Mapping): 

302 """ 

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

304 preserved for iteration and string representation. 

305 

306 Example:: 

307 

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

309 >>> ci_map['Name'] 

310 Jane 

311 >>> ci_map['NAME'] 

312 Jane 

313 >>> ci_map['name'] 

314 Jane 

315 >>> ci_map # original case preserved 

316 {'name': 'Jane'} 

317 """ 

318 

319 def __init__(self, data): 

320 if not isinstance(data, Mapping): 

321 data = {k: v for k, v in _destruct_iterable_mapping_values(data)} 

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

323 

324 def __getitem__(self, key): 

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

326 

327 def __len__(self): 

328 return len(self._store) 

329 

330 def __eq__(self, other): 

331 return isinstance(other, Mapping) and { 

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

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

334 

335 def __iter__(self): 

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

337 

338 def __repr__(self): 

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

340 

341 def copy(self): 

342 return self