add __setstate__ to loads from a serialised object

This commit is contained in:
Emmanuel Garette 2013-09-02 23:04:37 +02:00
parent cc3a33ef4f
commit 0212a15387
1 changed files with 100 additions and 30 deletions

View File

@ -98,7 +98,7 @@ class BaseOption(BaseInformation):
""" """
__slots__ = ('_name', '_requires', '_properties', '_readonly', __slots__ = ('_name', '_requires', '_properties', '_readonly',
'_consistencies', '_calc_properties', '_state_consistencies', '_consistencies', '_calc_properties', '_state_consistencies',
'_state_requires', '_stated') '_state_readonly', '_state_requires', '_stated')
def __init__(self, name, doc, requires, properties): def __init__(self, name, doc, requires, properties):
if not valid_name(name): if not valid_name(name):
@ -133,7 +133,7 @@ class BaseOption(BaseInformation):
"frozen" (which has noting to do with the high level "freeze" "frozen" (which has noting to do with the high level "freeze"
propertie or "read_only" property) propertie or "read_only" property)
""" """
if not name.startswith('_state'): if not name.startswith('_state') and name not in ('_cache_paths', '_consistencies'):
is_readonly = False is_readonly = False
# never change _name # never change _name
if name == '_name': if name == '_name':
@ -160,42 +160,58 @@ class BaseOption(BaseInformation):
name)) name))
object.__setattr__(self, name, value) object.__setattr__(self, name, value)
def _impl_convert_consistencies(self, cache): def _impl_convert_consistencies(self, descr, load=False):
# cache is a dico in import/not a dico in export if not load and self._consistencies is None:
if self._consistencies is None:
self._state_consistencies = None self._state_consistencies = None
elif load and self._state_consistencies is None:
self._consistencies = None
del(self._state_consistencies)
else: else:
if load:
consistencies = self._state_consistencies
else:
consistencies = self._consistencies
new_value = [] new_value = []
for consistency in self._consistencies: for consistency in consistencies:
if isinstance(cache, dict): if load:
new_value.append((consistency[0], cache[consistency[1]])) new_value.append((consistency[0],
descr.impl_get_opt_by_path(
consistency[1])))
else: else:
new_value.append((consistency[0], new_value.append((consistency[0],
cache.impl_get_path_by_opt( descr.impl_get_path_by_opt(
consistency[1]))) consistency[1])))
if isinstance(cache, dict): if load:
pass del(self._state_consistencies)
self._consistencies = tuple(new_value)
else: else:
self._state_consistencies = tuple(new_value) self._state_consistencies = tuple(new_value)
def _impl_convert_requires(self, cache): def _impl_convert_requires(self, descr, load=False):
# cache is a dico in import/not a dico in export if not load and self._requires is None:
if self._requires is None:
self._state_requires = None self._state_requires = None
elif load and self._state_requires is None:
self._requires = None
del(self._state_requires)
else: else:
if load:
_requires = self._state_requires
else:
_requires = self._requires
new_value = [] new_value = []
for requires in self._requires: for requires in _requires:
new_requires = [] new_requires = []
for require in requires: for require in requires:
if isinstance(cache, dict): if load:
new_require = [cache[require[0]]] new_require = [descr.impl_get_opt_by_path(require[0])]
else: else:
new_require = [cache.impl_get_path_by_opt(require[0])] new_require = [descr.impl_get_path_by_opt(require[0])]
new_require.extend(require[1:]) new_require.extend(require[1:])
new_requires.append(tuple(new_require)) new_requires.append(tuple(new_require))
new_value.append(tuple(new_requires)) new_value.append(tuple(new_requires))
if isinstance(cache, dict): if load:
pass del(self._state_requires)
self._requires = new_value
else: else:
self._state_requires = new_value self._state_requires = new_value
@ -203,8 +219,12 @@ class BaseOption(BaseInformation):
self._stated = True self._stated = True
self._impl_convert_consistencies(descr) self._impl_convert_consistencies(descr)
self._impl_convert_requires(descr) self._impl_convert_requires(descr)
try:
self._state_readonly = self._readonly
except AttributeError:
pass
def __getstate__(self, export=False): def __getstate__(self, stated=True):
try: try:
self._stated self._stated
except AttributeError: except AttributeError:
@ -228,8 +248,24 @@ class BaseOption(BaseInformation):
states[slot] = getattr(self, slot) states[slot] = getattr(self, slot)
except AttributeError: except AttributeError:
pass pass
if not stated:
del(states['_stated'])
return states return states
def _impl_setstate(self, descr):
self._impl_convert_consistencies(descr, load=True)
self._impl_convert_requires(descr, load=True)
try:
self._readonly = self._state_readonly
del(self._state_readonly)
del(self._stated)
except AttributeError:
pass
def __setstate__(self, state):
for key, value in state.items():
setattr(self, key, value)
class Option(BaseOption): class Option(BaseOption):
""" """
@ -596,6 +632,11 @@ class SymLinkOption(BaseOption):
super(SymLinkOption, self)._impl_getstate(descr) super(SymLinkOption, self)._impl_getstate(descr)
self._state_opt = descr.impl_get_path_by_opt(self._opt) self._state_opt = descr.impl_get_path_by_opt(self._opt)
def _impl_setstate(self, descr):
self._opt = descr.impl_get_opt_by_path(self._state_opt)
del(self._state_opt)
super(SymLinkOption, self)._impl_setstate(descr)
class IPOption(Option): class IPOption(Option):
"represents the choice of an ip" "represents the choice of an ip"
@ -885,14 +926,16 @@ class OptionDescription(BaseOption):
cache_path=None, cache_path=None,
cache_option=None, cache_option=None,
_currpath=None, _currpath=None,
_consistencies=None): _consistencies=None,
force_no_consistencies=False):
if _currpath is None and self._cache_paths is not None: if _currpath is None and self._cache_paths is not None:
# cache already set # cache already set
return return
if _currpath is None: if _currpath is None:
save = True save = True
_currpath = [] _currpath = []
_consistencies = {} if not force_no_consistencies:
_consistencies = {}
else: else:
save = False save = False
if cache_path is None: if cache_path is None:
@ -904,10 +947,12 @@ class OptionDescription(BaseOption):
raise ConflictError(_('duplicate option: {0}').format(option)) raise ConflictError(_('duplicate option: {0}').format(option))
cache_option.append(option) cache_option.append(option)
option._readonly = True if not force_no_consistencies:
option._readonly = True
cache_path.append(str('.'.join(_currpath + [attr]))) cache_path.append(str('.'.join(_currpath + [attr])))
if not isinstance(option, OptionDescription): if not isinstance(option, OptionDescription):
if option._consistencies is not None: if not force_no_consistencies and \
option._consistencies is not None:
for consistency in option._consistencies: for consistency in option._consistencies:
func, opt = consistency func, opt = consistency
opts = (option, opt) opts = (option, opt)
@ -920,12 +965,14 @@ class OptionDescription(BaseOption):
option.impl_build_cache(cache_path, option.impl_build_cache(cache_path,
cache_option, cache_option,
_currpath, _currpath,
_consistencies) _consistencies,
force_no_consistencies)
_currpath.pop() _currpath.pop()
if save: if save:
self._cache_paths = (tuple(cache_option), tuple(cache_path)) self._cache_paths = (tuple(cache_option), tuple(cache_path))
self._consistencies = _consistencies if not force_no_consistencies:
self._readonly = True self._consistencies = _consistencies
self._readonly = True
def impl_get_opt_by_path(self, path): def impl_get_opt_by_path(self, path):
try: try:
@ -1023,15 +1070,38 @@ class OptionDescription(BaseOption):
option._impl_getstate(descr) option._impl_getstate(descr)
def __getstate__(self): def __getstate__(self):
stated = True
try: try:
del(self._stated) self._stated
except AttributeError: except AttributeError:
# if cannot delete, _impl_getstate never launch # if cannot delete, _impl_getstate never launch
# launch it recursivement # launch it recursivement
# _stated prevent __getstate__ launch more than one time # _stated prevent __getstate__ launch more than one time
# _stated is delete, if re-serialize, re-lauch _impl_getstate # _stated is delete, if re-serialize, re-lauch _impl_getstate
self._impl_getstate() self._impl_getstate()
return super(OptionDescription, self).__getstate__() stated = False
return super(OptionDescription, self).__getstate__(stated)
def _impl_setstate(self, descr=None):
"""enables us to import from a dict
:param descr: parent :class:`tiramisu.option.OptionDescription`
"""
if descr is None:
self._cache_paths = None
self.impl_build_cache(force_no_consistencies=True)
descr = self
self._group_type = getattr(groups, self._state_group_type)
del(self._state_group_type)
super(OptionDescription, self)._impl_setstate(descr)
for option in self.impl_getchildren():
option._impl_setstate(descr)
def __setstate__(self, state):
super(OptionDescription, self).__setstate__(state)
try:
self._stated
except AttributeError:
self._impl_setstate()
def validate_requires_arg(requires, name): def validate_requires_arg(requires, name):