Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/werkzeug/datastructures.py: 31%

1447 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:35 +0000

1import base64 

2import codecs 

3import mimetypes 

4import os 

5import re 

6from collections.abc import Collection 

7from collections.abc import MutableSet 

8from copy import deepcopy 

9from io import BytesIO 

10from itertools import repeat 

11from os import fspath 

12 

13from . import exceptions 

14from ._internal import _missing 

15 

16 

17def is_immutable(self): 

18 raise TypeError(f"{type(self).__name__!r} objects are immutable") 

19 

20 

21def iter_multi_items(mapping): 

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

23 without dropping any from more complex structures. 

24 """ 

25 if isinstance(mapping, MultiDict): 

26 yield from mapping.items(multi=True) 

27 elif isinstance(mapping, dict): 

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

29 if isinstance(value, (tuple, list)): 

30 for v in value: 

31 yield key, v 

32 else: 

33 yield key, value 

34 else: 

35 yield from mapping 

36 

37 

38class ImmutableListMixin: 

39 """Makes a :class:`list` immutable. 

40 

41 .. versionadded:: 0.5 

42 

43 :private: 

44 """ 

45 

46 _hash_cache = None 

47 

48 def __hash__(self): 

49 if self._hash_cache is not None: 

50 return self._hash_cache 

51 rv = self._hash_cache = hash(tuple(self)) 

52 return rv 

53 

54 def __reduce_ex__(self, protocol): 

55 return type(self), (list(self),) 

56 

57 def __delitem__(self, key): 

58 is_immutable(self) 

59 

60 def __iadd__(self, other): 

61 is_immutable(self) 

62 

63 def __imul__(self, other): 

64 is_immutable(self) 

65 

66 def __setitem__(self, key, value): 

67 is_immutable(self) 

68 

69 def append(self, item): 

70 is_immutable(self) 

71 

72 def remove(self, item): 

73 is_immutable(self) 

74 

75 def extend(self, iterable): 

76 is_immutable(self) 

77 

78 def insert(self, pos, value): 

79 is_immutable(self) 

80 

81 def pop(self, index=-1): 

82 is_immutable(self) 

83 

84 def reverse(self): 

85 is_immutable(self) 

86 

87 def sort(self, key=None, reverse=False): 

88 is_immutable(self) 

89 

90 

91class ImmutableList(ImmutableListMixin, list): 

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

93 

94 .. versionadded:: 0.5 

95 

96 :private: 

97 """ 

98 

99 def __repr__(self): 

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

101 

102 

103class ImmutableDictMixin: 

104 """Makes a :class:`dict` immutable. 

105 

106 .. versionadded:: 0.5 

107 

108 :private: 

109 """ 

110 

111 _hash_cache = None 

112 

113 @classmethod 

114 def fromkeys(cls, keys, value=None): 

115 instance = super().__new__(cls) 

116 instance.__init__(zip(keys, repeat(value))) 

117 return instance 

118 

119 def __reduce_ex__(self, protocol): 

120 return type(self), (dict(self),) 

121 

122 def _iter_hashitems(self): 

123 return self.items() 

124 

125 def __hash__(self): 

126 if self._hash_cache is not None: 

127 return self._hash_cache 

128 rv = self._hash_cache = hash(frozenset(self._iter_hashitems())) 

129 return rv 

130 

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

132 is_immutable(self) 

133 

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

135 is_immutable(self) 

136 

137 def pop(self, key, default=None): 

138 is_immutable(self) 

139 

140 def popitem(self): 

141 is_immutable(self) 

142 

143 def __setitem__(self, key, value): 

144 is_immutable(self) 

145 

146 def __delitem__(self, key): 

147 is_immutable(self) 

148 

149 def clear(self): 

150 is_immutable(self) 

151 

152 

153class ImmutableMultiDictMixin(ImmutableDictMixin): 

154 """Makes a :class:`MultiDict` immutable. 

155 

156 .. versionadded:: 0.5 

157 

158 :private: 

159 """ 

160 

161 def __reduce_ex__(self, protocol): 

162 return type(self), (list(self.items(multi=True)),) 

163 

164 def _iter_hashitems(self): 

165 return self.items(multi=True) 

166 

167 def add(self, key, value): 

168 is_immutable(self) 

169 

170 def popitemlist(self): 

171 is_immutable(self) 

172 

173 def poplist(self, key): 

174 is_immutable(self) 

175 

176 def setlist(self, key, new_list): 

177 is_immutable(self) 

178 

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

180 is_immutable(self) 

181 

182 

183def _calls_update(name): 

184 def oncall(self, *args, **kw): 

185 rv = getattr(super(UpdateDictMixin, self), name)(*args, **kw) 

186 

187 if self.on_update is not None: 

188 self.on_update(self) 

189 

190 return rv 

191 

192 oncall.__name__ = name 

193 return oncall 

194 

195 

196class UpdateDictMixin(dict): 

197 """Makes dicts call `self.on_update` on modifications. 

198 

199 .. versionadded:: 0.5 

200 

201 :private: 

202 """ 

203 

204 on_update = None 

205 

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

207 modified = key not in self 

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

209 if modified and self.on_update is not None: 

210 self.on_update(self) 

211 return rv 

212 

213 def pop(self, key, default=_missing): 

214 modified = key in self 

215 if default is _missing: 

216 rv = super().pop(key) 

217 else: 

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

219 if modified and self.on_update is not None: 

220 self.on_update(self) 

221 return rv 

222 

223 __setitem__ = _calls_update("__setitem__") 

224 __delitem__ = _calls_update("__delitem__") 

225 clear = _calls_update("clear") 

226 popitem = _calls_update("popitem") 

227 update = _calls_update("update") 

228 

229 

230class TypeConversionDict(dict): 

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

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

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

234 

235 .. versionadded:: 0.5 

236 """ 

237 

238 def get(self, key, default=None, type=None): 

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

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

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

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

243 found: 

244 

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

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

247 42 

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

249 -1 

250 

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

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

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

254 returned. 

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

256 :class:`MultiDict`. If a :exc:`ValueError` is raised 

257 by this callable the default value is returned. 

258 """ 

259 try: 

260 rv = self[key] 

261 except KeyError: 

262 return default 

263 if type is not None: 

264 try: 

265 rv = type(rv) 

266 except ValueError: 

267 rv = default 

268 return rv 

269 

270 

271class ImmutableTypeConversionDict(ImmutableDictMixin, TypeConversionDict): 

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

273 modifications. 

274 

275 .. versionadded:: 0.5 

276 """ 

277 

278 def copy(self): 

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

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

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

282 """ 

283 return TypeConversionDict(self) 

284 

285 def __copy__(self): 

286 return self 

287 

288 

289class MultiDict(TypeConversionDict): 

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

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

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

293 elements pass multiple values for the same key. 

294 

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

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

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

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

299 explained below. 

300 

301 Basic Usage: 

302 

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

304 >>> d 

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

306 >>> d['a'] 

307 'b' 

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

309 ['b', 'c'] 

310 >>> 'a' in d 

311 True 

312 

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

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

315 

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

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

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

319 exceptions. 

320 

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

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

323 onwards some keyword parameters. 

324 

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

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

327 or `None`. 

328 """ 

329 

330 def __init__(self, mapping=None): 

331 if isinstance(mapping, MultiDict): 

332 dict.__init__(self, ((k, l[:]) for k, l in mapping.lists())) 

333 elif isinstance(mapping, dict): 

334 tmp = {} 

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

336 if isinstance(value, (tuple, list)): 

337 if len(value) == 0: 

338 continue 

339 value = list(value) 

340 else: 

341 value = [value] 

342 tmp[key] = value 

343 dict.__init__(self, tmp) 

344 else: 

345 tmp = {} 

346 for key, value in mapping or (): 

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

348 dict.__init__(self, tmp) 

349 

350 def __getstate__(self): 

351 return dict(self.lists()) 

352 

353 def __setstate__(self, value): 

354 dict.clear(self) 

355 dict.update(self, value) 

356 

357 def __iter__(self): 

358 # Work around https://bugs.python.org/issue43246. 

359 # (`return super().__iter__()` also works here, which makes this look 

360 # even more like it should be a no-op, yet it isn't.) 

361 return dict.__iter__(self) 

362 

363 def __getitem__(self, key): 

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

365 raises KeyError if not found. 

366 

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

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

369 """ 

370 

371 if key in self: 

372 lst = dict.__getitem__(self, key) 

373 if len(lst) > 0: 

374 return lst[0] 

375 raise exceptions.BadRequestKeyError(key) 

376 

377 def __setitem__(self, key, value): 

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

379 

380 :param key: the key for the value. 

381 :param value: the value to set. 

382 """ 

383 dict.__setitem__(self, key, [value]) 

384 

385 def add(self, key, value): 

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

387 

388 .. versionadded:: 0.6 

389 

390 :param key: the key for the value. 

391 :param value: the value to add. 

392 """ 

393 dict.setdefault(self, key, []).append(value) 

394 

395 def getlist(self, key, type=None): 

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

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

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

399 with the callable defined there. 

400 

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

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

403 :class:`MultiDict`. If a :exc:`ValueError` is raised 

404 by this callable the value will be removed from the list. 

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

406 """ 

407 try: 

408 rv = dict.__getitem__(self, key) 

409 except KeyError: 

410 return [] 

411 if type is None: 

412 return list(rv) 

413 result = [] 

414 for item in rv: 

415 try: 

416 result.append(type(item)) 

417 except ValueError: 

418 pass 

419 return result 

420 

421 def setlist(self, key, new_list): 

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

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

424 the dictionary. 

425 

426 >>> d = MultiDict() 

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

428 >>> d['foo'] 

429 '1' 

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

431 ['1', '2'] 

432 

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

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

435 are removed first. 

436 """ 

437 dict.__setitem__(self, key, list(new_list)) 

438 

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

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

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

442 

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

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

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

446 """ 

447 if key not in self: 

448 self[key] = default 

449 else: 

450 default = self[key] 

451 return default 

452 

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

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

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

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

457 to the list: 

458 

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

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

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

462 [1, 2, 3] 

463 

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

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

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

467 before returned. 

468 :return: a :class:`list` 

469 """ 

470 if key not in self: 

471 default_list = list(default_list or ()) 

472 dict.__setitem__(self, key, default_list) 

473 else: 

474 default_list = dict.__getitem__(self, key) 

475 return default_list 

476 

477 def items(self, multi=False): 

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

479 

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

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

482 contain pairs for the first value of each key. 

483 """ 

484 for key, values in dict.items(self): 

485 if multi: 

486 for value in values: 

487 yield key, value 

488 else: 

489 yield key, values[0] 

490 

491 def lists(self): 

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

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

494 for key, values in dict.items(self): 

495 yield key, list(values) 

496 

497 def values(self): 

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

499 for values in dict.values(self): 

500 yield values[0] 

501 

502 def listvalues(self): 

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

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

505 

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

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

508 True 

509 """ 

510 return dict.values(self) 

511 

512 def copy(self): 

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

514 return self.__class__(self) 

515 

516 def deepcopy(self, memo=None): 

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

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

519 

520 def to_dict(self, flat=True): 

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

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

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

524 

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

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

527 contain the first value for each key. 

528 :return: a :class:`dict` 

529 """ 

530 if flat: 

531 return dict(self.items()) 

532 return dict(self.lists()) 

533 

534 def update(self, mapping): 

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

536 

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

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

539 >>> a.update(b) 

540 >>> a 

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

542 

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

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

545 

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

547 >>> y = MultiDict() 

548 >>> y.update(x) 

549 >>> y 

550 MultiDict([]) 

551 """ 

