datastructures.py (44543B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\werkzeug\datastructures.py 2 import re 3 import codecs 4 import mimetypes 5 from werkzeug._internal import _proxy_repr, _missing, _empty_stream 6 _locale_delim_re = re.compile('[_-]') 7 8 def is_immutable(self): 9 raise TypeError('%r objects are immutable' % self.__class__.__name__) 10 11 12 def iter_multi_items(mapping): 13 if isinstance(mapping, MultiDict): 14 for item in mapping.iteritems(multi=True): 15 yield item 16 17 elif isinstance(mapping, dict): 18 for key, value in mapping.iteritems(): 19 if isinstance(value, (tuple, list)): 20 for value in value: 21 yield (key, value) 22 23 else: 24 yield (key, value) 25 26 else: 27 for item in mapping: 28 yield item 29 30 31 class ImmutableListMixin(object): 32 33 def __reduce_ex__(self, protocol): 34 return (type(self), (list(self),)) 35 36 def __delitem__(self, key): 37 is_immutable(self) 38 39 def __delslice__(self, i, j): 40 is_immutable(self) 41 42 def __iadd__(self, other): 43 is_immutable(self) 44 45 __imul__ = __iadd__ 46 47 def __setitem__(self, key, value): 48 is_immutable(self) 49 50 def __setslice__(self, i, j, value): 51 is_immutable(self) 52 53 def append(self, item): 54 is_immutable(self) 55 56 remove = append 57 58 def extend(self, iterable): 59 is_immutable(self) 60 61 def insert(self, pos, value): 62 is_immutable(self) 63 64 def pop(self, index = -1): 65 is_immutable(self) 66 67 def reverse(self): 68 is_immutable(self) 69 70 def sort(self, cmp = None, key = None, reverse = None): 71 is_immutable(self) 72 73 74 class ImmutableList(ImmutableListMixin, list): 75 __repr__ = _proxy_repr(list) 76 77 78 class ImmutableDictMixin(object): 79 80 def __reduce_ex__(self, protocol): 81 return (type(self), (dict(self),)) 82 83 def setdefault(self, key, default = None): 84 is_immutable(self) 85 86 def update(self, *args, **kwargs): 87 is_immutable(self) 88 89 def pop(self, key, default = None): 90 is_immutable(self) 91 92 def popitem(self): 93 is_immutable(self) 94 95 def __setitem__(self, key, value): 96 is_immutable(self) 97 98 def __delitem__(self, key): 99 is_immutable(self) 100 101 def clear(self): 102 is_immutable(self) 103 104 105 class ImmutableMultiDictMixin(ImmutableDictMixin): 106 107 def __reduce_ex__(self, protocol): 108 return (type(self), (self.items(multi=True),)) 109 110 def add(self, key, value): 111 is_immutable(self) 112 113 def popitemlist(self): 114 is_immutable(self) 115 116 def poplist(self, key): 117 is_immutable(self) 118 119 def setlist(self, key, new_list): 120 is_immutable(self) 121 122 def setlistdefault(self, key, default_list = None): 123 is_immutable(self) 124 125 126 class UpdateDictMixin(object): 127 on_update = None 128 129 def calls_update(name): 130 131 def oncall(self, *args, **kw): 132 rv = getattr(super(UpdateDictMixin, self), name)(*args, **kw) 133 if self.on_update is not None: 134 self.on_update(self) 135 return rv 136 137 oncall.__name__ = name 138 return oncall 139 140 __setitem__ = calls_update('__setitem__') 141 __delitem__ = calls_update('__delitem__') 142 clear = calls_update('clear') 143 pop = calls_update('pop') 144 popitem = calls_update('popitem') 145 setdefault = calls_update('setdefault') 146 update = calls_update('update') 147 del calls_update 148 149 150 class TypeConversionDict(dict): 151 152 def get(self, key, default = None, type = None): 153 try: 154 rv = self[key] 155 if type is not None: 156 rv = type(rv) 157 except (KeyError, ValueError): 158 rv = default 159 160 return rv 161 162 163 class ImmutableTypeConversionDict(ImmutableDictMixin, TypeConversionDict): 164 165 def copy(self): 166 return TypeConversionDict(self) 167 168 def __copy__(self): 169 return self 170 171 172 class MultiDict(TypeConversionDict): 173 KeyError = None 174 175 def __init__(self, mapping = None): 176 if isinstance(mapping, MultiDict): 177 dict.__init__(self, ((k, l[:]) for k, l in mapping.iterlists())) 178 elif isinstance(mapping, dict): 179 tmp = {} 180 for key, value in mapping.iteritems(): 181 if isinstance(value, (tuple, list)): 182 value = list(value) 183 else: 184 value = [value] 185 tmp[key] = value 186 187 dict.__init__(self, tmp) 188 else: 189 tmp = {} 190 for key, value in mapping or (): 191 tmp.setdefault(key, []).append(value) 192 193 dict.__init__(self, tmp) 194 195 def __getstate__(self): 196 return dict(self.lists()) 197 198 def __setstate__(self, value): 199 dict.clear(self) 200 dict.update(self, value) 201 202 def __iter__(self): 203 return self.iterkeys() 204 205 def __getitem__(self, key): 206 if key in self: 207 return dict.__getitem__(self, key)[0] 208 raise self.KeyError(key) 209 210 def __setitem__(self, key, value): 211 dict.__setitem__(self, key, [value]) 212 213 def add(self, key, value): 214 dict.setdefault(self, key, []).append(value) 215 216 def getlist(self, key, type = None): 217 try: 218 rv = dict.__getitem__(self, key) 219 except KeyError: 220 return [] 221 222 if type is None: 223 return list(rv) 224 result = [] 225 for item in rv: 226 try: 227 result.append(type(item)) 228 except ValueError: 229 pass 230 231 return result 232 233 def setlist(self, key, new_list): 234 dict.__setitem__(self, key, list(new_list)) 235 236 def setdefault(self, key, default = None): 237 if key not in self: 238 self[key] = default 239 else: 240 default = self[key] 241 return default 242 243 def setlistdefault(self, key, default_list = None): 244 if key not in self: 245 default_list = list(default_list or ()) 246 dict.__setitem__(self, key, default_list) 247 else: 248 default_list = dict.__getitem__(self, key) 249 return default_list 250 251 def items(self, multi = False): 252 return list(self.iteritems(multi)) 253 254 def lists(self): 255 return list(self.iterlists()) 256 257 def values(self): 258 return [ self[key] for key in self.iterkeys() ] 259 260 def listvalues(self): 261 return list(self.iterlistvalues()) 262 263 def iteritems(self, multi = False): 264 for key, values in dict.iteritems(self): 265 if multi: 266 for value in values: 267 yield (key, value) 268 269 else: 270 yield (key, values[0]) 271 272 def iterlists(self): 273 for key, values in dict.iteritems(self): 274 yield (key, list(values)) 275 276 def itervalues(self): 277 for values in dict.itervalues(self): 278 yield values[0] 279 280 def iterlistvalues(self): 281 for values in dict.itervalues(self): 282 yield list(values) 283 284 def copy(self): 285 return self.__class__(self) 286 287 def to_dict(self, flat = True): 288 if flat: 289 return dict(self.iteritems()) 290 return dict(self.lists()) 291 292 def update(self, other_dict): 293 for key, value in iter_multi_items(other_dict): 294 MultiDict.add(self, key, value) 295 296 def pop(self, key, default = _missing): 297 try: 298 return dict.pop(self, key)[0] 299 except KeyError as e: 300 if default is not _missing: 301 return default 302 raise self.KeyError(str(e)) 303 304 def popitem(self): 305 try: 306 item = dict.popitem(self) 307 return (item[0], item[1][0]) 308 except KeyError as e: 309 raise self.KeyError(str(e)) 310 311 def poplist(self, key): 312 return dict.pop(self, key, []) 313 314 def popitemlist(self): 315 try: 316 return dict.popitem(self) 317 except KeyError as e: 318 raise self.KeyError(str(e)) 319 320 def __repr__(self): 321 return '%s(%r)' % (self.__class__.__name__, self.items(multi=True)) 322 323 324 class _omd_bucket(object): 325 __slots__ = ('prev', 'key', 'value', 'next') 326 327 def __init__(self, omd, key, value): 328 self.prev = omd._last_bucket 329 self.key = key 330 self.value = value 331 self.next = None 332 if omd._first_bucket is None: 333 omd._first_bucket = self 334 if omd._last_bucket is not None: 335 omd._last_bucket.next = self 336 omd._last_bucket = self 337 338 def unlink(self, omd): 339 if self.prev: 340 self.prev.next = self.next 341 if self.next: 342 self.next.prev = self.prev 343 if omd._first_bucket is self: 344 omd._first_bucket = self.next 345 if omd._last_bucket is self: 346 omd._last_bucket = self.prev 347 348 349 class OrderedMultiDict(MultiDict): 350 KeyError = None 351 352 def __init__(self, mapping = None): 353 dict.__init__(self) 354 self._first_bucket = self._last_bucket = None 355 if mapping is not None: 356 OrderedMultiDict.update(self, mapping) 357 358 def __eq__(self, other): 359 if not isinstance(other, MultiDict): 360 return NotImplemented 361 if isinstance(other, OrderedMultiDict): 362 iter1 = self.iteritems(multi=True) 363 iter2 = other.iteritems(multi=True) 364 try: 365 for k1, v1 in iter1: 366 k2, v2 = iter2.next() 367 if k1 != k2 or v1 != v2: 368 return False 369 370 except StopIteration: 371 return False 372 373 try: 374 iter2.next() 375 except StopIteration: 376 return True 377 378 return False 379 if len(self) != len(other): 380 return False 381 for key, values in self.iterlists(): 382 if other.getlist(key) != values: 383 return False 384 385 return True 386 387 def __ne__(self, other): 388 return not self.__eq__(other) 389 390 def __reduce_ex__(self, protocol): 391 return (type(self), (self.items(multi=True),)) 392 393 def __getstate__(self): 394 return self.items(multi=True) 395 396 def __setstate__(self, values): 397 dict.clear(self) 398 for key, value in values: 399 self.add(key, value) 400 401 def __getitem__(self, key): 402 if key in self: 403 return dict.__getitem__(self, key)[0].value 404 raise self.KeyError(key) 405 406 def __setitem__(self, key, value): 407 self.poplist(key) 408 self.add(key, value) 409 410 def __delitem__(self, key): 411 self.pop(key) 412 413 def iterkeys(self): 414 return (key for key, value in self.iteritems()) 415 416 def itervalues(self): 417 return (value for key, value in self.iteritems()) 418 419 def iteritems(self, multi = False): 420 ptr = self._first_bucket 421 if multi: 422 while ptr is not None: 423 yield (ptr.key, ptr.value) 424 ptr = ptr.next 425 426 else: 427 returned_keys = set() 428 while ptr is not None: 429 if ptr.key not in returned_keys: 430 returned_keys.add(ptr.key) 431 yield (ptr.key, ptr.value) 432 ptr = ptr.next 433 434 def iterlists(self): 435 returned_keys = set() 436 ptr = self._first_bucket 437 while ptr is not None: 438 if ptr.key not in returned_keys: 439 yield (ptr.key, self.getlist(ptr.key)) 440 returned_keys.add(ptr.key) 441 ptr = ptr.next 442 443 def iterlistvalues(self): 444 for key, values in self.iterlists(): 445 yield values 446 447 def add(self, key, value): 448 dict.setdefault(self, key, []).append(_omd_bucket(self, key, value)) 449 450 def getlist(self, key, type = None): 451 try: 452 rv = dict.__getitem__(self, key) 453 except KeyError: 454 return [] 455 456 if type is None: 457 return [ x.value for x in rv ] 458 result = [] 459 for item in rv: 460 try: 461 result.append(type(item.value)) 462 except ValueError: 463 pass 464 465 return result 466 467 def setlist(self, key, new_list): 468 self.poplist(key) 469 for value in new_list: 470 self.add(key, value) 471 472 def setlistdefault(self, key, default_list = None): 473 raise TypeError('setlistdefault is unsupported for ordered multi dicts') 474 475 def update(self, mapping): 476 for key, value in iter_multi_items(mapping): 477 OrderedMultiDict.add(self, key, value) 478 479 def poplist(self, key): 480 buckets = dict.pop(self, key, ()) 481 for bucket in buckets: 482 bucket.unlink(self) 483 484 return [ x.value for x in buckets ] 485 486 def pop(self, key, default = _missing): 487 try: 488 buckets = dict.pop(self, key) 489 except KeyError as e: 490 if default is not _missing: 491 return default 492 raise self.KeyError(str(e)) 493 494 for bucket in buckets: 495 bucket.unlink(self) 496 497 return buckets[0].value 498 499 def popitem(self): 500 try: 501 key, buckets = dict.popitem(self) 502 except KeyError as e: 503 raise self.KeyError(str(e)) 504 505 for bucket in buckets: 506 bucket.unlink(self) 507 508 return (key, buckets[0].value) 509 510 def popitemlist(self): 511 try: 512 key, buckets = dict.popitem(self) 513 except KeyError as e: 514 raise self.KeyError(str(e)) 515 516 for bucket in buckets: 517 bucket.unlink(self) 518 519 return (key, [ x.value for x in buckets ]) 520 521 522 def _options_header_vkw(value, kw): 523 if not kw: 524 return value 525 return dump_options_header(value, dict(((k.replace('_', '-'), v) for k, v in kw.items()))) 526 527 528 class Headers(object): 529 KeyError = None 530 531 def __init__(self, defaults = None, _list = None): 532 if _list is None: 533 _list = [] 534 self._list = _list 535 if defaults is not None: 536 if isinstance(defaults, (list, Headers)): 537 self._list.extend(defaults) 538 else: 539 self.extend(defaults) 540 541 @classmethod 542 def linked(cls, headerlist): 543 return cls(_list=headerlist) 544 545 def __getitem__(self, key, _index_operation = True): 546 if _index_operation: 547 if isinstance(key, (int, long)): 548 return self._list[key] 549 if isinstance(key, slice): 550 return self.__class__(self._list[key]) 551 ikey = key.lower() 552 for k, v in self._list: 553 if k.lower() == ikey: 554 return v 555 556 raise self.KeyError(key) 557 558 def __eq__(self, other): 559 return other.__class__ is self.__class__ and set(other._list) == set(self._list) 560 561 def __ne__(self, other): 562 return not self.__eq__(other) 563 564 def get(self, key, default = None, type = None): 565 try: 566 rv = self.__getitem__(key, _index_operation=False) 567 except KeyError: 568 return default 569 570 if type is None: 571 return rv 572 try: 573 return type(rv) 574 except ValueError: 575 return default 576 577 def getlist(self, key, type = None): 578 ikey = key.lower() 579 result = [] 580 for k, v in self: 581 if k.lower() == ikey: 582 if type is not None: 583 try: 584 v = type(v) 585 except ValueError: 586 continue 587 588 result.append(v) 589 590 return result 591 592 def get_all(self, name): 593 return self.getlist(name) 594 595 def iteritems(self, lower = False): 596 for key, value in self: 597 if lower: 598 key = key.lower() 599 yield (key, value) 600 601 def iterkeys(self, lower = False): 602 for key, _ in self.iteritems(lower): 603 yield key 604 605 def itervalues(self): 606 for _, value in self.iteritems(): 607 yield value 608 609 def keys(self, lower = False): 610 return list(self.iterkeys(lower)) 611 612 def values(self): 613 return list(self.itervalues()) 614 615 def items(self, lower = False): 616 return list(self.iteritems(lower)) 617 618 def extend(self, iterable): 619 if isinstance(iterable, dict): 620 for key, value in iterable.iteritems(): 621 if isinstance(value, (tuple, list)): 622 for v in value: 623 self.add(key, v) 624 625 else: 626 self.add(key, value) 627 628 else: 629 for key, value in iterable: 630 self.add(key, value) 631 632 def __delitem__(self, key, _index_operation = True): 633 if _index_operation and isinstance(key, (int, long, slice)): 634 del self._list[key] 635 return 636 key = key.lower() 637 new = [] 638 for k, v in self._list: 639 if k.lower() != key: 640 new.append((k, v)) 641 642 self._list[:] = new 643 644 def remove(self, key): 645 return self.__delitem__(key, _index_operation=False) 646 647 def pop(self, key = None, default = _missing): 648 if key is None: 649 return self._list.pop() 650 if isinstance(key, (int, long)): 651 return self._list.pop(key) 652 try: 653 rv = self[key] 654 self.remove(key) 655 except KeyError: 656 if default is not _missing: 657 return default 658 raise 659 660 return rv 661 662 def popitem(self): 663 return self.pop() 664 665 def __contains__(self, key): 666 try: 667 self.__getitem__(key, _index_operation=False) 668 except KeyError: 669 return False 670 671 return True 672 673 has_key = __contains__ 674 675 def __iter__(self): 676 return iter(self._list) 677 678 def __len__(self): 679 return len(self._list) 680 681 def add(self, _key, _value, **kw): 682 self._list.append((_key, _options_header_vkw(_value, kw))) 683 684 def add_header(self, _key, _value, **_kw): 685 self.add(_key, _value, **_kw) 686 687 def clear(self): 688 del self._list[:] 689 690 def set(self, _key, _value, **kw): 691 lc_key = _key.lower() 692 _value = _options_header_vkw(_value, kw) 693 for idx, (old_key, old_value) in enumerate(self._list): 694 if old_key.lower() == lc_key: 695 self._list[idx] = (_key, _value) 696 break 697 else: 698 return self.add(_key, _value) 699 700 self._list[idx + 1:] = [ (k, v) for k, v in self._list[idx + 1:] if k.lower() != lc_key ] 701 702 def setdefault(self, key, value): 703 if key in self: 704 return self[key] 705 self.set(key, value) 706 return value 707 708 def __setitem__(self, key, value): 709 if isinstance(key, (slice, int, long)): 710 self._list[key] = value 711 else: 712 self.set(key, value) 713 714 def to_list(self, charset = 'utf-8'): 715 result = [] 716 for k, v in self: 717 if isinstance(v, unicode): 718 v = v.encode(charset) 719 else: 720 v = str(v) 721 result.append((k, v)) 722 723 return result 724 725 def copy(self): 726 return self.__class__(self._list) 727 728 def __copy__(self): 729 return self.copy() 730 731 def __str__(self, charset = 'utf-8'): 732 strs = [] 733 for key, value in self.to_list(charset): 734 strs.append('%s: %s' % (key, value)) 735 736 strs.append('\r\n') 737 return '\r\n'.join(strs) 738 739 def __repr__(self): 740 return '%s(%r)' % (self.__class__.__name__, list(self)) 741 742 743 class ImmutableHeadersMixin(object): 744 745 def __delitem__(self, key): 746 is_immutable(self) 747 748 def __setitem__(self, key, value): 749 is_immutable(self) 750 751 set = __setitem__ 752 753 def add(self, item): 754 is_immutable(self) 755 756 remove = add_header = add 757 758 def extend(self, iterable): 759 is_immutable(self) 760 761 def insert(self, pos, value): 762 is_immutable(self) 763 764 def pop(self, index = -1): 765 is_immutable(self) 766 767 def popitem(self): 768 is_immutable(self) 769 770 def setdefault(self, key, default): 771 is_immutable(self) 772 773 774 class EnvironHeaders(ImmutableHeadersMixin, Headers): 775 776 def __init__(self, environ): 777 self.environ = environ 778 779 @classmethod 780 def linked(cls, environ): 781 raise TypeError('%r object is always linked to environment, no separate initializer' % cls.__name__) 782 783 def __eq__(self, other): 784 return self.environ is other.environ 785 786 def __getitem__(self, key, _index_operation = False): 787 key = key.upper().replace('-', '_') 788 if key in ('CONTENT_TYPE', 'CONTENT_LENGTH'): 789 return self.environ[key] 790 return self.environ['HTTP_' + key] 791 792 def __len__(self): 793 return len(list(iter(self))) 794 795 def __iter__(self): 796 for key, value in self.environ.iteritems(): 797 if key.startswith('HTTP_') and key not in ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'): 798 yield (key[5:].replace('_', '-').title(), value) 799 elif key in ('CONTENT_TYPE', 'CONTENT_LENGTH'): 800 yield (key.replace('_', '-').title(), value) 801 802 def copy(self): 803 raise TypeError('cannot create %r copies' % self.__class__.__name__) 804 805 806 class CombinedMultiDict(ImmutableMultiDictMixin, MultiDict): 807 808 def __reduce_ex__(self, protocol): 809 return (type(self), (self.dicts,)) 810 811 def __init__(self, dicts = None): 812 self.dicts = dicts or [] 813 814 @classmethod 815 def fromkeys(cls): 816 raise TypeError('cannot create %r instances by fromkeys' % cls.__name__) 817 818 def __getitem__(self, key): 819 for d in self.dicts: 820 if key in d: 821 return d[key] 822 823 raise self.KeyError(key) 824 825 def get(self, key, default = None, type = None): 826 for d in self.dicts: 827 if key in d: 828 if type is not None: 829 try: 830 return type(d[key]) 831 except ValueError: 832 continue 833 834 return d[key] 835 836 return default 837 838 def getlist(self, key, type = None): 839 rv = [] 840 for d in self.dicts: 841 rv.extend(d.getlist(key, type)) 842 843 return rv 844 845 def keys(self): 846 rv = set() 847 for d in self.dicts: 848 rv.update(d.keys()) 849 850 return list(rv) 851 852 def iteritems(self, multi = False): 853 found = set() 854 for d in self.dicts: 855 for key, value in d.iteritems(multi): 856 if multi: 857 yield (key, value) 858 elif key not in found: 859 found.add(key) 860 yield (key, value) 861 862 def itervalues(self): 863 for key, value in self.iteritems(): 864 yield value 865 866 def values(self): 867 return list(self.itervalues()) 868 869 def items(self, multi = False): 870 return list(self.iteritems(multi)) 871 872 def iterlists(self): 873 rv = {} 874 for d in self.dicts: 875 for key, values in d.iterlists(): 876 rv.setdefault(key, []).extend(values) 877 878 return rv.iteritems() 879 880 def lists(self): 881 return list(self.iterlists()) 882 883 def iterlistvalues(self): 884 return (x[0] for x in self.lists()) 885 886 def listvalues(self): 887 return list(self.iterlistvalues()) 888 889 def iterkeys(self): 890 return iter(self.keys()) 891 892 __iter__ = iterkeys 893 894 def copy(self): 895 return self.__class__(self.dicts[:]) 896 897 def to_dict(self, flat = True): 898 rv = {} 899 for d in reversed(self.dicts): 900 rv.update(d.to_dict(flat)) 901 902 return rv 903 904 def __len__(self): 905 return len(self.keys()) 906 907 def __contains__(self, key): 908 for d in self.dicts: 909 if key in d: 910 return True 911 912 return False 913 914 has_key = __contains__ 915 916 def __repr__(self): 917 return '%s(%r)' % (self.__class__.__name__, self.dicts) 918 919 920 class FileMultiDict(MultiDict): 921 922 def add_file(self, name, file, filename = None, content_type = None): 923 if isinstance(file, FileStorage): 924 self[name] = file 925 return 926 if isinstance(file, basestring): 927 if filename is None: 928 filename = file 929 file = open(file, 'rb') 930 if filename and content_type is None: 931 content_type = mimetypes.guess_type(filename)[0] or 'application/octet-stream' 932 self[name] = FileStorage(file, filename, name, content_type) 933 934 935 class ImmutableDict(ImmutableDictMixin, dict): 936 __repr__ = _proxy_repr(dict) 937 938 def copy(self): 939 return dict(self) 940 941 def __copy__(self): 942 return self 943 944 945 class ImmutableMultiDict(ImmutableMultiDictMixin, MultiDict): 946 947 def copy(self): 948 return MultiDict(self) 949 950 def __copy__(self): 951 return self 952 953 954 class ImmutableOrderedMultiDict(ImmutableMultiDictMixin, OrderedMultiDict): 955 956 def copy(self): 957 return OrderedMultiDict(self) 958 959 def __copy__(self): 960 return self 961 962 963 class Accept(ImmutableList): 964 965 def __init__(self, values = ()): 966 if values is None: 967 list.__init__(self) 968 self.provided = False 969 elif isinstance(values, Accept): 970 self.provided = values.provided 971 list.__init__(self, values) 972 else: 973 self.provided = True 974 values = [ (a, b) for b, a in values ] 975 values.sort() 976 values.reverse() 977 list.__init__(self, [ (a, b) for b, a in values ]) 978 979 def _value_matches(self, value, item): 980 return item == '*' or item.lower() == value.lower() 981 982 def __getitem__(self, key): 983 if isinstance(key, basestring): 984 return self.quality(key) 985 return list.__getitem__(self, key) 986 987 def quality(self, key): 988 for item, quality in self: 989 if self._value_matches(key, item): 990 return quality 991 992 return 0 993 994 def __contains__(self, value): 995 for item, quality in self: 996 if self._value_matches(value, item): 997 return True 998 999 return False 1000 1001 def __repr__(self): 1002 return '%s([%s])' % (self.__class__.__name__, ', '.join(('(%r, %s)' % (x, y) for x, y in self))) 1003 1004 def index(self, key): 1005 if isinstance(key, basestring): 1006 for idx, (item, quality) in enumerate(self): 1007 if self._value_matches(key, item): 1008 return idx 1009 1010 raise ValueError(key) 1011 return list.index(self, key) 1012 1013 def find(self, key): 1014 try: 1015 return self.index(key) 1016 except ValueError: 1017 return -1 1018 1019 def values(self): 1020 return list(self.itervalues()) 1021 1022 def itervalues(self): 1023 for item in self: 1024 yield item[0] 1025 1026 def to_header(self): 1027 result = [] 1028 for value, quality in self: 1029 if quality != 1: 1030 value = '%s;q=%s' % (value, quality) 1031 result.append(value) 1032 1033 return ','.join(result) 1034 1035 def __str__(self): 1036 return self.to_header() 1037 1038 def best_match(self, matches, default = None): 1039 best_quality = -1 1040 result = default 1041 for server_item in matches: 1042 for client_item, quality in self: 1043 if quality <= best_quality: 1044 break 1045 if self._value_matches(client_item, server_item): 1046 best_quality = quality 1047 result = server_item 1048 1049 return result 1050 1051 @property 1052 def best(self): 1053 if self: 1054 return self[0][0] 1055 1056 1057 class MIMEAccept(Accept): 1058 1059 def _value_matches(self, value, item): 1060 1061 def _normalize(x): 1062 x = x.lower() 1063 return x == '*' and ('*', '*') or x.split('/', 1) 1064 1065 if '/' not in value: 1066 raise ValueError('invalid mimetype %r' % value) 1067 value_type, value_subtype = _normalize(value) 1068 if value_type == '*' and value_subtype != '*': 1069 raise ValueError('invalid mimetype %r' % value) 1070 if '/' not in item: 1071 return False 1072 item_type, item_subtype = _normalize(item) 1073 if item_type == '*' and item_subtype != '*': 1074 return False 1075 return item_type == item_subtype == '*' or value_type == value_subtype == '*' or item_type == value_type and (item_subtype == '*' or value_subtype == '*' or item_subtype == value_subtype) 1076 1077 @property 1078 def accept_html(self): 1079 return 'text/html' in self or 'application/xhtml+xml' in self or self.accept_xhtml 1080 1081 @property 1082 def accept_xhtml(self): 1083 return 'application/xhtml+xml' in self or 'application/xml' in self 1084 1085 1086 class LanguageAccept(Accept): 1087 1088 def _value_matches(self, value, item): 1089 1090 def _normalize(language): 1091 return _locale_delim_re.split(language.lower()) 1092 1093 return item == '*' or _normalize(value) == _normalize(item) 1094 1095 1096 class CharsetAccept(Accept): 1097 1098 def _value_matches(self, value, item): 1099 1100 def _normalize(name): 1101 try: 1102 return codecs.lookup(name).name 1103 except LookupError: 1104 return name.lower() 1105 1106 return item == '*' or _normalize(value) == _normalize(item) 1107 1108 1109 def cache_property(key, empty, type): 1110 return property(lambda x: x._get_cache_value(key, empty, type), lambda x, v: x._set_cache_value(key, v, type), lambda x: x._del_cache_value(key), 'accessor for %r' % key) 1111 1112 1113 class _CacheControl(UpdateDictMixin, dict): 1114 no_cache = cache_property('no-cache', '*', None) 1115 no_store = cache_property('no-store', None, bool) 1116 max_age = cache_property('max-age', -1, int) 1117 no_transform = cache_property('no-transform', None, None) 1118 1119 def __init__(self, values = (), on_update = None): 1120 dict.__init__(self, values or ()) 1121 self.on_update = on_update 1122 self.provided = values is not None 1123 1124 def _get_cache_value(self, key, empty, type): 1125 if type is bool: 1126 return key in self 1127 if key in self: 1128 value = self[key] 1129 if value is None: 1130 return empty 1131 if type is not None: 1132 try: 1133 value = type(value) 1134 except ValueError: 1135 pass 1136 1137 return value 1138 1139 def _set_cache_value(self, key, value, type): 1140 if type is bool: 1141 if value: 1142 self[key] = None 1143 else: 1144 self.pop(key, None) 1145 elif value is None: 1146 self.pop(key) 1147 elif value is True: 1148 self[key] = None 1149 else: 1150 self[key] = value 1151 1152 def _del_cache_value(self, key): 1153 if key in self: 1154 del self[key] 1155 1156 def to_header(self): 1157 return dump_header(self) 1158 1159 def __str__(self): 1160 return self.to_header() 1161 1162 def __repr__(self): 1163 return '<%s %r>' % (self.__class__.__name__, self.to_header()) 1164 1165 1166 class RequestCacheControl(ImmutableDictMixin, _CacheControl): 1167 max_stale = cache_property('max-stale', '*', int) 1168 min_fresh = cache_property('min-fresh', '*', int) 1169 no_transform = cache_property('no-transform', None, None) 1170 only_if_cached = cache_property('only-if-cached', None, bool) 1171 1172 1173 class ResponseCacheControl(_CacheControl): 1174 public = cache_property('public', None, bool) 1175 private = cache_property('private', '*', None) 1176 must_revalidate = cache_property('must-revalidate', None, bool) 1177 proxy_revalidate = cache_property('proxy-revalidate', None, bool) 1178 s_maxage = cache_property('s-maxage', None, None) 1179 1180 1181 _CacheControl.cache_property = staticmethod(cache_property) 1182 1183 class CallbackDict(UpdateDictMixin, dict): 1184 1185 def __init__(self, initial = None, on_update = None): 1186 dict.__init__(self, initial or ()) 1187 self.on_update = on_update 1188 1189 def __repr__(self): 1190 return '<%s %s>' % (self.__class__.__name__, dict.__repr__(self)) 1191 1192 1193 class HeaderSet(object): 1194 1195 def __init__(self, headers = None, on_update = None): 1196 self._headers = list(headers or ()) 1197 self._set = set([ x.lower() for x in self._headers ]) 1198 self.on_update = on_update 1199 1200 def add(self, header): 1201 self.update((header,)) 1202 1203 def remove(self, header): 1204 key = header.lower() 1205 if key not in self._set: 1206 raise KeyError(header) 1207 self._set.remove(key) 1208 for idx, key in enumerate(self._headers): 1209 if key.lower() == header: 1210 del self._headers[idx] 1211 break 1212 1213 if self.on_update is not None: 1214 self.on_update(self) 1215 1216 def update(self, iterable): 1217 inserted_any = False 1218 for header in iterable: 1219 key = header.lower() 1220 if key not in self._set: 1221 self._headers.append(header) 1222 self._set.add(key) 1223 inserted_any = True 1224 1225 if inserted_any and self.on_update is not None: 1226 self.on_update(self) 1227 1228 def discard(self, header): 1229 try: 1230 return self.remove(header) 1231 except KeyError: 1232 pass 1233 1234 def find(self, header): 1235 header = header.lower() 1236 for idx, item in enumerate(self._headers): 1237 if item.lower() == header: 1238 return idx 1239 1240 return -1 1241 1242 def index(self, header): 1243 rv = self.find(header) 1244 if rv < 0: 1245 raise IndexError(header) 1246 return rv 1247 1248 def clear(self): 1249 self._set.clear() 1250 del self._headers[:] 1251 if self.on_update is not None: 1252 self.on_update(self) 1253 1254 def as_set(self, preserve_casing = False): 1255 if preserve_casing: 1256 return set(self._headers) 1257 return set(self._set) 1258 1259 def to_header(self): 1260 return ', '.join(map(quote_header_value, self._headers)) 1261 1262 def __getitem__(self, idx): 1263 return self._headers[idx] 1264 1265 def __delitem__(self, idx): 1266 rv = self._headers.pop(idx) 1267 self._set.remove(rv.lower()) 1268 if self.on_update is not None: 1269 self.on_update(self) 1270 1271 def __setitem__(self, idx, value): 1272 old = self._headers[idx] 1273 self._set.remove(old.lower()) 1274 self._headers[idx] = value 1275 self._set.add(value.lower()) 1276 if self.on_update is not None: 1277 self.on_update(self) 1278 1279 def __contains__(self, header): 1280 return header.lower() in self._set 1281 1282 def __len__(self): 1283 return len(self._set) 1284 1285 def __iter__(self): 1286 return iter(self._headers) 1287 1288 def __nonzero__(self): 1289 return bool(self._set) 1290 1291 def __str__(self): 1292 return self.to_header() 1293 1294 def __repr__(self): 1295 return '%s(%r)' % (self.__class__.__name__, self._headers) 1296 1297 1298 class ETags(object): 1299 1300 def __init__(self, strong_etags = None, weak_etags = None, star_tag = False): 1301 self._strong = frozenset(not star_tag and strong_etags or ()) 1302 self._weak = frozenset(weak_etags or ()) 1303 self.star_tag = star_tag 1304 1305 def as_set(self, include_weak = False): 1306 rv = set(self._strong) 1307 if include_weak: 1308 rv.update(self._weak) 1309 return rv 1310 1311 def is_weak(self, etag): 1312 return etag in self._weak 1313 1314 def contains_weak(self, etag): 1315 return self.is_weak(etag) or self.contains(etag) 1316 1317 def contains(self, etag): 1318 if self.star_tag: 1319 return True 1320 return etag in self._strong 1321 1322 def contains_raw(self, etag): 1323 etag, weak = unquote_etag(etag) 1324 if weak: 1325 return self.contains_weak(etag) 1326 return self.contains(etag) 1327 1328 def to_header(self): 1329 if self.star_tag: 1330 return '*' 1331 return ', '.join([ '"%s"' % x for x in self._strong ] + [ 'w/"%s"' % x for x in self._weak ]) 1332 1333 def __call__(self, etag = None, data = None, include_weak = False): 1334 if [etag, data].count(None) != 1: 1335 raise TypeError('either tag or data required, but at least one') 1336 if etag is None: 1337 etag = generate_etag(data) 1338 if include_weak: 1339 if etag in self._weak: 1340 return True 1341 return etag in self._strong 1342 1343 def __nonzero__(self): 1344 return bool(self.star_tag or self._strong) 1345 1346 def __str__(self): 1347 return self.to_header() 1348 1349 def __iter__(self): 1350 return iter(self._strong) 1351 1352 def __contains__(self, etag): 1353 return self.contains(etag) 1354 1355 def __repr__(self): 1356 return '<%s %r>' % (self.__class__.__name__, str(self)) 1357 1358 1359 class Authorization(ImmutableDictMixin, dict): 1360 1361 def __init__(self, auth_type, data = None): 1362 dict.__init__(self, data or {}) 1363 self.type = auth_type 1364 1365 username = property(lambda x: x.get('username'), doc='\n The username transmitted. This is set for both basic and digest\n auth all the time.') 1366 password = property(lambda x: x.get('password'), doc='\n When the authentication type is basic this is the password\n transmitted by the client, else `None`.') 1367 realm = property(lambda x: x.get('realm'), doc='\n This is the server realm sent back for HTTP digest auth.') 1368 nonce = property(lambda x: x.get('nonce'), doc='\n The nonce the server sent for digest auth, sent back by the client.\n A nonce should be unique for every 401 response for HTTP digest\n auth.') 1369 uri = property(lambda x: x.get('uri'), doc='\n The URI from Request-URI of the Request-Line; duplicated because\n proxies are allowed to change the Request-Line in transit. HTTP\n digest auth only.') 1370 nc = property(lambda x: x.get('nc'), doc='\n The nonce count value transmitted by clients if a qop-header is\n also transmitted. HTTP digest auth only.') 1371 cnonce = property(lambda x: x.get('cnonce'), doc='\n If the server sent a qop-header in the ``WWW-Authenticate``\n header, the client has to provide this value for HTTP digest auth.\n See the RFC for more details.') 1372 response = property(lambda x: x.get('response'), doc='\n A string of 32 hex digits computed as defined in RFC 2617, which\n proves that the user knows a password. Digest auth only.') 1373 opaque = property(lambda x: x.get('opaque'), doc='\n The opaque header from the server returned unchanged by the client.\n It is recommended that this string be base64 or hexadecimal data.\n Digest auth only.') 1374 1375 @property 1376 def qop(self): 1377 1378 def on_update(header_set): 1379 if not header_set and 'qop' in self: 1380 del self['qop'] 1381 elif header_set: 1382 self['qop'] = header_set.to_header() 1383 1384 return parse_set_header(self.get('qop'), on_update) 1385 1386 1387 class WWWAuthenticate(UpdateDictMixin, dict): 1388 _require_quoting = frozenset(['domain', 1389 'nonce', 1390 'opaque', 1391 'realm']) 1392 1393 def __init__(self, auth_type = None, values = None, on_update = None): 1394 dict.__init__(self, values or ()) 1395 if auth_type: 1396 self['__auth_type__'] = auth_type 1397 self.on_update = on_update 1398 1399 def set_basic(self, realm = 'authentication required'): 1400 dict.clear(self) 1401 dict.update(self, {'__auth_type__': 'basic', 1402 'realm': realm}) 1403 if self.on_update: 1404 self.on_update(self) 1405 1406 def set_digest(self, realm, nonce, qop = ('auth',), opaque = None, algorithm = None, stale = False): 1407 d = {'__auth_type__': 'digest', 1408 'realm': realm, 1409 'nonce': nonce, 1410 'qop': dump_header(qop)} 1411 if stale: 1412 d['stale'] = 'TRUE' 1413 if opaque is not None: 1414 d['opaque'] = opaque 1415 if algorithm is not None: 1416 d['algorithm'] = algorithm 1417 dict.clear(self) 1418 dict.update(self, d) 1419 if self.on_update: 1420 self.on_update(self) 1421 1422 def to_header(self): 1423 d = dict(self) 1424 auth_type = d.pop('__auth_type__', None) or 'basic' 1425 return '%s %s' % (auth_type.title(), ', '.join([ '%s=%s' % (key, quote_header_value(value, allow_token=key not in self._require_quoting)) for key, value in d.iteritems() ])) 1426 1427 def __str__(self): 1428 return self.to_header() 1429 1430 def __repr__(self): 1431 return '<%s %r>' % (self.__class__.__name__, self.to_header()) 1432 1433 def auth_property(name, doc = None): 1434 1435 def _set_value(self, value): 1436 if value is None: 1437 self.pop(name, None) 1438 else: 1439 self[name] = str(value) 1440 1441 return property(lambda x: x.get(name), _set_value, doc=doc) 1442 1443 def _set_property(name, doc = None): 1444 1445 def fget(self): 1446 1447 def on_update(header_set): 1448 if not header_set and name in self: 1449 del self[name] 1450 elif header_set: 1451 self[name] = header_set.to_header() 1452 1453 return parse_set_header(self.get(name), on_update) 1454 1455 return property(fget, doc=doc) 1456 1457 type = auth_property('__auth_type__', doc='\n The type of the auth mechanism. HTTP currently specifies\n `Basic` and `Digest`.') 1458 realm = auth_property('realm', doc='\n A string to be displayed to users so they know which username and\n password to use. This string should contain at least the name of\n the host performing the authentication and might additionally\n indicate the collection of users who might have access.') 1459 domain = _set_property('domain', doc='\n A list of URIs that define the protection space. If a URI is an\n absolute path, it is relative to the canonical root URL of the\n server being accessed.') 1460 nonce = auth_property('nonce', doc='\n A server-specified data string which should be uniquely generated\n each time a 401 response is made. It is recommended that this\n string be base64 or hexadecimal data.') 1461 opaque = auth_property('opaque', doc='\n A string of data, specified by the server, which should be returned\n by the client unchanged in the Authorization header of subsequent\n requests with URIs in the same protection space. It is recommended\n that this string be base64 or hexadecimal data.') 1462 algorithm = auth_property('algorithm', doc='\n A string indicating a pair of algorithms used to produce the digest\n and a checksum. If this is not present it is assumed to be "MD5".\n If the algorithm is not understood, the challenge should be ignored\n (and a different one used, if there is more than one).') 1463 qop = _set_property('qop', doc='\n A set of quality-of-privacy directives such as auth and auth-int.') 1464 1465 def _get_stale(self): 1466 val = self.get('stale') 1467 if val is not None: 1468 return val.lower() == 'true' 1469 1470 def _set_stale(self, value): 1471 if value is None: 1472 self.pop('stale', None) 1473 else: 1474 self['stale'] = value and 'TRUE' or 'FALSE' 1475 1476 stale = property(_get_stale, _set_stale, doc='\n A flag, indicating that the previous request from the client was\n rejected because the nonce value was stale.') 1477 del _get_stale 1478 del _set_stale 1479 auth_property = staticmethod(auth_property) 1480 del _set_property 1481 1482 1483 class FileStorage(object): 1484 1485 def __init__(self, stream = None, filename = None, name = None, content_type = 'application/octet-stream', content_length = -1, headers = None): 1486 self.name = name 1487 self.stream = stream or _empty_stream 1488 self.filename = filename or getattr(stream, 'name', None) 1489 self.content_type = content_type 1490 self.content_length = content_length 1491 if headers is None: 1492 headers = Headers() 1493 self.headers = headers 1494 1495 def save(self, dst, buffer_size = 16384): 1496 from shutil import copyfileobj 1497 close_dst = False 1498 if isinstance(dst, basestring): 1499 dst = file(dst, 'wb') 1500 close_dst = True 1501 try: 1502 copyfileobj(self.stream, dst, buffer_size) 1503 finally: 1504 if close_dst: 1505 dst.close() 1506 1507 def close(self): 1508 try: 1509 self.stream.close() 1510 except: 1511 pass 1512 1513 def __nonzero__(self): 1514 return bool(self.filename) 1515 1516 def __getattr__(self, name): 1517 return getattr(self.stream, name) 1518 1519 def __iter__(self): 1520 return iter(self.readline, '') 1521 1522 def __repr__(self): 1523 return '<%s: %r (%r)>' % (self.__class__.__name__, self.filename, self.content_type) 1524 1525 1526 from werkzeug.http import dump_options_header, dump_header, generate_etag, quote_header_value, parse_set_header, unquote_etag 1527 from werkzeug.exceptions import BadRequest 1528 for _cls in (MultiDict, 1529 OrderedMultiDict, 1530 CombinedMultiDict, 1531 Headers, 1532 EnvironHeaders): 1533 _cls.KeyError = BadRequest.wrap(KeyError, _cls.__name__ + '.KeyError') 1534 1535 del _cls