Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/werkzeug/datastructures/structures.py: 44%

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

387 statements  

1from __future__ import annotations 

2 

3import collections.abc as cabc 

4import typing as t 

5from copy import deepcopy 

6 

7from .. import exceptions 

8from .._internal import _missing 

9from .mixins import _ImmutableDictMixin 

10from .mixins import _ImmutableListMixin 

11from .mixins import ImmutableMultiDictMixin 

12 

13K = t.TypeVar("K") 

14V = t.TypeVar("V") 

15T = t.TypeVar("T") 

16 

17 

18def iter_multi_items( 

19 mapping: ( 

20 MultiDict[K, V] 

21 | cabc.Mapping[K, V | list[V] | tuple[V, ...] | set[V]] 

22 | cabc.Iterable[tuple[K, V]] 

23 ), 

24) -> cabc.Iterator[tuple[K, V]]: 

25 """Iterates over the items of a mapping yielding keys and values 

26 without dropping any from more complex structures. 

27 """ 

28 if isinstance(mapping, MultiDict): 

29 yield from mapping.items(multi=True) 

30 elif isinstance(mapping, cabc.Mapping): 

31 for key, value in mapping.items(): 

32 if isinstance(value, (list, tuple, set)): 

33 for v in value: 

34 yield key, v 

35 else: 

36 yield key, value 

37 else: 

38 yield from mapping 

39 

40 

41class _ImmutableList(_ImmutableListMixin, list[V]): # type: ignore[misc] 

42 """An immutable :class:`list`. 

43 

44 .. deprecated:: 3.2 

45 Will be removed in Werkzeug 4.0. Use ``collections.abc.Sequence`` 

46 instead. 

47 

48 .. versionadded:: 0.5 

49 

50 :private: 

51 """ 

52 

53 def __repr__(self) -> str: 

54 return f"{type(self).__name__}({list.__repr__(self)})" 

55 

56 

57class _TypeConversionDict(dict[K, V]): 

58 """Works like a regular dict but the :meth:`get` method can perform 

59 type conversions. :class:`MultiDict` and :class:`CombinedMultiDict` 

60 are subclasses of this class and provide the same feature. 

61 

62 .. versionadded:: 0.5 

63 """ 

64 

65 @t.overload # type: ignore[override] 

66 def get(self, key: K) -> V | None: ... 

67 @t.overload 

68 def get(self, key: K, default: V) -> V: ... 

69 @t.overload 

70 def get(self, key: K, default: T) -> V | T: ... 

71 @t.overload 

72 def get(self, key: str, type: cabc.Callable[[V], T]) -> T | None: ... 

73 @t.overload 

74 def get(self, key: str, default: T, type: cabc.Callable[[V], T]) -> T: ... 

75 def get( # type: ignore[misc] 

76 self, 

77 key: K, 

78 default: V | T | None = None, 

79 type: cabc.Callable[[V], T] | None = None, 

80 ) -> V | T | None: 

81 """Return the default value if the requested data doesn't exist. 

82 If `type` is provided and is a callable it should convert the value, 

83 return it or raise a :exc:`ValueError` if that is not possible. In 

84 this case the function will return the default as if the value was not 

85 found: 

86 

87 >>> d = TypeConversionDict(foo='42', bar='blub') 

88 >>> d.get('foo', type=int) 

89 42 

90 >>> d.get('bar', -1, type=int) 

91 -1 

92 

93 :param key: The key to be looked up. 

94 :param default: The default value to be returned if the key can't 

95 be looked up. If not further specified `None` is 

96 returned. 

97 :param type: A callable that is used to cast the value in the 

98 :class:`MultiDict`. If a :exc:`ValueError` or a 

99 :exc:`TypeError` is raised by this callable the default 

100 value is returned. 

101 

102 .. versionchanged:: 3.0.2 

103 Returns the default value on :exc:`TypeError`, too. 

104 """ 

105 try: 

106 rv = self[key] 

107 except KeyError: 

108 return default 

109 

110 if type is None: 

111 return rv 

112 

113 try: 

114 return type(rv) 

115 except (ValueError, TypeError): 

116 return default 

117 

118 

119class _ImmutableTypeConversionDict( # type: ignore[misc] 

120 _ImmutableDictMixin[K, V], _TypeConversionDict[K, V] 

121): 

