aboutsummaryrefslogtreecommitdiffstats
path: root/libmproxy/stateobject.py
diff options
context:
space:
mode:
Diffstat (limited to 'libmproxy/stateobject.py')
-rw-r--r--libmproxy/stateobject.py103
1 files changed, 38 insertions, 65 deletions
diff --git a/libmproxy/stateobject.py b/libmproxy/stateobject.py
index 6fb73c24..53ccef0e 100644
--- a/libmproxy/stateobject.py
+++ b/libmproxy/stateobject.py
@@ -1,78 +1,51 @@
from __future__ import absolute_import
-class StateObject(object):
- def _get_state(self):
- raise NotImplementedError # pragma: nocover
-
- def _load_state(self, state):
- raise NotImplementedError # pragma: nocover
-
- @classmethod
- def _from_state(cls, state):
- raise NotImplementedError # pragma: nocover
- # Usually, this function roughly equals to the following code:
- # f = cls()
- # f._load_state(state)
- # return f
-
- def __eq__(self, other):
- try:
- return self._get_state() == other._get_state()
- except AttributeError: # we may compare with something that's not a StateObject
- return False
-
- def __ne__(self, other):
- return not self.__eq__(other)
-
-
-class SimpleStateObject(StateObject):
- """
- A StateObject with opionated conventions that tries to keep everything DRY.
- Simply put, you agree on a list of attributes and their type.
- Attributes can either be primitive types(str, tuple, bool, ...) or StateObject instances themselves.
- SimpleStateObject uses this information for the default _get_state(), _from_state(s) and _load_state(s) methods.
- Overriding _get_state or _load_state to add custom adjustments is always possible.
+class StateObject(object):
"""
+ An object with serializable state.
- _stateobject_attributes = None # none by default to raise an exception if definition was forgotten
- """
- An attribute-name -> class-or-type dict containing all attributes that should be serialized
- If the attribute is a class, this class must be a subclass of StateObject.
+ State attributes can either be serializable types(str, tuple, bool, ...)
+ or StateObject instances themselves.
"""
+ # An attribute-name -> class-or-type dict containing all attributes that
+ # should be serialized. If the attribute is a class, it must implement the
+ # StateObject protocol.
+ _stateobject_attributes = None
+ # A set() of attributes that should be ignored for short state
+ _stateobject_long_attributes = frozenset([])
- def _get_state(self):
- return {attr: self._get_state_attr(attr, cls)
- for attr, cls in self._stateobject_attributes.iteritems()}
+ def from_state(self, state):
+ raise NotImplementedError()
- def _get_state_attr(self, attr, cls):
+ def get_state(self, short=False):
"""
- helper for _get_state.
- returns the value of the given attribute
+ Retrieve object state. If short is true, return an abbreviated
+ format with long data elided.
"""
- val = getattr(self, attr)
- if hasattr(val, "_get_state"):
- return val._get_state()
- else:
- return val
-
- def _load_state(self, state):
+ state = {}
for attr, cls in self._stateobject_attributes.iteritems():
- self._load_state_attr(attr, cls, state)
-
- def _load_state_attr(self, attr, cls, state):
+ if short and attr in self._stateobject_long_attributes:
+ continue
+ val = getattr(self, attr)
+ if hasattr(val, "get_state"):
+ state[attr] = val.get_state(short)
+ else:
+ state[attr] = val
+ return state
+
+ def load_state(self, state):
"""
- helper for _load_state.
- loads the given attribute from the state.
+ Load object state from data returned by a get_state call.
"""
- if state.get(attr, None) is None:
- setattr(self, attr, None)
- return
-
- curr = getattr(self, attr)
- if hasattr(curr, "_load_state"):
- curr._load_state(state[attr])
- elif hasattr(cls, "_from_state"):
- setattr(self, attr, cls._from_state(state[attr]))
- else:
- setattr(self, attr, cls(state[attr])) \ No newline at end of file
+ for attr, cls in self._stateobject_attributes.iteritems():
+ if state.get(attr, None) is None:
+ setattr(self, attr, None)
+ else:
+ curr = getattr(self, attr)
+ if hasattr(curr, "load_state"):
+ curr.load_state(state[attr])
+ elif hasattr(cls, "from_state"):
+ setattr(self, attr, cls.from_state(state[attr]))
+ else:
+ setattr(self, attr, cls(state[attr]))