summaryrefslogtreecommitdiff
path: root/django/utils/datastructures.py
diff options
context:
space:
mode:
authorSantiago Basulto <santiago.basulto@gmail.com>2018-05-04 20:37:01 -0300
committerTim Graham <timograham@gmail.com>2019-01-16 13:38:47 -0500
commit4fc35a9c3efdc9154efce28cb23cb84f8834517e (patch)
treea4f7b10244cb933d827cf72ef57dc11e68c1a6ca /django/utils/datastructures.py
parentaa5d0a5a90a690dc6f8fdbbffba143e32c86e40a (diff)
Fixed #20147 -- Added HttpRequest.headers.
Diffstat (limited to 'django/utils/datastructures.py')
-rw-r--r--django/utils/datastructures.py59
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