122 """Works like a :class:`TypeConversionDict` but does not support 

123 modifications. 

124 

125 .. versionadded:: 0.5 

126 """ 

127 

128 def copy(self) -> _TypeConversionDict[K, V]: 

129 """Return a shallow mutable copy of this object. Keep in mind that 

130 the standard library's :func:`copy` function is a no-op for this class 

131 like for any other python immutable type (eg: :class:`tuple`). 

132 """ 

133 return _TypeConversionDict(self) 

134 

135 def __copy__(self) -> t.Self: 

136 return self 

137 

138 

139class MultiDict(dict[K, V]): 

140 """A :class:`MultiDict` is a dictionary subclass customized to deal with 

141 multiple values for the same key which is for example used by the parsing 

142 functions in the wrappers. This is necessary because some HTML form 

143 elements pass multiple values for the same key. 

144 

145 :class:`MultiDict` implements all standard dictionary methods. 

146 Internally, it saves all values for a key as a list, but the standard dict 

147 access methods will only return the first value for a key. If you want to 

148 gain access to the other values, too, you have to use the `list` methods as 

149 explained below. 

150 

151 Basic Usage: 

152 

153 >>> d = MultiDict([('a', 'b'), ('a', 'c')]) 

154 >>> d 

155 MultiDict([('a', 'b'), ('a', 'c')]) 

156 >>> d['a'] 

157 'b' 

158 >>> d.getlist('a') 

159 ['b', 'c'] 

160 >>> 'a' in d 

161 True 

162 

163 It behaves like a normal dict thus all dict functions will only return the 

164 first value when multiple values for one key are found. 

165 

166 From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a 

167 subclass of the :exc:`~exceptions.BadRequest` HTTP exception and will 

168 render a page for a ``400 BAD REQUEST`` if caught in a catch-all for HTTP 

169 exceptions. 

170 

171 A :class:`MultiDict` can be constructed from an iterable of 

172 ``(key, value)`` tuples, a dict, a :class:`MultiDict` or from Werkzeug 0.2 

173 onwards some keyword parameters. 

174 

175 :param mapping: the initial value for the :class:`MultiDict`. Either a 

176 regular dict, an iterable of ``(key, value)`` tuples 

177 or `None`. 

178 

179 .. versionchanged:: 3.1 

180 Implement ``|`` and ``|=`` operators. 

181 """ 

182 

183 def __init__( 

184 self, 

185 mapping: ( 

186 MultiDict[K, V] 

187 | cabc.Mapping[K, V | list[V] | tuple[V, ...] | set[V]] 

188 | cabc.Iterable[tuple[K, V]] 

189 | None 

190 ) = None, 

191 ) -> None: 

192 if mapping is None: 

193 super().__init__() 

194 elif isinstance(mapping, MultiDict): 

195 super().__init__((k, vs[:]) for k, vs in mapping.lists()) # type: ignore[misc] 

196 elif isinstance(mapping, cabc.Mapping): 

197 tmp = {} 

198 for key, value in mapping.items(): 

199 if isinstance(value, (list, tuple, set)): 

200 value = list(value) 

201 

202 if not value: 

203 continue 

204 else: 

205 value = [value] 

206 tmp[key] = value 

207 super().__init__(tmp) # type: ignore[arg-type] 

208 else: 

209 tmp = {} 

210 for key, value in mapping: 

211 tmp.setdefault(key, []).append(value) 

212 super().__init__(tmp) # type: ignore[arg-type] 

213 

214 def __getstate__(self) -> t.Any: 

215 return dict(self.lists()) 

216 

217 def __setstate__(self, value: t.Any) -> None: 

218 super().clear() 

219 super().update(value) 

220 

221 def __iter__(self) -> cabc.Iterator[K]: 

222 # https://github.com/python/cpython/issues/87412 

223 # If __iter__ is not overridden, Python uses a fast path for dict(md), 

224 # taking the data directly and getting lists of values, rather than 

225 # calling __getitem__ and getting only the first value. 

226 return super().__iter__() 

227 

228 def __getitem__(self, key: K) -> V: 