552 for key, value in iter_multi_items(mapping): 

553 MultiDict.add(self, key, value) 

554 

555 def pop(self, key, default=_missing): 

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

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

558 

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

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

561 1 

562 >>> "foo" in d 

563 False 

564 

565 :param key: the key to pop. 

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

567 not in the dictionary. 

568 """ 

569 try: 

570 lst = dict.pop(self, key) 

571 

572 if len(lst) == 0: 

573 raise exceptions.BadRequestKeyError(key) 

574 

575 return lst[0] 

576 except KeyError: 

577 if default is not _missing: 

578 return default 

579 

580 raise exceptions.BadRequestKeyError(key) from None 

581 

582 def popitem(self): 

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

584 try: 

585 item = dict.popitem(self) 

586 

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

588 raise exceptions.BadRequestKeyError(item[0]) 

589 

590 return (item[0], item[1][0]) 

591 except KeyError as e: 

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

593 

594 def poplist(self, key): 

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

596 an empty list is returned. 

597 

598 .. versionchanged:: 0.5 

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

600 raising an error. 

601 """ 

602 return dict.pop(self, key, []) 

603 

604 def popitemlist(self): 

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

606 try: 

607 return dict.popitem(self) 

608 except KeyError as e: 

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

610 

611 def __copy__(self): 

612 return self.copy() 

613 

614 def __deepcopy__(self, memo): 

615 return self.deepcopy(memo=memo) 

616 

617 def __repr__(self): 

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

619 

620 

621class _omd_bucket: 

622 """Wraps values in the :class:`OrderedMultiDict`. This makes it 

623 possible to keep an order over multiple different keys. It requires 

624 a lot of extra memory and slows down access a lot, but makes it 

625 possible to access elements in O(1) and iterate in O(n). 

626 """ 

627 

628 __slots__ = ("prev", "key", "value", "next") 

629 

630 def __init__(self, omd, key, value): 

631 self.prev = omd._last_bucket 

632 self.key = key 

633 self.value = value 

634 self.next = None 

635 

636 if omd._first_bucket is None: 

637 omd._first_bucket = self 

638 if omd._last_bucket is not None: 

639 omd._last_bucket.next = self 

640 omd._last_bucket = self 

641 

642 def unlink(self, omd): 

643 if self.prev: 

644 self.prev.next = self.next 

645 if self.next: 

646 self.next.prev = self.prev 

647 if omd._first_bucket is self: 

648 omd._first_bucket = self.next 

649 if omd._last_bucket is self: 

650 omd._last_bucket = self.prev 

651 

652 

653class OrderedMultiDict(MultiDict): 

654 """Works like a regular :class:`MultiDict` but preserves the 

655 order of the fields. To convert the ordered multi dict into a 

656 list you can use the :meth:`items` method and pass it ``multi=True``. 

657 

658 In general an :class:`OrderedMultiDict` is an order of magnitude 

659 slower than a :class:`MultiDict`. 

660 

661 .. admonition:: note 

662 

663 Due to a limitation in Python you cannot convert an ordered 

664 multi dict into a regular dict by using ``dict(multidict)``. 

665 Instead you have to use the :meth:`to_dict` method, otherwise 

666 the internal bucket objects are exposed. 

667 """ 

668 

669 def __init__(self, mapping=None): 

670 dict.__init__(self) 

671 self._first_bucket = self._last_bucket = None 

672 if mapping is not None: 

673 OrderedMultiDict.update(self, mapping) 

674 

675 def __eq__(self, other): 

676 if not isinstance(other, MultiDict): 

677 return NotImplemented 

678 if isinstance(other, OrderedMultiDict): 

679 iter1 = iter(self.items(multi=True)) 

680 iter2 = iter(other.items(multi=True)) 

681 try: 

682 for k1, v1 in iter1: 

683 k2, v2 = next(iter2) 

684 if k1 != k2 or v1 != v2: 

685 return False 

686 except StopIteration: 

687 return False 

688 try: 

689 next(iter2) 

690 except StopIteration: 

691 return True 

692 return False 

693 if len(self) != len(other): 

694 return False 

695 for key, values in self.lists(): 

696 if other.getlist(key) != values: 

697 return False 

698 return True 

699 

700 __hash__ = None 

701 

702 def __reduce_ex__(self, protocol): 

703 return type(self), (list(self.items(multi=True)),) 

704 

705 def __getstate__(self): 

706 return list(self.items(multi=True)) 

707 

708 def __setstate__(self, values): 

709 dict.clear(self) 

710 for key, value in values: 

711 self.add(key, value) 

712 

713 def __getitem__(self, key): 

714 if key in self: 

715 return dict.__getitem__(self, key)[0].value 

716 raise exceptions.BadRequestKeyError(key) 

717 

718 def __setitem__(self, key, value): 

719 self.poplist(key) 

720 self.add(key, value) 

721 

722 def __delitem__(self, key): 

723 self.pop(key) 

724 

725 def keys(self): 

726 return (key for key, value in self.items()) 

727 

728 def __iter__(self): 

729 return iter(self.keys()) 

730 

731 def values(self): 

732 return (value for key, value in self.items()) 

733 

734 def items(self, multi=False): 

735 ptr = self._first_bucket 

736 if multi: 

737 while ptr is not None: 

738 yield ptr.key, ptr.value 

739 ptr = ptr.next 

740 else: 

741 returned_keys = set() 

742 while ptr is not None: 

743 if ptr.key not in returned_keys: 

744 returned_keys.add(ptr.key) 

745 yield ptr.key, ptr.value 

746 ptr = ptr.next 

747 

748 def lists(self): 

749 returned_keys = set() 

750 ptr = self._first_bucket 

751 while ptr is not None: 

752 if ptr.key not in returned_keys: 

753 yield ptr.key, self.getlist(ptr.key) 

754 returned_keys.add(ptr.key) 

755 ptr = ptr.next 

756 

757 def listvalues(self): 

758 for _key, values in self.lists(): 

759 yield values 

760 

761 def add(self, key, value): 

762 dict.setdefault(self, key, []).append(_omd_bucket(self, key, value)) 

763 

764 def getlist(self, key, type=None): 

765 try: 

766 rv = dict.__getitem__(self, key) 

767 except KeyError: 

768 return [] 

769 if type is None: 

770 return [x.value for x in rv] 

771 result = [] 

772 for item in rv: 

773 try: 

774 result.append(type(item.value)) 

775 except ValueError: 

776 pass 

777 return result 

778 

779 def setlist(self, key, new_list): 

780 self.poplist(key) 

781 for value in new_list: 

782 self.add(key, value) 

783 

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

785 raise TypeError("setlistdefault is unsupported for ordered multi dicts") 

786 

787 def update(self, mapping): 

788 for key, value in iter_multi_items(mapping): 

789 OrderedMultiDict.add(self, key, value) 

790 

791 def poplist(self, key): 

792 buckets = dict.pop(self, key, ()) 

793 for bucket in buckets: 

794 bucket.unlink(self) 

795 return [x.value for x in buckets] 

796 

797 def pop(self, key, default=_missing): 

798 try: 

799 buckets = dict.pop(self, key) 

800 except KeyError: 

801 if default is not _missing: 

802 return default 

803 

804 raise exceptions.BadRequestKeyError(key) from None 

805 

806 for bucket in buckets: 

807 bucket.unlink(self) 

808 

809 return buckets[0].value 

810 

811 def popitem(self): 

812 try: 

813 key, buckets = dict.popitem(self) 

814 except KeyError as e: 

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

816 

817 for bucket in buckets: 

818 bucket.unlink(self) 

819 

820 return key, buckets[0].value 

821 

822 def popitemlist(self): 

823 try: 

824 key, buckets = dict.popitem(self) 

825 except KeyError as e: 

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

827 

828 for bucket in buckets: 

829 bucket.unlink(self) 

830 

831 return key, [x.value for x in buckets] 

832 

833 

834def _options_header_vkw(value, kw): 

835 return http.dump_options_header( 

836 value, {k.replace("_", "-"): v for k, v in kw.items()} 

837 ) 

838 

839 

840def _unicodify_header_value(value): 

841 if isinstance(value, bytes): 

842 value = value.decode("latin-1") 

843 if not isinstance(value, str): 

844 value = str(value) 

845 return value 

846 

847 

848class Headers: 

849 """An object that stores some headers. It has a dict-like interface, 

850 but is ordered, can store the same key multiple times, and iterating 

851 yields ``(key, value)`` pairs instead of only keys. 

852 

853 This data structure is useful if you want a nicer way to handle WSGI 

854 headers which are stored as tuples in a list. 

855 

856 From Werkzeug 0.3 onwards, the :exc:`KeyError` raised by this class is 

857 also a subclass of the :class:`~exceptions.BadRequest` HTTP exception 

858 and will render a page for a ``400 BAD REQUEST`` if caught in a 

859 catch-all for HTTP exceptions. 

860 

861 Headers is mostly compatible with the Python :class:`wsgiref.headers.Headers` 

862 class, with the exception of `__getitem__`. :mod:`wsgiref` will return 

863 `None` for ``headers['missing']``, whereas :class:`Headers` will raise 

864 a :class:`KeyError`. 

865 

866 To create a new ``Headers`` object, pass it a list, dict, or 

867 other ``Headers`` object with default values. These values are 

868 validated the same way values added later are. 

869 

870 :param defaults: The list of default values for the :class:`Headers`. 

871 

872 .. versionchanged:: 2.1.0 

873 Default values are validated the same as values added later. 

874 

875 .. versionchanged:: 0.9 

876 This data structure now stores unicode values similar to how the 

877 multi dicts do it. The main difference is that bytes can be set as 

878 well which will automatically be latin1 decoded. 

879 

880 .. versionchanged:: 0.9 

881 The :meth:`linked` function was removed without replacement as it 

882 was an API that does not support the changes to the encoding model. 

883 """ 

884 

885 def __init__(self, defaults=None): 

886 self._list = [] 

887 if defaults is not None: 

888 self.extend(defaults) 

889 

890 def __getitem__(self, key, _get_mode=False): 

891 if not _get_mode: 

892 if isinstance(key, int): 

893 return self._list[key] 

894 elif isinstance(key, slice): 

895 return self.__class__(self._list[key]) 

896 if not isinstance(key, str): 

897 raise exceptions.BadRequestKeyError(key) 

898 ikey = key.lower() 

899 for k, v in self._list: 

900 if k.lower() == ikey: 

901 return v 

902 # micro optimization: if we are in get mode we will catch that 

903 # exception one stack level down so we can raise a standard 

904 # key error instead of our special one. 

905 if _get_mode: 

906 raise KeyError() 

907 raise exceptions.BadRequestKeyError(key) 

908 

909 def __eq__(self, other): 

910 def lowered(item): 

911 return (item[0].lower(),) + item[1:] 

912 

913 return other.__class__ is self.__class__ and set( 

914 map(lowered, other._list) 

915 ) == set(map(lowered, self._list)) 

916 

917 __hash__ = None 

918 

919 def get(self, key, default=None, type=None, as_bytes=False): 

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

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

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

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

924 found: 

925 

926 >>> d = Headers([('Content-Length', '42')]) 

927 >>> d.get('Content-Length', type=int) 

928 42 

929 

930 .. versionadded:: 0.9 

931 Added support for `as_bytes`. 

932 

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

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

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

936 returned. 

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

938 :class:`Headers`. If a :exc:`ValueError` is raised 

939 by this callable the default value is returned. 

940 :param as_bytes: return bytes instead of strings. 

