diff options
| author | Santiago Basulto <santiago.basulto@gmail.com> | 2018-05-04 20:37:01 -0300 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2019-01-16 13:38:47 -0500 |
| commit | 4fc35a9c3efdc9154efce28cb23cb84f8834517e (patch) | |
| tree | a4f7b10244cb933d827cf72ef57dc11e68c1a6ca /django/utils/datastructures.py | |
| parent | aa5d0a5a90a690dc6f8fdbbffba143e32c86e40a (diff) | |
Fixed #20147 -- Added HttpRequest.headers.
Diffstat (limited to 'django/utils/datastructures.py')
| -rw-r--r-- | django/utils/datastructures.py | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/django/utils/datastructures.py b/django/utils/datastructures.py index c5bda0056a..191c2348f6 100644 --- a/django/utils/datastructures.py +++ b/django/utils/datastructures.py @@ -1,5 +1,6 @@ import copy from collections import OrderedDict +from collections.abc import Mapping class OrderedSet: @@ -280,3 +281,61 @@ class DictWrapper(dict): if use_func: return self.func(value) return value + + +def _destruct_iterable_mapping_values(data): + for i, elem in enumerate(data): + if len(elem) != 2: + raise ValueError( + 'dictionary update sequence element #{} has ' + 'length {}; 2 is required.'.format(i, len(elem)) + ) + if not isinstance(elem[0], str): + raise ValueError('Element key %r invalid, only strings are allowed' % elem[0]) + yield tuple(elem) + + +class CaseInsensitiveMapping(Mapping): + """ + Mapping allowing case-insensitive key lookups. Original case of keys is + preserved for iteration and string representation. + + Example:: + + >>> ci_map = CaseInsensitiveMapping({'name': 'Jane'}) + >>> ci_map['Name'] + Jane + >>> ci_map['NAME'] + Jane + >>> ci_map['name'] + Jane + >>> ci_map # original case preserved + {'name': 'Jane'} + """ + + def __init__(self, data): + if not isinstance(data, Mapping): + data = {k: v for k, v in _destruct_iterable_mapping_values(data)} + self._store = {k.lower(): (k, v) for k, v in data.items()} + + def __getitem__(self, key): + return self._store[key.lower()][1] + + def __len__(self): + return len(self._store) + + def __eq__(self, other): + return isinstance(other, Mapping) and { + k.lower(): v for k, v in self.items() + } == { + k.lower(): v for k, v in other.items() + } + + def __iter__(self): + return (original_key for original_key, value in self._store.values()) + + def __repr__(self): + return repr({key: value for key, value in self._store.values()}) + + def copy(self): + return self |