229 """Return the first data value for this key; 

230 raises KeyError if not found. 

231 

232 :param key: The key to be looked up. 

233 :raise KeyError: if the key does not exist. 

234 """ 

235 

236 if key in self: 

237 lst = super().__getitem__(key) 

238 if len(lst) > 0: # type: ignore[arg-type] 

239 return lst[0] # type: ignore[index,no-any-return] 

240 raise exceptions.BadRequestKeyError(key) 

241 

242 def __setitem__(self, key: K, value: V) -> None: 

243 """Like :meth:`add` but removes an existing key first. 

244 

245 :param key: the key for the value. 

246 :param value: the value to set. 

247 """ 

248 super().__setitem__(key, [value]) # type: ignore[assignment] 

249 

250 def add(self, key: K, value: V) -> None: 

251 """Adds a new value for the key. 

252 

253 .. versionadded:: 0.6 

254 

255 :param key: the key for the value. 

256 :param value: the value to add. 

257 """ 

258 super().setdefault(key, []).append(value) # type: ignore[arg-type,attr-defined] 

259 

260 @t.overload # type: ignore[override] 

261 def get(self, key: K) -> V | None: ... 

262 @t.overload 

263 def get(self, key: K, default: V) -> V: ... 

264 @t.overload 

265 def get(self, key: K, default: T) -> V | T: ... 

266 @t.overload 

267 def get(self, key: str, type: cabc.Callable[[V], T]) -> T | None: ... 

268 @t.overload 

269 def get(self, key: str, default: T, type: cabc.Callable[[V], T]) -> T: ... 

270 def get( # type: ignore[misc] 

271 self, 

272 key: K, 

273 default: V | T | None = None, 

274 type: cabc.Callable[[V], T] | None = None, 

275 ) -> V | T | None: 

276 """Get the first value for the key, or a default if it's not set. 

277 

278 :param key: The key to get. 

279 :param default: The value to return if the key is not set. 

280 :param type: Convert the value using this function. If it raises a 

281 ``TypeError`` or ``ValueError``, return ``default``. 

282 

283 .. versionchanged:: 3.0.2 

284 Returns the default value on :exc:`TypeError`, too. 

285 """ 

286 try: 

287 rv = self[key] 

288 except KeyError: 

289 return default 

290 

291 if type is None: 

292 return rv 

293 

294 try: 

295 return type(rv) 

296 except (ValueError, TypeError): 

297 return default 

298 

299 @t.overload 

300 def getlist(self, key: K) -> list[V]: ... 

301 @t.overload 

302 def getlist(self, key: K, type: cabc.Callable[[V], T]) -> list[T]: ... 

303 def getlist( 

304 self, key: K, type: cabc.Callable[[V], T] | None = None 

305 ) -> list[V] | list[T]: 

306 """Return the list of items for a given key. If that key is not in the 

307 `MultiDict`, the return value will be an empty list. Just like `get`, 

308 `getlist` accepts a `type` parameter. All items will be converted 

309 with the callable defined there. 

310 

311 :param key: The key to be looked up. 

312 :param type: Callable to convert each value. If a ``ValueError`` or 

313 ``TypeError`` is raised, the value is omitted. 

314 :return: a :class:`list` of all the values for the key. 

315 

316 .. versionchanged:: 3.1 

317 Catches ``TypeError`` in addition to ``ValueError``. 

318 """ 

319 try: 

320 rv: list[V] = super().__getitem__(key) # type: ignore[assignment] 

321 except KeyError: 

322 return [] 

323 if type is None: 

324 return list(rv) 

325 result = [] 

326 for item in rv: 

327 try: 

328 result.append(type(item)) 

329 except (ValueError, TypeError): 

330 pass 

331 return result 

332 

333 def setlist(self, key: K, new_list: cabc.Iterable[V]) -> None: 

334 """Remove the old values for a key and add new ones. Note that the list 

335 you pass the values in will be shallow-copied before it is inserted in 

336 the dictionary. 

337 

338 >>> d = MultiDict() 

339 >>> d.setlist('foo', ['1', '2']) 

340 >>> d['foo'] 

341 '1' 

342 >>> d.getlist('foo') 

343 ['1', '2'] 

344 

345 :param key: The key for which the values are set. 

346 :param new_list: An iterable with the new values for the key. Old values 

347 are removed first. 

348 """ 