941 """ 

942 try: 

943 rv = self.__getitem__(key, _get_mode=True) 

944 except KeyError: 

945 return default 

946 if as_bytes: 

947 rv = rv.encode("latin1") 

948 if type is None: 

949 return rv 

950 try: 

951 return type(rv) 

952 except ValueError: 

953 return default 

954 

955 def getlist(self, key, type=None, as_bytes=False): 

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

957 :class:`Headers`, the return value will be an empty list. Just like 

958 :meth:`get`, :meth:`getlist` accepts a `type` parameter. All items will 

959 be converted with the callable defined there. 

960 

961 .. versionadded:: 0.9 

962 Added support for `as_bytes`. 

963 

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

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

966 :class:`Headers`. If a :exc:`ValueError` is raised 

967 by this callable the value will be removed from the list. 

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

969 :param as_bytes: return bytes instead of strings. 

970 """ 

971 ikey = key.lower() 

972 result = [] 

973 for k, v in self: 

974 if k.lower() == ikey: 

975 if as_bytes: 

976 v = v.encode("latin1") 

977 if type is not None: 

978 try: 

979 v = type(v) 

980 except ValueError: 

981 continue 

982 result.append(v) 

983 return result 

984 

985 def get_all(self, name): 

986 """Return a list of all the values for the named field. 

987 

988 This method is compatible with the :mod:`wsgiref` 

989 :meth:`~wsgiref.headers.Headers.get_all` method. 

990 """ 

991 return self.getlist(name) 

992 

993 def items(self, lower=False): 

994 for key, value in self: 

995 if lower: 

996 key = key.lower() 

997 yield key, value 

998 

999 def keys(self, lower=False): 

1000 for key, _ in self.items(lower): 

1001 yield key 

1002 

1003 def values(self): 

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

1005 yield value 

1006 

1007 def extend(self, *args, **kwargs): 

1008 """Extend headers in this object with items from another object 

1009 containing header items as well as keyword arguments. 

1010 

1011 To replace existing keys instead of extending, use 

1012 :meth:`update` instead. 

1013 

1014 If provided, the first argument can be another :class:`Headers` 

1015 object, a :class:`MultiDict`, :class:`dict`, or iterable of 

1016 pairs. 

1017 

1018 .. versionchanged:: 1.0 

1019 Support :class:`MultiDict`. Allow passing ``kwargs``. 

1020 """ 

1021 if len(args) > 1: 

1022 raise TypeError(f"update expected at most 1 arguments, got {len(args)}") 

1023 

1024 if args: 

1025 for key, value in iter_multi_items(args[0]): 

1026 self.add(key, value) 

1027 

1028 for key, value in iter_multi_items(kwargs): 

1029 self.add(key, value) 

1030 

1031 def __delitem__(self, key, _index_operation=True): 

1032 if _index_operation and isinstance(key, (int, slice)): 

1033 del self._list[key] 

1034 return 

1035 key = key.lower() 

1036 new = [] 

1037 for k, v in self._list: 

1038 if k.lower() != key: 

1039 new.append((k, v)) 

1040 self._list[:] = new 

1041 

1042 def remove(self, key): 

1043 """Remove a key. 

1044 

1045 :param key: The key to be removed. 

1046 """ 

1047 return self.__delitem__(key, _index_operation=False) 

1048 

1049 def pop(self, key=None, default=_missing): 

1050 """Removes and returns a key or index. 

1051 

1052 :param key: The key to be popped. If this is an integer the item at 

1053 that position is removed, if it's a string the value for 

1054 that key is. If the key is omitted or `None` the last 

1055 item is removed. 

1056 :return: an item. 

1057 """ 

1058 if key is None: 

1059 return self._list.pop() 

1060 if isinstance(key, int): 

1061 return self._list.pop(key) 

1062 try: 

1063 rv = self[key] 

1064 self.remove(key) 

1065 except KeyError: 

1066 if default is not _missing: 

1067 return default 

1068 raise 

1069 return rv 

1070 

1071 def popitem(self): 

1072 """Removes a key or index and returns a (key, value) item.""" 

1073 return self.pop() 

1074 

1075 def __contains__(self, key): 

1076 """Check if a key is present.""" 

1077 try: 

1078 self.__getitem__(key, _get_mode=True) 

1079 except KeyError: 

1080 return False 

1081 return True 

1082 

1083 def __iter__(self): 

1084 """Yield ``(key, value)`` tuples.""" 

1085 return iter(self._list) 

1086 

1087 def __len__(self): 

1088 return len(self._list) 

1089 

1090 def add(self, _key, _value, **kw): 

1091 """Add a new header tuple to the list. 

1092 

1093 Keyword arguments can specify additional parameters for the header 

1094 value, with underscores converted to dashes:: 

1095 

1096 >>> d = Headers() 

1097 >>> d.add('Content-Type', 'text/plain') 

1098 >>> d.add('Content-Disposition', 'attachment', filename='foo.png') 

1099 

1100 The keyword argument dumping uses :func:`dump_options_header` 

1101 behind the scenes. 

1102 

1103 .. versionadded:: 0.4.1 

1104 keyword arguments were added for :mod:`wsgiref` compatibility. 

1105 """ 

1106 if kw: 

1107 _value = _options_header_vkw(_value, kw) 

1108 _key = _unicodify_header_value(_key) 

1109 _value = _unicodify_header_value(_value) 

1110 self._validate_value(_value) 

1111 self._list.append((_key, _value)) 

1112 

1113 def _validate_value(self, value): 

1114 if not isinstance(value, str): 

1115 raise TypeError("Value should be a string.") 

1116 if "\n" in value or "\r" in value: 

1117 raise ValueError( 

1118 "Detected newline in header value. This is " 

1119 "a potential security problem" 

1120 ) 

1121 

1122 def add_header(self, _key, _value, **_kw): 

1123 """Add a new header tuple to the list. 

1124 

1125 An alias for :meth:`add` for compatibility with the :mod:`wsgiref` 

1126 :meth:`~wsgiref.headers.Headers.add_header` method. 

1127 """ 

1128 self.add(_key, _value, **_kw) 

1129 

1130 def clear(self): 

1131 """Clears all headers.""" 

1132 del self._list[:] 

1133 

1134 def set(self, _key, _value, **kw): 

1135 """Remove all header tuples for `key` and add a new one. The newly 

1136 added key either appears at the end of the list if there was no 

1137 entry or replaces the first one. 

1138 

1139 Keyword arguments can specify additional parameters for the header 

1140 value, with underscores converted to dashes. See :meth:`add` for 

1141 more information. 

1142 

1143 .. versionchanged:: 0.6.1 

1144 :meth:`set` now accepts the same arguments as :meth:`add`. 

1145 

1146 :param key: The key to be inserted. 

1147 :param value: The value to be inserted. 

1148 """ 

1149 if kw: 

1150 _value = _options_header_vkw(_value, kw) 

1151 _key = _unicodify_header_value(_key) 

1152 _value = _unicodify_header_value(_value) 

1153 self._validate_value(_value) 

1154 if not self._list: 

1155 self._list.append((_key, _value)) 

1156 return 

1157 listiter = iter(self._list) 

1158 ikey = _key.lower() 

1159 for idx, (old_key, _old_value) in enumerate(listiter): 

1160 if old_key.lower() == ikey: 

1161 # replace first occurrence 

1162 self._list[idx] = (_key, _value) 

1163 break 

1164 else: 

1165 self._list.append((_key, _value)) 

1166 return 

1167 self._list[idx + 1 :] = [t for t in listiter if t[0].lower() != ikey] 

1168 

1169 def setlist(self, key, values): 

1170 """Remove any existing values for a header and add new ones. 

1171 

1172 :param key: The header key to set. 

1173 :param values: An iterable of values to set for the key. 

1174 

1175 .. versionadded:: 1.0 

1176 """ 

1177 if values: 

1178 values_iter = iter(values) 

1179 self.set(key, next(values_iter)) 

1180 

1181 for value in values_iter: 

1182 self.add(key, value) 

1183 else: 

1184 self.remove(key) 

1185 

1186 def setdefault(self, key, default): 

1187 """Return the first value for the key if it is in the headers, 

1188 otherwise set the header to the value given by ``default`` and 

1189 return that. 

1190 

1191 :param key: The header key to get. 

1192 :param default: The value to set for the key if it is not in the 

1193 headers. 

1194 """ 

1195 if key in self: 

1196 return self[key] 

1197 

1198 self.set(key, default) 

1199 return default 

1200 

1201 def setlistdefault(self, key, default): 

1202 """Return the list of values for the key if it is in the 

1203 headers, otherwise set the header to the list of values given 

1204 by ``default`` and return that. 

1205 

1206 Unlike :meth:`MultiDict.setlistdefault`, modifying the returned 

1207 list will not affect the headers. 

1208 

1209 :param key: The header key to get. 

1210 :param default: An iterable of values to set for the key if it 

1211 is not in the headers. 

1212 

1213 .. versionadded:: 1.0 

1214 """ 

1215 if key not in self: 

1216 self.setlist(key, default) 

1217 

1218 return self.getlist(key) 

1219 

1220 def __setitem__(self, key, value): 

1221 """Like :meth:`set` but also supports index/slice based setting.""" 

1222 if isinstance(key, (slice, int)): 

1223 if isinstance(key, int): 

1224 value = [value] 

1225 value = [ 

1226 (_unicodify_header_value(k), _unicodify_header_value(v)) 

1227 for (k, v) in value 

1228 ] 

1229 for _, v in value: 

1230 self._validate_value(v) 

1231 if isinstance(key, int): 

1232 self._list[key] = value[0] 

1233 else: 

1234 self._list[key] = value 

1235 else: 

1236 self.set(key, value) 

1237 

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

1239 """Replace headers in this object with items from another 

1240 headers object and keyword arguments. 

1241 

1242 To extend existing keys instead of replacing, use :meth:`extend` 

1243 instead. 

1244 

1245 If provided, the first argument can be another :class:`Headers` 

1246 object, a :class:`MultiDict`, :class:`dict`, or iterable of 

1247 pairs. 

1248 

1249 .. versionadded:: 1.0 

1250 """ 

1251 if len(args) > 1: 

1252 raise TypeError(f"update expected at most 1 arguments, got {len(args)}") 

1253 

1254 if args: 

1255 mapping = args[0] 

1256 

1257 if isinstance(mapping, (Headers, MultiDict)): 

1258 for key in mapping.keys(): 

1259 self.setlist(key, mapping.getlist(key)) 

1260 elif isinstance(mapping, dict): 

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

1262 if isinstance(value, (list, tuple)): 

1263 self.setlist(key, value) 

1264 else: 

1265 self.set(key, value) 

1266 else: 

1267 for key, value in mapping: 

1268 self.set(key, value) 

1269 

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

1271 if isinstance(value, (list, tuple)): 

1272 self.setlist(key, value) 

1273 else: 

1274 self.set(key, value) 

1275 

1276 def to_wsgi_list(self): 

1277 """Convert the headers into a list suitable for WSGI. 

1278 

1279 :return: list 

1280 """ 

1281 return list(self) 

1282 

1283 def copy(self): 

1284 return self.__class__(self._list) 

1285 

1286 def __copy__(self): 

1287 return self.copy() 

1288 

1289 def __str__(self): 

1290 """Returns formatted headers suitable for HTTP transmission.""" 

1291 strs = [] 

1292 for key, value in self.to_wsgi_list(): 

1293 strs.append(f"{key}: {value}") 

1294 strs.append("\r\n") 

1295 return "\r\n".join(strs) 

1296 

1297 def __repr__(self): 

1298 return f"{type(self).__name__}({list(self)!r})" 

1299 

1300 

1301class ImmutableHeadersMixin: 

