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