aboutsummaryrefslogtreecommitdiffstats
path: root/netlib/multidict.py
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@nullcube.com>2016-05-21 11:37:36 +1200
committerAldo Cortesi <aldo@nullcube.com>2016-05-21 11:37:36 +1200
commita5c4cd034081d7dcdbd4b46bd69718edb45d4719 (patch)
tree52accc866d25c735e6c36f05255bb3f5349f8ac7 /netlib/multidict.py
parent96d8ec1ee33b076a472afc3053fdd8256559fcc3 (diff)
downloadmitmproxy-a5c4cd034081d7dcdbd4b46bd69718edb45d4719.tar.gz
mitmproxy-a5c4cd034081d7dcdbd4b46bd69718edb45d4719.tar.bz2
mitmproxy-a5c4cd034081d7dcdbd4b46bd69718edb45d4719.zip
A clearer implementation of MultiDictView
This makes MultiDictView work with a simple getter/setter pair, rather than using attributes with implicit leading underscores. Also move MultiDictView into multidict.py and adds some simple unit tests.
Diffstat (limited to 'netlib/multidict.py')
-rw-r--r--netlib/multidict.py49
1 files changed, 40 insertions, 9 deletions
diff --git a/netlib/multidict.py b/netlib/multidict.py
index a359d46b..3af7979b 100644
--- a/netlib/multidict.py
+++ b/netlib/multidict.py
@@ -15,13 +15,7 @@ from .utils import Serializable
@six.add_metaclass(ABCMeta)
-class MultiDict(MutableMapping, Serializable):
- def __init__(self, fields=None):
-
- # it is important for us that .fields is immutable, so that we can easily
- # detect changes to it.
- self.fields = tuple(fields) if fields else tuple() # type: Tuple[Tuple[bytes, bytes], ...]
-
+class _MultiDict(MutableMapping, Serializable):
def __repr__(self):
fields = tuple(
repr(field)
@@ -97,7 +91,7 @@ class MultiDict(MutableMapping, Serializable):
value
for k, value in self.fields
if self._kconv(k) == key
- ]
+ ]
def set_all(self, key, values):
"""
@@ -173,7 +167,7 @@ class MultiDict(MutableMapping, Serializable):
if multi:
return self.fields
else:
- return super(MultiDict, self).items()
+ return super(_MultiDict, self).items()
def to_dict(self):
"""
@@ -213,6 +207,12 @@ class MultiDict(MutableMapping, Serializable):
return cls(tuple(x) for x in state)
+class MultiDict(_MultiDict):
+ def __init__(self, fields=None):
+ super(MultiDict, self).__init__()
+ self.fields = tuple(fields) if fields else tuple() # type: Tuple[Tuple[bytes, bytes], ...]
+
+
@six.add_metaclass(ABCMeta)
class ImmutableMultiDict(MultiDict):
def _immutable(self, *_):
@@ -246,3 +246,34 @@ class ImmutableMultiDict(MultiDict):
ret = self.copy()
super(ImmutableMultiDict, ret).insert(index, key, value)
return ret
+
+
+class MultiDictView(_MultiDict):
+ """
+ The MultiDictView provides the MultiDict interface over calculated data.
+ The view itself contains no state - data is retrieved from the parent on
+ request, and stored back to the parent on change.
+ """
+ def __init__(self, getter, setter):
+ self._getter = getter
+ self._setter = setter
+ super(MultiDictView, self).__init__()
+
+ @staticmethod
+ def _kconv(key):
+ # All request-attributes are case-sensitive.
+ return key
+
+ @staticmethod
+ def _reduce_values(values):
+ # We just return the first element if
+ # multiple elements exist with the same key.
+ return values[0]
+
+ @property
+ def fields(self):
+ return self._getter()
+
+ @fields.setter
+ def fields(self, value):
+ return self._setter(value)