1302 """Makes a :class:`Headers` immutable. We do not mark them as 

1303 hashable though since the only usecase for this datastructure 

1304 in Werkzeug is a view on a mutable structure. 

1305 

1306 .. versionadded:: 0.5 

1307 

1308 :private: 

1309 """ 

1310 

1311 def __delitem__(self, key, **kwargs): 

1312 is_immutable(self) 

1313 

1314 def __setitem__(self, key, value): 

1315 is_immutable(self) 

1316 

1317 def set(self, _key, _value, **kw): 

1318 is_immutable(self) 

1319 

1320 def setlist(self, key, values): 

1321 is_immutable(self) 

1322 

1323 def add(self, _key, _value, **kw): 

1324 is_immutable(self) 

1325 

1326 def add_header(self, _key, _value, **_kw): 

1327 is_immutable(self) 

1328 

1329 def remove(self, key): 

1330 is_immutable(self) 

1331 

1332 def extend(self, *args, **kwargs): 

1333 is_immutable(self) 

1334 

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

1336 is_immutable(self) 

1337 

1338 def insert(self, pos, value): 

1339 is_immutable(self) 

1340 

1341 def pop(self, key=None, default=_missing): 

1342 is_immutable(self) 

1343 

1344 def popitem(self): 

1345 is_immutable(self) 

1346 

1347 def setdefault(self, key, default): 

1348 is_immutable(self) 

1349 

1350 def setlistdefault(self, key, default): 

1351 is_immutable(self) 

1352 

1353 

1354class EnvironHeaders(ImmutableHeadersMixin, Headers): 

1355 """Read only version of the headers from a WSGI environment. This 

1356 provides the same interface as `Headers` and is constructed from 

1357 a WSGI environment. 

1358 

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

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

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

1362 HTTP exceptions. 

1363 """ 

1364 

1365 def __init__(self, environ): 

1366 self.environ = environ 

1367 

1368 def __eq__(self, other): 

1369 return self.environ is other.environ 

1370 

1371 __hash__ = None 

1372 

1373 def __getitem__(self, key, _get_mode=False): 

1374 # _get_mode is a no-op for this class as there is no index but 

1375 # used because get() calls it. 

1376 if not isinstance(key, str): 

1377 raise KeyError(key) 

1378 key = key.upper().replace("-", "_") 

1379 if key in ("CONTENT_TYPE", "CONTENT_LENGTH"): 

1380 return _unicodify_header_value(self.environ[key]) 

1381 return _unicodify_header_value(self.environ[f"HTTP_{key}"]) 

1382 

1383 def __len__(self): 

1384 # the iter is necessary because otherwise list calls our 

1385 # len which would call list again and so forth. 

1386 return len(list(iter(self))) 

1387 

1388 def __iter__(self): 

1389 for key, value in self.environ.items(): 

1390 if key.startswith("HTTP_") and key not in ( 

1391 "HTTP_CONTENT_TYPE", 

1392 "HTTP_CONTENT_LENGTH", 

1393 ): 

1394 yield ( 

1395 key[5:].replace("_", "-").title(), 

1396 _unicodify_header_value(value), 

1397 ) 

1398 elif key in ("CONTENT_TYPE", "CONTENT_LENGTH") and value: 

1399 yield (key.replace("_", "-").title(), _unicodify_header_value(value)) 

1400 

1401 def copy(self): 

1402 raise TypeError(f"cannot create {type(self).__name__!r} copies") 

1403 

1404 

1405class CombinedMultiDict(ImmutableMultiDictMixin, MultiDict): 

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

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

1408 dicts: 

1409 

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

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

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

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

1414 >>> combined['foo'] 

1415 'bar' 

1416 >>> combined['blub'] 

1417 'blah' 

1418 

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

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

1421 

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

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

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

1425 exceptions. 

1426 """ 

1427 

1428 def __reduce_ex__(self, protocol): 

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

1430 

1431 def __init__(self, dicts=None): 

1432 self.dicts = list(dicts) or [] 

1433 

1434 @classmethod 

1435 def fromkeys(cls, keys, value=None): 

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

1437 

1438 def __getitem__(self, key): 

1439 for d in self.dicts: 

1440 if key in d: 

1441 return d[key] 

1442 raise exceptions.BadRequestKeyError(key) 

1443 

1444 def get(self, key, default=None, type=None): 

1445 for d in self.dicts: 

1446 if key in d: 

1447 if type is not None: 

1448 try: 

1449 return type(d[key]) 

1450 except ValueError: 

1451 continue 

1452 return d[key] 

1453 return default 

1454 

1455 def getlist(self, key, type=None): 

1456 rv = [] 

1457 for d in self.dicts: 

1458 rv.extend(d.getlist(key, type)) 

1459 return rv 

1460 

1461 def _keys_impl(self): 

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

1463 saving one list creation from an iterator. 

1464 """ 

1465 rv = set() 

1466 rv.update(*self.dicts) 

1467 return rv 

1468 

1469 def keys(self): 

1470 return self._keys_impl() 

1471 

1472 def __iter__(self): 

1473 return iter(self.keys()) 

1474 

1475 def items(self, multi=False): 

1476 found = set() 

1477 for d in self.dicts: 

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

1479 if multi: 

1480 yield key, value 

1481 elif key not in found: 

1482 found.add(key) 

1483 yield key, value 

1484 

1485 def values(self): 

1486 for _key, value in self.items(): 

1487 yield value 

1488 

1489 def lists(self): 

1490 rv = {} 

1491 for d in self.dicts: 

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

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

1494 return list(rv.items()) 

1495 

1496 def listvalues(self): 

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

1498 

1499 def copy(self): 

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

1501 

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

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

1504 wrapped dicts. 

1505 

1506 .. versionchanged:: 0.15 

1507 Return a mutable :class:`MultiDict`. 

1508 """ 

1509 return MultiDict(self) 

1510 

1511 def to_dict(self, flat=True): 

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

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

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

1515 

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

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

1518 contain the first item for each key. 

1519 :return: a :class:`dict` 

1520 """ 

1521 if flat: 

1522 return dict(self.items()) 

1523 

1524 return dict(self.lists()) 

1525 

1526 def __len__(self): 

1527 return len(self._keys_impl()) 

1528 

1529 def __contains__(self, key): 

1530 for d in self.dicts: 

1531 if key in d: 

1532 return True 

1533 return False 

1534 

1535 def __repr__(self): 

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

1537 

1538 

1539class FileMultiDict(MultiDict): 

1540 """A special :class:`MultiDict` that has convenience methods to add 

1541 files to it. This is used for :class:`EnvironBuilder` and generally 

1542 useful for unittesting. 

1543 

1544 .. versionadded:: 0.5 

1545 """ 

1546 

1547 def add_file(self, name, file, filename=None, content_type=None): 

1548 """Adds a new file to the dict. `file` can be a file name or 

1549 a :class:`file`-like or a :class:`FileStorage` object. 

1550 

1551 :param name: the name of the field. 

1552 :param file: a filename or :class:`file`-like object 

1553 :param filename: an optional filename 

1554 :param content_type: an optional content type 

1555 """ 

1556 if isinstance(file, FileStorage): 

1557 value = file 

1558 else: 

1559 if isinstance(file, str): 

1560 if filename is None: 

1561 filename = file 

1562 file = open(file, "rb") 

1563 if filename and content_type is None: 

1564 content_type = ( 

1565 mimetypes.guess_type(filename)[0] or "application/octet-stream" 

1566 ) 

1567 value = FileStorage(file, filename, name, content_type) 

1568 

1569 self.add(name, value) 

1570 

1571 

1572class ImmutableDict(ImmutableDictMixin, dict): 

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

1574 

1575 .. versionadded:: 0.5 

1576 """ 

1577 

1578 def __repr__(self): 

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

1580 

1581 def copy(self): 

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

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

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

1585 """ 

1586 return dict(self) 

1587 

1588 def __copy__(self): 

1589 return self 

1590 

1591 

1592class ImmutableMultiDict(ImmutableMultiDictMixin, MultiDict): 

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

1594 

1595 .. versionadded:: 0.5 

1596 """ 

1597 

1598 def copy(self): 

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

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

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

1602 """ 

1603 return MultiDict(self) 

1604 

1605 def __copy__(self): 

1606 return self 

1607 

1608 

1609class ImmutableOrderedMultiDict(ImmutableMultiDictMixin, OrderedMultiDict): 

1610 """An immutable :class:`OrderedMultiDict`. 

1611 

1612 .. versionadded:: 0.6 

1613 """ 

1614 

1615 def _iter_hashitems(self): 

1616 return enumerate(self.items(multi=True)) 

1617 

1618 def copy(self): 

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

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

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

1622 """ 

1623 return OrderedMultiDict(self) 

1624 

1625 def __copy__(self): 

1626 return self 

1627 

1628 

1629class Accept(ImmutableList): 

1630 """An :class:`Accept` object is just a list subclass for lists of 

1631 ``(value, quality)`` tuples. It is automatically sorted by specificity 

1632 and quality. 

1633 

1634 All :class:`Accept` objects work similar to a list but provide extra 

1635 functionality for working with the data. Containment checks are 

1636 normalized to the rules of that header: 

1637 

1638 >>> a = CharsetAccept([('ISO-8859-1', 1), ('utf-8', 0.7)]) 

1639 >>> a.best 

1640 'ISO-8859-1' 

1641 >>> 'iso-8859-1' in a 

1642 True 

1643 >>> 'UTF8' in a 

1644 True 

1645 >>> 'utf7' in a 

1646 False 

1647 

1648 To get the quality for an item you can use normal item lookup: 

1649 

1650 >>> print a['utf-8'] 

1651 0.7 

1652 >>> a['utf7'] 

1653 0 

1654 

1655 .. versionchanged:: 0.5 

1656 :class:`Accept` objects are forced immutable now. 

1657 

1658 .. versionchanged:: 1.0.0 

1659 :class:`Accept` internal values are no longer ordered 

1660 alphabetically for equal quality tags. Instead the initial 

1661 order is preserved. 

1662 

1663 """ 

1664 

1665 def __init__(self, values=()): 

1666 if values is None: 

1667 list.__init__(self) 

1668 self.provided = False 

1669 elif isinstance(values, Accept): 

1670 self.provided = values.provided 

1671 list.__init__(self, values) 

1672 else: 

1673 self.provided = True 

1674 values = sorted( 

1675 values, key=lambda x: (self._specificity(x[0]), x[1]), reverse=True 

1676 ) 

1677 list.__init__(self, values) 

1678 

1679 def _specificity(self, value): 

1680 """Returns a tuple describing the value's specificity.""" 

1681 return (value != "*",) 

1682 

1683 def _value_matches(self, value, item): 

1684 """Check if a value matches a given accept item.""" 

1685 return item == "*" or item.lower() == value.lower() 

1686 

1687 def __getitem__(self, key): 

1688 """Besides index lookup (getting item n) you can also pass it a string 

1689 to get the quality for the item. If the item is not in the list, the 

1690 returned quality is ``0``. 

1691 """ 

1692 if isinstance(key, str): 

1693 return self.quality(key) 

1694 return list.__getitem__(self, key) 

1695 

1696 def quality(self, key): 

1697 """Returns the quality of the key. 

1698 

1699 .. versionadded:: 0.6 

1700 In previous versions you had to use the item-lookup syntax 

1701 (eg: ``obj[key]`` instead of ``obj.quality(key)``) 

1702 """ 

1703 for item, quality in self: 

1704 if self._value_matches(key, item): 

1705 return quality 

1706 return 0 

1707 

1708 def __contains__(self, value): 