349 super().__setitem__(key, list(new_list)) # type: ignore[assignment] 

350 

351 @t.overload 

352 def setdefault(self, key: K) -> None: ... 

353 @t.overload 

354 def setdefault(self, key: K, default: V) -> V: ... 

355 def setdefault(self, key: K, default: V | None = None) -> V | None: 

356 """Returns the value for the key if it is in the dict, otherwise it 

357 returns `default` and sets that value for `key`. 

358 

359 :param key: The key to be looked up. 

360 :param default: The default value to be returned if the key is not 

361 in the dict. If not further specified it's `None`. 

362 """ 

363 if key not in self: 

364 self[key] = default # type: ignore[assignment] 

365 

366 return self[key] 

367 

368 def setlistdefault( 

369 self, key: K, default_list: cabc.Iterable[V] | None = None 

370 ) -> list[V]: 

371 """Like `setdefault` but sets multiple values. The list returned 

372 is not a copy, but the list that is actually used internally. This 

373 means that you can put new values into the dict by appending items 

374 to the list: 

375 

376 >>> d = MultiDict({"foo": 1}) 

377 >>> d.setlistdefault("foo").extend([2, 3]) 

378 >>> d.getlist("foo") 

379 [1, 2, 3] 

380 

381 :param key: The key to be looked up. 

382 :param default_list: An iterable of default values. It is either copied 

383 (in case it was a list) or converted into a list 

384 before returned. 

385 :return: a :class:`list` 

386 """ 

387 if key not in self: 

388 super().__setitem__(key, list(default_list or ())) # type: ignore[assignment] 

389 

390 return super().__getitem__(key) # type: ignore[return-value] 

391 

392 def items(self, multi: bool = False) -> cabc.Iterable[tuple[K, V]]: # type: ignore[override] 

393 """Return an iterator of ``(key, value)`` pairs. 

394 

395 :param multi: If set to `True` the iterator returned will have a pair 

396 for each value of each key. Otherwise it will only 

397 contain pairs for the first value of each key. 

398 """ 

399 values: list[V] 

400 

401 for key, values in super().items(): # type: ignore[assignment] 

402 if multi: 

403 for value in values: 

404 yield key, value 

405 else: 

406 yield key, values[0] 

407 

408 def lists(self) -> cabc.Iterable[tuple[K, list[V]]]: 

409 """Return a iterator of ``(key, values)`` pairs, where values is the list 

410 of all values associated with the key.""" 

411 values: list[V] 

412 

413 for key, values in super().items(): # type: ignore[assignment] 

414 yield key, list(values) 

415 

416 def values(self) -> cabc.Iterable[V]: # type: ignore[override] 

417 """Returns an iterator of the first value on every key's value list.""" 

418 values: list[V] 

419 

420 for values in super().values(): # type: ignore[assignment] 

421 yield values[0] 

422 

423 def listvalues(self) -> cabc.Iterable[list[V]]: 

424 """Return an iterator of all values associated with a key. Zipping 

425 :meth:`keys` and this is the same as calling :meth:`lists`: 

426 

427 >>> d = MultiDict({"foo": [1, 2, 3]}) 

428 >>> zip(d.keys(), d.listvalues()) == d.lists() 

429 True 

430 """ 

431 return super().values() # type: ignore[return-value] 

432 

433 def copy(self) -> t.Self: 

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

435 return self.__class__(self) 

436 

437 def deepcopy(self, memo: t.Any = None) -> t.Self: 

438 """Return a deep copy of this object.""" 

439 return self.__class__(deepcopy(self.to_dict(flat=False), memo)) 

440 

441 @t.overload 

442 def to_dict(self, flat: t.Literal[True] = ...) -> dict[K, V]: ... 

443 @t.overload 

444 def to_dict(self, flat: t.Literal[False]) -> dict[K, list[V]]: ... 

445 def to_dict(self, flat: bool = True) -> dict[K, V] | dict[K, list[V]]: 

446 """Return the contents as regular dict. If `flat` is `True` the 

447 returned dict will only have the first item present, if `flat` is 

448 `False` all values will be returned as lists. 

449 

450 :param flat: If set to `False` the dict returned will have lists 

451 with all the values in it. Otherwise it will only 

452 contain the first value for each key. 

453 :return: a :class:`dict` 

454 """ 