1709 for item, _quality in self: 

1710 if self._value_matches(value, item): 

1711 return True 

1712 return False 

1713 

1714 def __repr__(self): 

1715 pairs_str = ", ".join(f"({x!r}, {y})" for x, y in self) 

1716 return f"{type(self).__name__}([{pairs_str}])" 

1717 

1718 def index(self, key): 

1719 """Get the position of an entry or raise :exc:`ValueError`. 

1720 

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

1722 

1723 .. versionchanged:: 0.5 

1724 This used to raise :exc:`IndexError`, which was inconsistent 

1725 with the list API. 

1726 """ 

1727 if isinstance(key, str): 

1728 for idx, (item, _quality) in enumerate(self): 

1729 if self._value_matches(key, item): 

1730 return idx 

1731 raise ValueError(key) 

1732 return list.index(self, key) 

1733 

1734 def find(self, key): 

1735 """Get the position of an entry or return -1. 

1736 

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

1738 """ 

1739 try: 

1740 return self.index(key) 

1741 except ValueError: 

1742 return -1 

1743 

1744 def values(self): 

1745 """Iterate over all values.""" 

1746 for item in self: 

1747 yield item[0] 

1748 

1749 def to_header(self): 

1750 """Convert the header set into an HTTP header string.""" 

1751 result = [] 

1752 for value, quality in self: 

1753 if quality != 1: 

1754 value = f"{value};q={quality}" 

1755 result.append(value) 

1756 return ",".join(result) 

1757 

1758 def __str__(self): 

1759 return self.to_header() 

1760 

1761 def _best_single_match(self, match): 

1762 for client_item, quality in self: 

1763 if self._value_matches(match, client_item): 

1764 # self is sorted by specificity descending, we can exit 

1765 return client_item, quality 

1766 return None 

1767 

1768 def best_match(self, matches, default=None): 

1769 """Returns the best match from a list of possible matches based 

1770 on the specificity and quality of the client. If two items have the 

1771 same quality and specificity, the one is returned that comes first. 

1772 

1773 :param matches: a list of matches to check for 

1774 :param default: the value that is returned if none match 

1775 """ 

1776 result = default 

1777 best_quality = -1 

1778 best_specificity = (-1,) 

1779 for server_item in matches: 

1780 match = self._best_single_match(server_item) 

1781 if not match: 

1782 continue 

1783 client_item, quality = match 

1784 specificity = self._specificity(client_item) 

1785 if quality <= 0 or quality < best_quality: 

1786 continue 

1787 # better quality or same quality but more specific => better match 

1788 if quality > best_quality or specificity > best_specificity: 

1789 result = server_item 

1790 best_quality = quality 

1791 best_specificity = specificity 

1792 return result 

1793 

1794 @property 

1795 def best(self): 

1796 """The best match as value.""" 

1797 if self: 

1798 return self[0][0] 

1799 

1800 

1801_mime_split_re = re.compile(r"/|(?:\s*;\s*)") 

1802 

1803 

1804def _normalize_mime(value): 

1805 return _mime_split_re.split(value.lower()) 

1806 

1807 

1808class MIMEAccept(Accept): 

1809 """Like :class:`Accept` but with special methods and behavior for 

1810 mimetypes. 

1811 """ 

1812 

1813 def _specificity(self, value): 

1814 return tuple(x != "*" for x in _mime_split_re.split(value)) 

1815 

1816 def _value_matches(self, value, item): 

1817 # item comes from the client, can't match if it's invalid. 

1818 if "/" not in item: 

1819 return False 

1820 

1821 # value comes from the application, tell the developer when it 

1822 # doesn't look valid. 

1823 if "/" not in value: 

1824 raise ValueError(f"invalid mimetype {value!r}") 

1825 

1826 # Split the match value into type, subtype, and a sorted list of parameters. 

1827 normalized_value = _normalize_mime(value) 

1828 value_type, value_subtype = normalized_value[:2] 

1829 value_params = sorted(normalized_value[2:]) 

1830 

1831 # "*/*" is the only valid value that can start with "*". 

1832 if value_type == "*" and value_subtype != "*": 

1833 raise ValueError(f"invalid mimetype {value!r}") 

1834 

1835 # Split the accept item into type, subtype, and parameters. 

1836 normalized_item = _normalize_mime(item) 

1837 item_type, item_subtype = normalized_item[:2] 

1838 item_params = sorted(normalized_item[2:]) 

1839 

1840 # "*/not-*" from the client is invalid, can't match. 

1841 if item_type == "*" and item_subtype != "*": 

1842 return False 

1843 

1844 return ( 

1845 (item_type == "*" and item_subtype == "*") 

1846 or (value_type == "*" and value_subtype == "*") 

1847 ) or ( 

1848 item_type == value_type 

1849 and ( 

1850 item_subtype == "*" 

1851 or value_subtype == "*" 

1852 or (item_subtype == value_subtype and item_params == value_params) 

1853 ) 

1854 ) 

1855 

1856 @property 

1857 def accept_html(self): 

1858 """True if this object accepts HTML.""" 

1859 return ( 

1860 "text/html" in self or "application/xhtml+xml" in self or self.accept_xhtml 

1861 ) 

1862 

1863 @property 

1864 def accept_xhtml(self): 

1865 """True if this object accepts XHTML.""" 

1866 return "application/xhtml+xml" in self or "application/xml" in self 

1867 

1868 @property 

1869 def accept_json(self): 

1870 """True if this object accepts JSON.""" 

1871 return "application/json" in self 

1872 

1873 

1874_locale_delim_re = re.compile(r"[_-]") 

1875 

1876 

1877def _normalize_lang(value): 

1878 """Process a language tag for matching.""" 

1879 return _locale_delim_re.split(value.lower()) 

1880 

1881 

1882class LanguageAccept(Accept): 

1883 """Like :class:`Accept` but with normalization for language tags.""" 

1884 

1885 def _value_matches(self, value, item): 

1886 return item == "*" or _normalize_lang(value) == _normalize_lang(item) 

1887 

1888 def best_match(self, matches, default=None): 

1889 """Given a list of supported values, finds the best match from 

1890 the list of accepted values. 

1891 

1892 Language tags are normalized for the purpose of matching, but 

1893 are returned unchanged. 

1894 

1895 If no exact match is found, this will fall back to matching 

1896 the first subtag (primary language only), first with the 

1897 accepted values then with the match values. This partial is not 

1898 applied to any other language subtags. 

1899 

1900 The default is returned if no exact or fallback match is found. 

1901 

1902 :param matches: A list of supported languages to find a match. 

1903 :param default: The value that is returned if none match. 

1904 """ 

1905 # Look for an exact match first. If a client accepts "en-US", 

1906 # "en-US" is a valid match at this point. 

1907 result = super().best_match(matches) 

1908 

1909 if result is not None: 

1910 return result 

1911 

1912 # Fall back to accepting primary tags. If a client accepts 

1913 # "en-US", "en" is a valid match at this point. Need to use 

1914 # re.split to account for 2 or 3 letter codes. 

1915 fallback = Accept( 

1916 [(_locale_delim_re.split(item[0], 1)[0], item[1]) for item in self] 

1917 ) 

1918 result = fallback.best_match(matches) 

1919 

1920 if result is not None: 

1921 return result 

1922 

1923 # Fall back to matching primary tags. If the client accepts 

1924 # "en", "en-US" is a valid match at this point. 

1925 fallback_matches = [_locale_delim_re.split(item, 1)[0] for item in matches] 

1926 result = super().best_match(fallback_matches) 

1927 

1928 # Return a value from the original match list. Find the first 

1929 # original value that starts with the matched primary tag. 

1930 if result is not None: 

1931 return next(item for item in matches if item.startswith(result)) 

1932 

1933 return default 

1934 

1935 

1936class CharsetAccept(Accept): 

1937 """Like :class:`Accept` but with normalization for charsets.""" 

1938 

1939 def _value_matches(self, value, item): 

1940 def _normalize(name): 

1941 try: 

1942 return codecs.lookup(name).name 

1943 except LookupError: 

1944 return name.lower() 

1945 

1946 return item == "*" or _normalize(value) == _normalize(item) 

1947 

1948 

1949def cache_control_property(key, empty, type): 

1950 """Return a new property object for a cache header. Useful if you 

1951 want to add support for a cache extension in a subclass. 

1952 

1953 .. versionchanged:: 2.0 

1954 Renamed from ``cache_property``. 

1955 """ 

1956 return property( 

1957 lambda x: x._get_cache_value(key, empty, type), 

1958 lambda x, v: x._set_cache_value(key, v, type), 

1959 lambda x: x._del_cache_value(key), 

1960 f"accessor for {key!r}", 

1961 ) 

1962 

1963 

1964class _CacheControl(UpdateDictMixin, dict): 

1965 """Subclass of a dict that stores values for a Cache-Control header. It 

1966 has accessors for all the cache-control directives specified in RFC 2616. 

1967 The class does not differentiate between request and response directives. 

1968 

1969 Because the cache-control directives in the HTTP header use dashes the 

1970 python descriptors use underscores for that. 

1971 

1972 To get a header of the :class:`CacheControl` object again you can convert 

1973 the object into a string or call the :meth:`to_header` method. If you plan 

1974 to subclass it and add your own items have a look at the sourcecode for 

1975 that class. 

1976 

1977 .. versionchanged:: 2.1.0 

1978 Setting int properties such as ``max_age`` will convert the 

1979 value to an int. 

1980 

1981 .. versionchanged:: 0.4 

1982 

1983 Setting `no_cache` or `private` to boolean `True` will set the implicit 

1984 none-value which is ``*``: 

1985 

1986 >>> cc = ResponseCacheControl() 

1987 >>> cc.no_cache = True 

1988 >>> cc 

1989 <ResponseCacheControl 'no-cache'> 

1990 >>> cc.no_cache 

1991 '*' 

1992 >>> cc.no_cache = None 

1993 >>> cc 

1994 <ResponseCacheControl ''> 

1995 

1996 In versions before 0.5 the behavior documented here affected the now 

1997 no longer existing `CacheControl` class. 

1998 """ 

1999 

2000 no_cache = cache_control_property("no-cache", "*", None) 

2001 no_store = cache_control_property("no-store", None, bool) 

2002 max_age = cache_control_property("max-age", -1, int) 

2003 no_transform = cache_control_property("no-transform", None, None) 

2004 

2005 def __init__(self, values=(), on_update=None): 

2006 dict.__init__(self, values or ()) 

2007 self.on_update = on_update 

2008 self.provided = values is not None 

2009 

2010 def _get_cache_value(self, key, empty, type): 

2011 """Used internally by the accessor properties.""" 

2012 if type is bool: 

2013 return key in self 

2014 if key in self: 

2015 value = self[key] 

2016 if value is None: 

2017 return empty 

2018 elif type is not None: 

2019 try: 

2020 value = type(value) 

2021 except ValueError: 

2022 pass 

2023 return value 

2024 return None 

2025 

2026 def _set_cache_value(self, key, value, type): 

2027 """Used internally by the accessor properties.""" 

2028 if type is bool: 

2029 if value: 

2030 self[key] = None 

2031 else: 

2032 self.pop(key, None) 

2033 else: 

2034 if value is None: 

2035 self.pop(key, None) 

2036 elif value is True: 

2037 self[key] = None 

2038 else: 

2039 if type is not None: 

2040 self[key] = type(value) 

2041 else: 

2042 self[key] = value 

2043 

2044 def _del_cache_value(self, key): 

2045 """Used internally by the accessor properties.""" 

2046 if key in self: 

2047 del self[key] 

2048 

2049 def to_header(self): 

2050 """Convert the stored values into a cache control header.""" 

2051 return http.dump_header(self) 

2052 

2053 def __str__(self): 

2054 return self.to_header() 

2055 

2056 def __repr__(self): 

2057 kv_str = " ".join(f"{k}={v!r}" for k, v in sorted(self.items())) 

2058 return f"<{type(self).__name__} {kv_str}>" 

2059 

2060 cache_property = staticmethod(cache_control_property) 

2061 

2062 

2063class RequestCacheControl(ImmutableDictMixin, _CacheControl): 

2064 """A cache control for requests. This is immutable and gives access 

2065 to all the request-relevant cache control headers. 

2066 

2067 To get a header of the :class:`RequestCacheControl` object again you can 

2068 convert the object into a string or call the :meth:`to_header` method. If 

2069 you plan to subclass it and add your own items have a look at the sourcecode 

2070 for that class. 

2071 

2072 .. versionchanged:: 2.1.0 

2073 Setting int properties such as ``max_age`` will convert the 

2074 value to an int. 

2075 

2076 .. versionadded:: 0.5 

2077 In previous versions a `CacheControl` class existed that was used 

2078 both for request and response. 

2079 """ 

2080 

2081 max_stale = cache_control_property("max-stale", "*", int) 

2082 min_fresh = cache_control_property("min-fresh", "*", int) 

2083 only_if_cached = cache_control_property("only-if-cached", None, bool) 

2084 

2085 

2086class ResponseCacheControl(_CacheControl): 

2087 """A cache control for responses. Unlike :class:`RequestCacheControl` 

2088 this is mutable and gives access to response-relevant cache control 

2089 headers. 

2090 

2091 To get a header of the :class:`ResponseCacheControl` object again you can 

2092 convert the object into a string or call the :meth:`to_header` method. If 

2093 you plan to subclass it and add your own items have a look at the sourcecode 

2094 for that class. 

2095 

2096 .. versionchanged:: 2.1.1 

2097 ``s_maxage`` converts the value to an int. 

2098 

2099 .. versionchanged:: 2.1.0 

2100 Setting int properties such as ``max_age`` will convert the 

2101 value to an int. 

2102 

2103 .. versionadded:: 0.5 

2104 In previous versions a `CacheControl` class existed that was used 

2105 both for request and response. 

2106 """ 

2107 

2108 public = cache_control_property("public", None, bool) 

2109 private = cache_control_property("private", "*", None) 

2110 must_revalidate = cache_control_property("must-revalidate", None, bool) 

2111 proxy_revalidate = cache_control_property("proxy-revalidate", None, bool) 

2112 s_maxage = cache_control_property("s-maxage", None, int) 

2113 immutable = cache_control_property("immutable", None, bool) 

2114 

2115 

2116def csp_property(key): 

2117 """Return a new property object for a content security policy header. 

2118 Useful if you want to add support for a csp extension in a 

2119 subclass. 

2120 """ 

2121 return property( 

2122 lambda x: x._get_value(key), 

2123 lambda x, v: x._set_value(key, v), 

2124 lambda x: x._del_value(key), 

2125 f"accessor for {key!r}", 

2126 ) 

2127 

2128 

2129class ContentSecurityPolicy(UpdateDictMixin, dict): 

2130 """Subclass of a dict that stores values for a Content Security Policy 

2131 header. It has accessors for all the level 3 policies. 

2132 

2133 Because the csp directives in the HTTP header use dashes the 

2134 python descriptors use underscores for that. 

2135 

2136 To get a header of the :class:`ContentSecuirtyPolicy` object again 

2137 you can convert the object into a string or call the 

2138 :meth:`to_header` method. If you plan to subclass it and add your 

2139 own items have a look at the sourcecode for that class. 

2140 

2141 .. versionadded:: 1.0.0 

2142 Support for Content Security Policy headers was added. 

2143 

2144 """ 

2145 

2146 base_uri = csp_property("base-uri") 

2147 child_src = csp_property("child-src") 

2148 connect_src = csp_property("connect-src") 

2149 default_src = csp_property("default-src") 

2150 font_src = csp_property("font-src") 

2151 form_action = csp_property("form-action") 

2152 frame_ancestors = csp_property("frame-ancestors") 

2153 frame_src = csp_property("frame-src") 

2154 img_src = csp_property("img-src") 

2155 manifest_src = csp_property("manifest-src") 

2156 media_src = csp_property("media-src") 

2157 navigate_to = csp_property("navigate-to") 

2158 object_src = csp_property("object-src") 

2159 prefetch_src = csp_property("prefetch-src") 

2160 plugin_types = csp_property("plugin-types") 

2161 report_to = csp_property("report-to") 

2162 report_uri = csp_property("report-uri") 

2163 sandbox = csp_property("sandbox") 

2164 script_src = csp_property("script-src") 

2165 script_src_attr = csp_property("script-src-attr") 

2166 script_src_elem = csp_property("script-src-elem") 

2167 style_src = csp_property("style-src") 

2168 style_src_attr = csp_property("style-src-attr") 

2169 style_src_elem = csp_property("style-src-elem") 

2170 worker_src = csp_property("worker-src") 

2171 

2172 def __init__(self, values=(), on_update=None): 

2173 dict.__init__(self, values or ()) 

2174 self.on_update = on_update 

2175 self.provided = values is not None 

2176 

2177 def _get_value(self, key): 

2178 """Used internally by the accessor properties.""" 

2179 return self.get(key) 

2180 

2181 def _set_value(self, key, value): 

2182 """Used internally by the accessor properties.""" 

2183 if value is None: 

2184 self.pop(key, None) 

2185 else: 

2186 self[key] = value 

2187 

2188 def _del_value(self, key): 

2189 """Used internally by the accessor properties.""" 

2190 if key in self: 

2191 del self[key] 

2192 

2193 def to_header(self): 

2194 """Convert the stored values into a cache control header.""" 

2195 return http.dump_csp_header(self) 

2196 

2197 def __str__(self): 

2198 return self.to_header() 

2199 

2200 def __repr__(self): 

2201 kv_str = " ".join(f"{k}={v!r}" for k, v in sorted(self.items())) 

2202 return f"<{type(self).__name__} {kv_str}>" 

2203 

2204 

2205class CallbackDict(UpdateDictMixin, dict): 

2206 """A dict that calls a function passed every time something is changed. 

2207 The function is passed the dict instance. 

2208 """ 

2209 

2210 def __init__(self, initial=None, on_update=None): 

2211 dict.__init__(self, initial or ()) 

2212 self.on_update = on_update 

2213 

2214 def __repr__(self): 

2215 return f"<{type(self).__name__} {dict.__repr__(self)}>" 

2216 

2217 

2218class HeaderSet(MutableSet): 

2219 """Similar to the :class:`ETags` class this implements a set-like structure. 

2220 Unlike :class:`ETags` this is case insensitive and used for vary, allow, and 

2221 content-language headers. 

2222 

2223 If not constructed using the :func:`parse_set_header` function the 

2224 instantiation works like this: 

2225 

2226 >>> hs = HeaderSet(['foo', 'bar', 'baz']) 

2227 >>> hs 

2228 HeaderSet(['foo', 'bar', 'baz']) 

2229 """ 

2230 

2231 def __init__(self, headers=None, on_update=None): 

2232 self._headers = list(headers or ()) 

2233 self._set = {x.lower() for x in self._headers} 

2234 self.on_update = on_update 

2235 

2236 def add(self, header): 

2237 """Add a new header to the set.""" 

2238 self.update((header,)) 

2239 

2240 def remove(self, header): 

2241 """Remove a header from the set. This raises an :exc:`KeyError` if the 

2242 header is not in the set. 

2243 

2244 .. versionchanged:: 0.5 

2245 In older versions a :exc:`IndexError` was raised instead of a 

2246 :exc:`KeyError` if the object was missing. 

2247 

2248 :param header: the header to be removed. 

2249 """ 

2250 key = header.lower() 

2251 if key not in self._set: 

2252 raise KeyError(header) 

2253 self._set.remove(key) 

2254 for idx, key in enumerate(self._headers): 

2255 if key.lower() == header: 

2256 del self._headers[idx] 

2257 break 

2258 if self.on_update is not None: 

2259 self.on_update(self) 

2260 

2261 def update(self, iterable): 

2262 """Add all the headers from the iterable to the set. 

2263 

2264 :param iterable: updates the set with the items from the iterable. 

2265 """ 

2266 inserted_any = False 

2267 for header in iterable: 

2268 key = header.lower() 

2269 if key not in self._set: 

2270 self._headers.append(header) 

2271 self._set.add(key) 

2272 inserted_any = True 

2273 if inserted_any and self.on_update is not None: 

2274 self.on_update(self) 

2275 

2276 def discard(self, header): 

2277 """Like :meth:`remove` but ignores errors. 

2278 

2279 :param header: the header to be discarded. 

2280 """ 

2281 try: 

2282 self.remove(header) 

2283 except KeyError: 

2284 pass 

2285 

2286 def find(self, header): 

2287 """Return the index of the header in the set or return -1 if not found. 

2288 

2289 :param header: the header to be looked up. 

2290 """ 

2291 header = header.lower() 

2292 for idx, item in enumerate(self._headers): 

2293 if item.lower() == header: 

2294 return idx 

2295 return -1 

2296 

2297 def index(self, header): 

2298 """Return the index of the header in the set or raise an 

2299 :exc:`IndexError`. 

2300 

2301 :param header: the header to be looked up. 

2302 """ 

2303 rv = self.find(header) 

2304 if rv < 0: 

2305 raise IndexError(header) 

2306 return rv 

2307 

2308 def clear(self): 

2309 """Clear the set.""" 

2310 self._set.clear() 

2311 del self._headers[:] 

2312 if self.on_update is not None: 

2313 self.on_update(self) 

2314 

2315 def as_set(self, preserve_casing=False): 

2316 """Return the set as real python set type. When calling this, all 

2317 the items are converted to lowercase and the ordering is lost. 

2318 

2319 :param preserve_casing: if set to `True` the items in the set returned 

2320 will have the original case like in the 

2321 :class:`HeaderSet`, otherwise they will 

2322 be lowercase. 

2323 """ 

2324 if preserve_casing: 

2325 return set(self._headers) 

2326 return set(self._set) 

2327 

2328 def to_header(self): 

2329 """Convert the header set into an HTTP header string.""" 

2330 return ", ".join(map(http.quote_header_value, self._headers)) 

2331 

2332 def __getitem__(self, idx): 

2333 return self._headers[idx] 

2334 

2335 def __delitem__(self, idx): 

2336 rv = self._headers.pop(idx) 

2337 self._set.remove(rv.lower()) 

2338 if self.on_update is not None: 

2339 self.on_update(self) 

2340 

2341 def __setitem__(self, idx, value): 

2342 old = self._headers[idx] 

2343 self._set.remove(old.lower()) 

2344 self._headers[idx] = value 

2345 self._set.add(value.lower()) 

2346 if self.on_update is not None: 

2347 self.on_update(self) 

2348 

2349 def __contains__(self, header): 

2350 return header.lower() in self._set 

2351 

2352 def __len__(self): 

2353 return len(self._set) 

2354 

2355 def __iter__(self): 

2356 return iter(self._headers) 

2357 

2358 def __bool__(self): 

2359 return bool(self._set) 

2360 

2361 def __str__(self): 

2362 return self.to_header() 

2363 

2364 def __repr__(self): 

2365 return f"{type(self).__name__}({self._headers!r})" 

2366 

2367 

2368class ETags(Collection): 

2369 """A set that can be used to check if one etag is present in a collection 

2370 of etags. 

2371 """ 