455 if flat: 

456 return dict(self.items()) 

457 return dict(self.lists()) 

458 

459 def update( # type: ignore[override] 

460 self, 

461 mapping: ( 

462 MultiDict[K, V] 

463 | cabc.Mapping[K, V | list[V] | tuple[V, ...] | set[V]] 

464 | cabc.Iterable[tuple[K, V]] 

465 ), 

466 ) -> None: 

467 """update() extends rather than replaces existing key lists: 

468 

469 >>> a = MultiDict({'x': 1}) 

470 >>> b = MultiDict({'x': 2, 'y': 3}) 

471 >>> a.update(b) 

472 >>> a 

473 MultiDict([('y', 3), ('x', 1), ('x', 2)]) 

474 

475 If the value list for a key in ``other_dict`` is empty, no new values 

476 will be added to the dict and the key will not be created: 

477 

478 >>> x = {'empty_list': []} 

479 >>> y = MultiDict() 

480 >>> y.update(x) 

481 >>> y 

482 MultiDict([]) 

483 """ 

484 for key, value in iter_multi_items(mapping): 

485 self.add(key, value) 

486 

487 def __or__( # type: ignore[override] 

488 self, other: cabc.Mapping[K, V | list[V] | tuple[V, ...] | set[V]] 

489 ) -> MultiDict[K, V]: 

490 if not isinstance(other, cabc.Mapping): 

491 return NotImplemented 

492 

493 rv = self.copy() 

494 rv.update(other) 

495 return rv 

496 

497 def __ior__( # type: ignore[override] 

498 self, 

499 other: ( 

500 cabc.Mapping[K, V | list[V] | tuple[V, ...] | set[V]] 

501 | cabc.Iterable[tuple[K, V]] 

502 ), 

503 ) -> t.Self: 

504 if not isinstance(other, (cabc.Mapping, cabc.Iterable)): 

505 return NotImplemented 

506 

507 self.update(other) 

508 return self 

509 

510 @t.overload 

511 def pop(self, key: K) -> V: ... 

512 @t.overload 

513 def pop(self, key: K, default: V) -> V: ... 

514 @t.overload 

515 def pop(self, key: K, default: T) -> V | T: ... 

516 def pop( 

517 self, 

518 key: K, 

519 default: V | T = _missing, # type: ignore[assignment] 

520 ) -> V | T: 

521 """Pop the first item for a list on the dict. Afterwards the 

522 key is removed from the dict, so additional values are discarded: 

523 

524 >>> d = MultiDict({"foo": [1, 2, 3]}) 

525 >>> d.pop("foo") 

526 1 

527 >>> "foo" in d 

528 False 

529 

530 :param key: the key to pop. 

531 :param default: if provided the value to return if the key was 

532 not in the dictionary. 

533 """ 

534 lst: list[V] 

535 

536 try: 

537 lst = super().pop(key) # type: ignore[assignment] 

538 

539 if len(lst) == 0: 

540 raise exceptions.BadRequestKeyError(key) 

541 

542 return lst[0] 

543 except KeyError: 

544 if default is not _missing: 

545 return default 

546 

547 raise exceptions.BadRequestKeyError(key) from None 

548 

549 def popitem(self) -> tuple[K, V]: 

550 """Pop an item from the dict.""" 

551 item: tuple[K, list[V]] 

552 

553 try: 

554 item = super().popitem() # type: ignore[assignment] 

555 

556 if len(item[1]) == 0: 

557 raise exceptions.BadRequestKeyError(item[0]) 

558 

559 return item[0], item[1][0] 

560 except KeyError as e: 

561 raise exceptions.BadRequestKeyError(e.args[0]) from None 

562 

563 def poplist(self, key: K) -> list[V]: 

564 """Pop the list for a key from the dict. If the key is not in the dict 

565 an empty list is returned. 

566 

567 .. versionchanged:: 0.5 

568 If the key does no longer exist a list is returned instead of 

569 raising an error. 

570 """ 

571 return super().pop(key, []) # type: ignore[return-value] 

572 

573 def popitemlist(self) -> tuple[K, list[V]]: 