2372 

2373 def __init__(self, strong_etags=None, weak_etags=None, star_tag=False): 

2374 if not star_tag and strong_etags: 

2375 self._strong = frozenset(strong_etags) 

2376 else: 

2377 self._strong = frozenset() 

2378 

2379 self._weak = frozenset(weak_etags or ()) 

2380 self.star_tag = star_tag 

2381 

2382 def as_set(self, include_weak=False): 

2383 """Convert the `ETags` object into a python set. Per default all the 

2384 weak etags are not part of this set.""" 

2385 rv = set(self._strong) 

2386 if include_weak: 

2387 rv.update(self._weak) 

2388 return rv 

2389 

2390 def is_weak(self, etag): 

2391 """Check if an etag is weak.""" 

2392 return etag in self._weak 

2393 

2394 def is_strong(self, etag): 

2395 """Check if an etag is strong.""" 

2396 return etag in self._strong 

2397 

2398 def contains_weak(self, etag): 

2399 """Check if an etag is part of the set including weak and strong tags.""" 

2400 return self.is_weak(etag) or self.contains(etag) 

2401 

2402 def contains(self, etag): 

2403 """Check if an etag is part of the set ignoring weak tags. 

2404 It is also possible to use the ``in`` operator. 

2405 """ 

2406 if self.star_tag: 

2407 return True 

2408 return self.is_strong(etag) 

2409 

2410 def contains_raw(self, etag): 

2411 """When passed a quoted tag it will check if this tag is part of the 

2412 set. If the tag is weak it is checked against weak and strong tags, 

2413 otherwise strong only.""" 

2414 etag, weak = http.unquote_etag(etag) 

2415 if weak: 

2416 return self.contains_weak(etag) 

2417 return self.contains(etag) 

2418 

2419 def to_header(self): 

2420 """Convert the etags set into a HTTP header string.""" 

2421 if self.star_tag: 

2422 return "*" 

2423 return ", ".join( 

2424 [f'"{x}"' for x in self._strong] + [f'W/"{x}"' for x in self._weak] 

2425 ) 

2426 

2427 def __call__(self, etag=None, data=None, include_weak=False): 

2428 if [etag, data].count(None) != 1: 

2429 raise TypeError("either tag or data required, but at least one") 

2430 if etag is None: 

2431 etag = http.generate_etag(data) 

2432 if include_weak: 

2433 if etag in self._weak: 

2434 return True 

2435 return etag in self._strong 

2436 

2437 def __bool__(self): 

2438 return bool(self.star_tag or self._strong or self._weak) 

2439 

2440 def __str__(self): 

2441 return self.to_header() 

2442 

2443 def __len__(self): 

2444 return len(self._strong) 

2445 

2446 def __iter__(self): 

2447 return iter(self._strong) 

2448 

2449 def __contains__(self, etag): 

2450 return self.contains(etag) 

2451 

2452 def __repr__(self): 

2453 return f"<{type(self).__name__} {str(self)!r}>" 

2454 

2455 

2456class IfRange: 

2457 """Very simple object that represents the `If-Range` header in parsed 

2458 form. It will either have neither a etag or date or one of either but 

2459 never both. 

2460 

2461 .. versionadded:: 0.7 

2462 """ 

2463 

2464 def __init__(self, etag=None, date=None): 

2465 #: The etag parsed and unquoted. Ranges always operate on strong 

2466 #: etags so the weakness information is not necessary. 

2467 self.etag = etag 

2468 #: The date in parsed format or `None`. 

2469 self.date = date 

2470 

2471 def to_header(self): 

2472 """Converts the object back into an HTTP header.""" 

2473 if self.date is not None: 

2474 return http.http_date(self.date) 

2475 if self.etag is not None: 

2476 return http.quote_etag(self.etag) 

2477 return "" 

2478 

2479 def __str__(self): 

2480 return self.to_header() 

2481 

2482 def __repr__(self): 

2483 return f"<{type(self).__name__} {str(self)!r}>" 

2484 

2485 

2486class Range: 

2487 """Represents a ``Range`` header. All methods only support only 

2488 bytes as the unit. Stores a list of ranges if given, but the methods 

2489 only work if only one range is provided. 

2490 

2491 :raise ValueError: If the ranges provided are invalid. 

2492 

2493 .. versionchanged:: 0.15 

2494 The ranges passed in are validated. 

2495 

2496 .. versionadded:: 0.7 

2497 """ 

2498 

2499 def __init__(self, units, ranges): 

2500 #: The units of this range. Usually "bytes". 

2501 self.units = units 

2502 #: A list of ``(begin, end)`` tuples for the range header provided. 

2503 #: The ranges are non-inclusive. 

2504 self.ranges = ranges 

2505 

2506 for start, end in ranges: 

2507 if start is None or (end is not None and (start < 0 or start >= end)): 

2508 raise ValueError(f"{(start, end)} is not a valid range.") 

2509 

2510 def range_for_length(self, length): 

2511 """If the range is for bytes, the length is not None and there is 

2512 exactly one range and it is satisfiable it returns a ``(start, stop)`` 

2513 tuple, otherwise `None`. 

2514 """ 

2515 if self.units != "bytes" or length is None or len(self.ranges) != 1: 

2516 return None 

2517 start, end = self.ranges[0] 

2518 if end is None: 

2519 end = length 

2520 if start < 0: 

2521 start += length 

2522 if http.is_byte_range_valid(start, end, length): 

2523 return start, min(end, length) 

2524 return None 

2525 

2526 def make_content_range(self, length): 

2527 """Creates a :class:`~werkzeug.datastructures.ContentRange` object 

2528 from the current range and given content length. 

2529 """ 

2530 rng = self.range_for_length(length) 

2531 if rng is not None: 

2532 return ContentRange(self.units, rng[0], rng[1], length) 

2533 return None 

2534 

2535 def to_header(self): 

2536 """Converts the object back into an HTTP header.""" 

2537 ranges = [] 

2538 for begin, end in self.ranges: 

2539 if end is None: 

2540 ranges.append(f"{begin}-" if begin >= 0 else str(begin)) 

2541 else: 

2542 ranges.append(f"{begin}-{end - 1}") 

2543 return f"{self.units}={','.join(ranges)}" 

2544 

2545 def to_content_range_header(self, length): 

2546 """Converts the object into `Content-Range` HTTP header, 

2547 based on given length 

2548 """ 

2549 range = self.range_for_length(length) 

2550 if range is not None: 

2551 return f"{self.units} {range[0]}-{range[1] - 1}/{length}" 

2552 return None 

2553 

2554 def __str__(self): 

2555 return self.to_header() 

2556 

2557 def __repr__(self): 

2558 return f"<{type(self).__name__} {str(self)!r}>" 

2559 

2560 

2561def _callback_property(name): 

2562 def fget(self): 

2563 return getattr(self, name) 

2564 

2565 def fset(self, value): 

2566 setattr(self, name, value) 

2567 if self.on_update is not None: 

2568 self.on_update(self) 

2569 

2570 return property(fget, fset) 

2571 

2572 

2573class ContentRange: 

2574 """Represents the content range header. 

2575 

2576 .. versionadded:: 0.7 

2577 """ 

2578 

2579 def __init__(self, units, start, stop, length=None, on_update=None): 

2580 assert http.is_byte_range_valid(start, stop, length), "Bad range provided" 

2581 self.on_update = on_update 

2582 self.set(start, stop, length, units) 

2583 

2584 #: The units to use, usually "bytes" 

2585 units = _callback_property("_units") 

2586 #: The start point of the range or `None`. 

2587 start = _callback_property("_start") 

2588 #: The stop point of the range (non-inclusive) or `None`. Can only be 

2589 #: `None` if also start is `None`. 

2590 stop = _callback_property("_stop") 

2591 #: The length of the range or `None`. 

2592 length = _callback_property("_length") 

2593 

2594 def set(self, start, stop, length=None, units="bytes"): 

2595 """Simple method to update the ranges.""" 

2596 assert http.is_byte_range_valid(start, stop, length), "Bad range provided" 

2597 self._units = units 

2598 self._start = start 

2599 self._stop = stop 

2600 self._length = length 

2601 if self.on_update is not None: 

2602 self.on_update(self) 

2603 

2604 def unset(self): 

2605 """Sets the units to `None` which indicates that the header should 

2606 no longer be used. 

2607 """ 

2608 self.set(None, None, units=None) 

2609 

2610 def to_header(self): 

2611 if self.units is None: 

2612 return "" 

2613 if self.length is None: 

2614 length = "*" 

2615 else: 

2616 length = self.length 

2617 if self.start is None: 

2618 return f"{self.units} */{length}" 

2619 return f"{self.units} {self.start}-{self.stop - 1}/{length}" 

2620 

2621 def __bool__(self): 

2622 return self.units is not None 

2623 

2624 def __str__(self): 

2625 return self.to_header() 

2626 

2627 def __repr__(self): 

2628 return f"<{type(self).__name__} {str(self)!r}>" 

2629 

2630 

2631class Authorization(ImmutableDictMixin, dict): 

2632 """Represents an ``Authorization`` header sent by the client. 

2633 

2634 This is returned by 

2635 :func:`~werkzeug.http.parse_authorization_header`. It can be useful 

2636 to create the object manually to pass to the test 

2637 :class:`~werkzeug.test.Client`. 

2638 

2639 .. versionchanged:: 0.5 

2640 This object became immutable. 

2641 """ 

2642 

2643 def __init__(self, auth_type, data=None): 

2644 dict.__init__(self, data or {}) 

2645 self.type = auth_type 

2646 

2647 @property 

2648 def username(self): 

2649 """The username transmitted. This is set for both basic and digest 

2650 auth all the time. 

2651 """ 

2652 return self.get("username") 

2653 

2654 @property 

2655 def password(self): 

2656 """When the authentication type is basic this is the password 

2657 transmitted by the client, else `None`. 

2658 """ 

2659 return self.get("password") 

2660 

2661 @property 

2662 def realm(self): 

2663 """This is the server realm sent back for HTTP digest auth.""" 

2664 return self.get("realm") 

2665 

2666 @property 

2667 def nonce(self): 

2668 """The nonce the server sent for digest auth, sent back by the client. 

2669 A nonce should be unique for every 401 response for HTTP digest auth. 

2670 """ 

2671 return self.get("nonce") 

2672 

2673 @property 

2674 def uri(self): 

2675 """The URI from Request-URI of the Request-Line; duplicated because 

2676 proxies are allowed to change the Request-Line in transit. HTTP 

2677 digest auth only. 

2678 """ 

2679 return self.get("uri") 

2680 

2681 @property 

2682 def nc(self): 

2683 """The nonce count value transmitted by clients if a qop-header is 

2684 also transmitted. HTTP digest auth only. 

2685 """ 

2686 return self.get("nc") 

2687 

2688 @property 

2689 def cnonce(self): 

2690 """If the server sent a qop-header in the ``WWW-Authenticate`` 

2691 header, the client has to provide this value for HTTP digest auth. 

2692 See the RFC for more details. 

2693 """ 

2694 return self.get("cnonce") 

2695 

2696 @property 

2697 def response(self): 

2698 """A string of 32 hex digits computed as defined in RFC 2617, which 

2699 proves that the user knows a password. Digest auth only. 

2700 """ 

2701 return self.get("response") 

2702 

2703 @property 

2704 def opaque(self): 

2705 """The opaque header from the server returned unchanged by the client. 

2706 It is recommended that this string be base64 or hexadecimal data. 

2707 Digest auth only. 

2708 """ 

2709 return self.get("opaque") 

2710 