574 """Pop a ``(key, list)`` tuple from the dict.""" 

575 try: 

576 return super().popitem() # type: ignore[return-value] 

577 except KeyError as e: 

578 raise exceptions.BadRequestKeyError(e.args[0]) from None 

579 

580 def __copy__(self) -> t.Self: 

581 return self.copy() 

582 

583 def __deepcopy__(self, memo: t.Any) -> t.Self: 

584 return self.deepcopy(memo=memo) 

585 

586 def __repr__(self) -> str: 

587 return f"{type(self).__name__}({list(self.items(multi=True))!r})" 

588 

589 

590class CombinedMultiDict(ImmutableMultiDictMixin[K, V], MultiDict[K, V]): # type: ignore[misc] 

591 """A read only :class:`MultiDict` that you can pass multiple :class:`MultiDict` 

592 instances as sequence and it will combine the return values of all wrapped 

593 dicts: 

594 

595 >>> from werkzeug.datastructures import CombinedMultiDict, MultiDict 

596 >>> post = MultiDict([('foo', 'bar')]) 

597 >>> get = MultiDict([('blub', 'blah')]) 

598 >>> combined = CombinedMultiDict([get, post]) 

599 >>> combined['foo'] 

600 'bar' 

601 >>> combined['blub'] 

602 'blah' 

603 

604 This works for all read operations and will raise a `TypeError` for 

605 methods that usually change data which isn't possible. 

606 

607 From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a 

608 subclass of the :exc:`~exceptions.BadRequest` HTTP exception and will 

609 render a page for a ``400 BAD REQUEST`` if caught in a catch-all for HTTP 

610 exceptions. 

611 """ 

612 

613 def __reduce_ex__(self, protocol: t.SupportsIndex) -> t.Any: 

614 return type(self), (self.dicts,) 

615 

616 def __init__(self, dicts: cabc.Iterable[MultiDict[K, V]] | None = None) -> None: 

617 super().__init__() 

618 self.dicts: list[MultiDict[K, V]] = list(dicts or ()) 

619 

620 @classmethod 

621 def fromkeys(cls, keys: t.Any, value: t.Any = None) -> t.NoReturn: 

622 raise TypeError(f"cannot create {cls.__name__!r} instances by fromkeys") 

623 

624 def __getitem__(self, key: K) -> V: 

625 for d in self.dicts: 

626 if key in d: 

627 return d[key] 

628 raise exceptions.BadRequestKeyError(key) 

629 

630 @t.overload # type: ignore[override] 

631 def get(self, key: K) -> V | None: ... 

632 @t.overload 

633 def get(self, key: K, default: V) -> V: ... 

634 @t.overload 

635 def get(self, key: K, default: T) -> V | T: ... 

636 @t.overload 

637 def get(self, key: str, type: cabc.Callable[[V], T]) -> T | None: ... 

638 @t.overload 

639 def get(self, key: str, default: T, type: cabc.Callable[[V], T]) -> T: ... 

640 def get( # type: ignore[misc] 

641 self, 

642 key: K, 

643 default: V | T | None = None, 

644 type: cabc.Callable[[V], T] | None = None, 

645 ) -> V | T | None: 

646 for d in self.dicts: 

647 if key in d: 

648 if type is not None: 

649 try: 

650 return type(d[key]) 

651 except (ValueError, TypeError): 

652 continue 

653 return d[key] 

654 return default 

655 

656 @t.overload 

657 def getlist(self, key: K) -> list[V]: ... 

658 @t.overload 

659 def getlist(self, key: K, type: cabc.Callable[[V], T]) -> list[T]: ... 

660 def getlist( 

661 self, key: K, type: cabc.Callable[[V], T] | None = None 

662 ) -> list[V] | list[T]: 

663 rv = [] 

664 for d in self.dicts: 

665 rv.extend(d.getlist(key, type)) # type: ignore[arg-type] 

666 return rv 

667 

668 def _keys_impl(self) -> set[K]: 

669 """This function exists so __len__ can be implemented more efficiently, 

670 saving one list creation from an iterator. 

671 """ 

672 return set(k for d in self.dicts for k in d) 

673 

674 def keys(self) -> cabc.Iterable[K]: # type: ignore[override] 

675 return self._keys_impl() 

676 

677 def __iter__(self) -> cabc.Iterator[K]: 

678 return iter(self._keys_impl()) 

679 

680 @t.overload # type: ignore[override] 

681 def items(self) -> cabc.Iterable[tuple[K, V]]: ... 

682 @t.overload 

683 def items(self, multi: t.Literal[True]) -> cabc.Iterable[tuple[K, list[V]]]: ... 

684 def items( 

685 self, multi: bool = False 

686 ) -> cabc.Iterable[tuple[K, V]] | cabc.Iterable[tuple[K, list[V]]]: 

687 found = set() 

688 for d in self.dicts: 

689 for key, value in d.items(multi): 

690 if multi: 

691 yield key, value 

692 elif key not in found: 

693 found.add(key) 

694 yield key, value 

695 

696 def values(self) -> cabc.Iterable[V]: # type: ignore[override] 

697 for _, value in self.items(): 

698 yield value 

699 

700 def lists(self) -> cabc.Iterable[tuple[K, list[V]]]: 

701 rv: dict[K, list[V]] = {} 

702 for d in self.dicts: 

703 for key, values in d.lists(): 

704 rv.setdefault(key, []).extend(values) 

705 return rv.items() 

706 

707 def listvalues(self) -> cabc.Iterable[list[V]]: 

708 return (x[1] for x in self.lists()) 

709 

710 def copy(self) -> MultiDict[K, V]: # type: ignore[override] 

711 """Return a shallow mutable copy of this object. 

712 

713 This returns a :class:`MultiDict` representing the data at the 

714 time of copying. The copy will no longer reflect changes to the 

715 wrapped dicts. 

716 

717 .. versionchanged:: 0.15 

718 Return a mutable :class:`MultiDict`. 

719 """ 

720 return MultiDict(self) 

721 

722 def __len__(self) -> int: 

723 return len(self._keys_impl()) 

724 

725 def __contains__(self, key: K) -> bool: # type: ignore[override] 

726 for d in self.dicts: 

727 if key in d: 

728 return True 

729 return False 

730 

731 def __repr__(self) -> str: 

732 return f"{type(self).__name__}({self.dicts!r})" 

733 

734 

735class _ImmutableDict(_ImmutableDictMixin[K, V], dict[K, V]): # type: ignore[misc] 

736 """An immutable :class:`dict`. 

737 

738 .. deprecated:: 3.2 

739 Will be removed in Werkzeug 4.0. Use ``collections.abc.Mapping`` 

740 instead. 

741 

742 .. versionadded:: 0.5 

743 """ 

744 

745 def __repr__(self) -> str: 

746 return f"{type(self).__name__}({dict.__repr__(self)})" 

747 

748 def copy(self) -> dict[K, V]: 

749 """Return a shallow mutable copy of this object. Keep in mind that 

750 the standard library's :func:`copy` function is a no-op for this class 

751 like for any other python immutable type (eg: :class:`tuple`). 

752 """ 

753 return dict(self) 

754 

755 def __copy__(self) -> t.Self: 

756 return self 

757 

758 

759class ImmutableMultiDict(ImmutableMultiDictMixin[K, V], MultiDict[K, V]): # type: ignore[misc] 

760 """An immutable :class:`MultiDict`. 

761 

762 .. versionadded:: 0.5 

763 """ 

764 

765 def copy(self) -> MultiDict[K, V]: # type: ignore[override] 

766 """Return a shallow mutable copy of this object. Keep in mind that 

767 the standard library's :func:`copy` function is a no-op for this class 

768 like for any other python immutable type (eg: :class:`tuple`). 

769 """ 

770 return MultiDict(self) 

771 

772 def __copy__(self) -> t.Self: 

773 return self 

774 

775 

776class CallbackDict(dict[K, V]): 

777 """A dict that calls a function every time it is mutated. 

778 

779 :param initial: Initial data. 

780 :param on_update: A function to call every time this dict is mutated. The 

781 dict is passed as the first argument. 

782 """ 

783 

784 def __init__( 

785 self: t.Self, 

786 initial: cabc.Mapping[K, V] | cabc.Iterable[tuple[K, V]] | None = None, 

787 /, 

788 on_update: cabc.Callable[[t.Self], None] | None = None, 

789 ) -> None: 