2711 @property 

2712 def qop(self): 

2713 """Indicates what "quality of protection" the client has applied to 

2714 the message for HTTP digest auth. Note that this is a single token, 

2715 not a quoted list of alternatives as in WWW-Authenticate. 

2716 """ 

2717 return self.get("qop") 

2718 

2719 def to_header(self): 

2720 """Convert to a string value for an ``Authorization`` header. 

2721 

2722 .. versionadded:: 2.0 

2723 Added to support passing authorization to the test client. 

2724 """ 

2725 if self.type == "basic": 

2726 value = base64.b64encode( 

2727 f"{self.username}:{self.password}".encode() 

2728 ).decode("utf8") 

2729 return f"Basic {value}" 

2730 

2731 if self.type == "digest": 

2732 return f"Digest {http.dump_header(self)}" 

2733 

2734 raise ValueError(f"Unsupported type {self.type!r}.") 

2735 

2736 

2737def auth_property(name, doc=None): 

2738 """A static helper function for Authentication subclasses to add 

2739 extra authentication system properties onto a class:: 

2740 

2741 class FooAuthenticate(WWWAuthenticate): 

2742 special_realm = auth_property('special_realm') 

2743 

2744 For more information have a look at the sourcecode to see how the 

2745 regular properties (:attr:`realm` etc.) are implemented. 

2746 """ 

2747 

2748 def _set_value(self, value): 

2749 if value is None: 

2750 self.pop(name, None) 

2751 else: 

2752 self[name] = str(value) 

2753 

2754 return property(lambda x: x.get(name), _set_value, doc=doc) 

2755 

2756 

2757def _set_property(name, doc=None): 

2758 def fget(self): 

2759 def on_update(header_set): 

2760 if not header_set and name in self: 

2761 del self[name] 

2762 elif header_set: 

2763 self[name] = header_set.to_header() 

2764 

2765 return http.parse_set_header(self.get(name), on_update) 

2766 

2767 return property(fget, doc=doc) 

2768 

2769 

2770class WWWAuthenticate(UpdateDictMixin, dict): 

2771 """Provides simple access to `WWW-Authenticate` headers.""" 

2772 

2773 #: list of keys that require quoting in the generated header 

2774 _require_quoting = frozenset(["domain", "nonce", "opaque", "realm", "qop"]) 

2775 

2776 def __init__(self, auth_type=None, values=None, on_update=None): 

2777 dict.__init__(self, values or ()) 

2778 if auth_type: 

2779 self["__auth_type__"] = auth_type 

2780 self.on_update = on_update 

2781 

2782 def set_basic(self, realm="authentication required"): 

2783 """Clear the auth info and enable basic auth.""" 

2784 dict.clear(self) 

2785 dict.update(self, {"__auth_type__": "basic", "realm": realm}) 

2786 if self.on_update: 

2787 self.on_update(self) 

2788 

2789 def set_digest( 

2790 self, realm, nonce, qop=("auth",), opaque=None, algorithm=None, stale=False 

2791 ): 

2792 """Clear the auth info and enable digest auth.""" 

2793 d = { 

2794 "__auth_type__": "digest", 

2795 "realm": realm, 

2796 "nonce": nonce, 

2797 "qop": http.dump_header(qop), 

2798 } 

2799 if stale: 

2800 d["stale"] = "TRUE" 

2801 if opaque is not None: 

2802 d["opaque"] = opaque 

2803 if algorithm is not None: 

2804 d["algorithm"] = algorithm 

2805 dict.clear(self) 

2806 dict.update(self, d) 

2807 if self.on_update: 

2808 self.on_update(self) 

2809 

2810 def to_header(self): 

2811 """Convert the stored values into a WWW-Authenticate header.""" 

2812 d = dict(self) 

2813 auth_type = d.pop("__auth_type__", None) or "basic" 

2814 kv_items = ( 

2815 (k, http.quote_header_value(v, allow_token=k not in self._require_quoting)) 

2816 for k, v in d.items() 

2817 ) 

2818 kv_string = ", ".join([f"{k}={v}" for k, v in kv_items]) 

2819 return f"{auth_type.title()} {kv_string}" 

2820 

2821 def __str__(self): 

2822 return self.to_header() 

2823 

2824 def __repr__(self): 

2825 return f"<{type(self).__name__} {self.to_header()!r}>" 

2826 

2827 type = auth_property( 

2828 "__auth_type__", 

2829 doc="""The type of the auth mechanism. HTTP currently specifies 

2830 ``Basic`` and ``Digest``.""", 

2831 ) 

2832 realm = auth_property( 

2833 "realm", 

2834 doc="""A string to be displayed to users so they know which 

2835 username and password to use. This string should contain at 

2836 least the name of the host performing the authentication and 

2837 might additionally indicate the collection of users who might 

2838 have access.""", 

2839 ) 

2840 domain = _set_property( 

2841 "domain", 

2842 doc="""A list of URIs that define the protection space. If a URI 

2843 is an absolute path, it is relative to the canonical root URL of 

2844 the server being accessed.""", 

2845 ) 

2846 nonce = auth_property( 

2847 "nonce", 

2848 doc=""" 

2849 A server-specified data string which should be uniquely generated 

2850 each time a 401 response is made. It is recommended that this 

2851 string be base64 or hexadecimal data.""", 

2852 ) 

2853 opaque = auth_property( 

2854 "opaque", 

2855 doc="""A string of data, specified by the server, which should 

2856 be returned by the client unchanged in the Authorization header 

2857 of subsequent requests with URIs in the same protection space. 

2858 It is recommended that this string be base64 or hexadecimal 

2859 data.""", 

2860 ) 

2861 algorithm = auth_property( 

2862 "algorithm", 

2863 doc="""A string indicating a pair of algorithms used to produce 

2864 the digest and a checksum. If this is not present it is assumed 

2865 to be "MD5". If the algorithm is not understood, the challenge 

2866 should be ignored (and a different one used, if there is more 

2867 than one).""", 

2868 ) 

2869 qop = _set_property( 

2870 "qop", 

2871 doc="""A set of quality-of-privacy directives such as auth and 

2872 auth-int.""", 

2873 ) 

2874 

2875 @property 

2876 def stale(self): 

2877 """A flag, indicating that the previous request from the client 

2878 was rejected because the nonce value was stale. 

2879 """ 

2880 val = self.get("stale") 

2881 if val is not None: 

2882 return val.lower() == "true" 

2883 

2884 @stale.setter 

2885 def stale(self, value): 

2886 if value is None: 

2887 self.pop("stale", None) 

2888 else: 

2889 self["stale"] = "TRUE" if value else "FALSE" 

2890 

2891 auth_property = staticmethod(auth_property) 

2892 

2893 

2894class FileStorage: 

2895 """The :class:`FileStorage` class is a thin wrapper over incoming files. 

2896 It is used by the request object to represent uploaded files. All the 

2897 attributes of the wrapper stream are proxied by the file storage so 

2898 it's possible to do ``storage.read()`` instead of the long form 

2899 ``storage.stream.read()``. 

2900 """ 

2901 

2902 def __init__( 

2903 self, 

2904 stream=None, 

2905 filename=None, 

2906 name=None, 

2907 content_type=None, 

2908 content_length=None, 

2909 headers=None, 

2910 ): 

2911 self.name = name 

2912 self.stream = stream or BytesIO() 

2913 

2914 # If no filename is provided, attempt to get the filename from 

2915 # the stream object. Python names special streams like 

2916 # ``<stderr>`` with angular brackets, skip these streams. 

2917 if filename is None: 

2918 filename = getattr(stream, "name", None) 

2919 

2920 if filename is not None: 

2921 filename = os.fsdecode(filename) 

2922 

2923 if filename and filename[0] == "<" and filename[-1] == ">": 

2924 filename = None 

2925 else: 

2926 filename = os.fsdecode(filename) 

2927 

2928 self.filename = filename 

2929 

2930 if headers is None: 

2931 headers = Headers() 

2932 self.headers = headers 

2933 if content_type is not None: 

2934 headers["Content-Type"] = content_type 

2935 if content_length is not None: 

2936 headers["Content-Length"] = str(content_length) 

2937 

2938 def _parse_content_type(self): 

2939 if not hasattr(self, "_parsed_content_type"): 

2940 self._parsed_content_type = http.parse_options_header(self.content_type) 

2941 

2942 @property 

2943 def content_type(self): 

2944 """The content-type sent in the header. Usually not available""" 

2945 return self.headers.get("content-type") 

2946 

2947 @property 

2948 def content_length(self): 

2949 """The content-length sent in the header. Usually not available""" 

2950 try: 

2951 return int(self.headers.get("content-length") or 0) 

2952 except ValueError: 

2953 return 0 

2954 

2955 @property 

2956 def mimetype(self): 

2957 """Like :attr:`content_type`, but without parameters (eg, without 

2958 charset, type etc.) and always lowercase. For example if the content 

2959 type is ``text/HTML; charset=utf-8`` the mimetype would be 

2960 ``'text/html'``. 

2961 

2962 .. versionadded:: 0.7 

2963 """ 

2964 self._parse_content_type() 

2965 return self._parsed_content_type[0].lower() 

2966 

2967 @property 

2968 def mimetype_params(self): 

2969 """The mimetype parameters as dict. For example if the content 

2970 type is ``text/html; charset=utf-8`` the params would be 

2971 ``{'charset': 'utf-8'}``. 

2972 

2973 .. versionadded:: 0.7 

2974 """ 

2975 self._parse_content_type() 

2976 return self._parsed_content_type[1] 

2977 

2978 def save(self, dst, buffer_size=16384): 

2979 """Save the file to a destination path or file object. If the 

2980 destination is a file object you have to close it yourself after the 

2981 call. The buffer size is the number of bytes held in memory during 

2982 the copy process. It defaults to 16KB. 

2983 

2984 For secure file saving also have a look at :func:`secure_filename`. 

2985 

2986 :param dst: a filename, :class:`os.PathLike`, or open file 

2987 object to write to. 

2988 :param buffer_size: Passed as the ``length`` parameter of 

2989 :func:`shutil.copyfileobj`. 

2990 

2991 .. versionchanged:: 1.0 

2992 Supports :mod:`pathlib`. 

2993 """ 

2994 from shutil import copyfileobj 

2995 

2996 close_dst = False 

2997 

2998 if hasattr(dst, "__fspath__"): 

2999 dst = fspath(dst) 

3000 

3001 if isinstance(dst, str): 

3002 dst = open(dst, "wb") 

3003 close_dst = True 

3004 

3005 try: 

3006 copyfileobj(self.stream, dst, buffer_size) 

3007 finally: 

3008 if close_dst: 

3009 dst.close() 

3010 

3011 def close(self): 

3012 """Close the underlying file if possible.""" 

3013 try: 

3014 self.stream.close() 

3015 except Exception: 

3016 pass 

3017 

3018 def __bool__(self): 

3019 return bool(self.filename) 

3020 

3021 def __getattr__(self, name): 

3022 try: 

3023 return getattr(self.stream, name) 

3024 except AttributeError: 

3025 # SpooledTemporaryFile doesn't implement IOBase, get the 

3026 # attribute from its backing file instead. 

3027 # https://github.com/python/cpython/pull/3249 

3028 if hasattr(self.stream, "_file"): 

3029 return getattr(self.stream._file, name) 

3030 raise 

3031 

3032 def __iter__(self): 

3033 return iter(self.stream) 

3034 

3035 def __repr__(self): 

3036 return f"<{type(self).__name__}: {self.filename!r} ({self.content_type!r})>" 

3037 

3038 

3039# circular dependencies 

3040from . import http