790 if initial is None: 

791 super().__init__() 

792 else: 

793 super().__init__(initial) 

794 

795 self.on_update = on_update 

796 

797 @property 

798 def _on_update(self) -> cabc.Callable[[t.Self], None] | None: 

799 # compatibility with header datastructures 

800 return self.on_update 

801 

802 @_on_update.setter 

803 def _on_update(self, value: cabc.Callable[[t.Self], None] | None) -> None: 

804 self.on_update = value 

805 

806 def __repr__(self) -> str: 

807 return f"<{type(self).__name__} {super().__repr__()}>" 

808 

809 def _trigger_on_update(self: t.Self) -> None: 

810 if self.on_update is not None: 

811 self.on_update(self) 

812 

813 def setdefault( 

814 self, 

815 key: K, 

816 default: V = None, # type: ignore[assignment] 

817 /, 

818 ) -> V: 

819 modified = key not in self 

820 rv = super().setdefault(key, default) 

821 

822 if modified: 

823 self._trigger_on_update() 

824 

825 return rv 

826 

827 @t.overload 

828 def pop(self, key: K, /) -> V: ... 

829 @t.overload 

830 def pop(self, key: K, default: V, /) -> V: ... 

831 @t.overload 

832 def pop(self, key: K, default: T, /) -> T: ... 

833 def pop( 

834 self: t.Self, 

835 key: K, 

836 default: V | T = _missing, # type: ignore[assignment] 

837 /, 

838 ) -> V | T: 

839 modified = key in self 

840 

841 if default is _missing: 

842 rv: V | T = super().pop(key) 

843 else: 

844 rv = super().pop(key, default) 

845 

846 if modified: 

847 self._trigger_on_update() 

848 

849 return rv 

850 

851 def __setitem__(self, key: K, value: V) -> None: 

852 super().__setitem__(key, value) 

853 self._trigger_on_update() 

854 

855 def __delitem__(self, key: K) -> None: 

856 super().__delitem__(key) 

857 self._trigger_on_update() 

858 

859 def clear(self) -> None: 

860 super().clear() 

861 self._trigger_on_update() 

862 

863 def popitem(self) -> tuple[K, V]: 

864 rv = super().popitem() 

865 self._trigger_on_update() 

866 return rv 

867 

868 def update( # type: ignore[override] 

869 self, 

870 arg: cabc.Mapping[K, V] | cabc.Iterable[tuple[K, V]] | None = None, 

871 /, 

872 **kwargs: V, 

873 ) -> None: 

874 if arg is None: 

875 super().update(**kwargs) # type: ignore[call-overload] 

876 else: 

877 super().update(arg, **kwargs) 

878 

879 self._trigger_on_update() 

880 

881 def __ior__( # type: ignore[override, misc] 

882 self, other: cabc.Mapping[K, V] | cabc.Iterable[tuple[K, V]] 

883 ) -> t.Self: 

884 rv = super().__ior__(other) 

885 self._trigger_on_update() 

886 return rv 

887 

888 

889if not t.TYPE_CHECKING: 

890 

891 def __getattr__(name: str) -> t.Any: 

892 if name == "HeaderSet": 

893 import warnings 

894 

895 from .set import HeaderSet 

896 

897 warnings.warn( 

898 "'structures.HeaderSet' has moved to 'set.HeaderSet'. The old" 

899 " location is deprecated and will be removed in Werkzeug 4.0.", 

900 DeprecationWarning, 

901 stacklevel=2, 

902 ) 

903 return HeaderSet 

904 

905 alts = { 

906 "ImmutableList": "collections.abc.Sequence", 

907 "ImmutableDict": "collections.abc.Mapping", 

908 "ImmutableTypeConversionDict": "ImmutableMultiDict", 

909 "TypeConversionDict": "MultiDict", 

910 } 

911 

912 if name in alts: 

913 import warnings 

914 

915 warnings.warn( 

916 f"The '{name}' class is deprecated and will be removed in" 

917 f" Werkzeug 4.0. Use '{alts[name]}' instead.", 

918 DeprecationWarning, 

919 stacklevel=2, 

920 ) 

921 return globals()[f"_{name}"] 

922 

923 raise AttributeError(name)