From 2c1da6d72ed4b04a6db943d4f2cb436597935530 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Mon, 2 Sep 2013 15:01:49 +0200 Subject: [PATCH] an OptionDescription can be serialized --- tiramisu/option.py | 187 ++++++++++++++++++++++++--------------------- 1 file changed, 102 insertions(+), 85 deletions(-) diff --git a/tiramisu/option.py b/tiramisu/option.py index 7f457a3..4327938 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -92,82 +92,100 @@ class BaseInformation(object): class BaseOption(BaseInformation): - __slots__ = ('_readonly',) + __slots__ = ('_readonly', '_state_consistencies', '_state_requires') def __setattr__(self, name, value): - is_readonly = False - # never change _name - if name == '_name': + if not name.startswith('_state'): + is_readonly = False + # never change _name + if name == '_name': + try: + self._name + #so _name is already set + is_readonly = True + except: + pass try: - self._name - #so _name is already set - is_readonly = True - except: + if self._readonly is True: + if value is True: + # already readonly and try to re set readonly + # don't raise, just exit + return + is_readonly = True + except AttributeError: pass - try: - if self._readonly is True: - if value is True: - # already readonly and try to re set readonly - # don't raise, just exit - return - is_readonly = True - except AttributeError: - pass - if is_readonly: - raise AttributeError(_("'{0}' ({1}) object attribute '{2}' is" - " read-only").format( - self.__class__.__name__, self._name, - name)) + if is_readonly: + raise AttributeError(_("'{0}' ({1}) object attribute '{2}' is" + " read-only").format( + self.__class__.__name__, + self._name, + name)) object.__setattr__(self, name, value) - def _impl_convert_consistencies(self, value, cache): + def _impl_convert_consistencies(self, cache): # cache is a dico in import/not a dico in export - new_value = [] - for consistency in value: - if isinstance(cache, dict): - new_value = (consistency[0], cache[consistency[1]]) - else: - new_value = (consistency[0], cache.impl_get_path_by_opt( - consistency[1])) - return tuple(new_value) - - def _impl_convert_requires(self, value, cache): - # cache is a dico in import/not a dico in export - new_value = [] - for requires in value: - new_requires = [] - for require in requires: + if self._consistencies is None: + self._state_consistencies = None + else: + new_value = [] + for consistency in self._consistencies: if isinstance(cache, dict): - new_require = [cache[require[0]]] + new_value.append((consistency[0], cache[consistency[1]])) else: - new_require = [cache.impl_get_path_by_opt(require[0])] - new_require.extend(require[1:]) - new_requires.append(tuple(new_require)) - new_value.append(tuple(new_requires)) - return tuple(new_value) + new_value.append((consistency[0], + cache.impl_get_path_by_opt( + consistency[1]))) + if isinstance(cache, dict): + pass + else: + self._state_consistencies = tuple(new_value) - def impl_export(self, descr): - descr.impl_build_cache() - # add _opt_type (not in __slots__) - slots = set(['_opt_type']) + def _impl_convert_requires(self, cache): + # cache is a dico in import/not a dico in export + if self._requires is None: + self._state_requires = None + else: + new_value = [] + for requires in self._requires: + new_requires = [] + for require in requires: + if isinstance(cache, dict): + new_require = [cache[require[0]]] + else: + new_require = [cache.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 + else: + self._state_requires = new_value + + def _impl_getstate(self, descr): + self._impl_convert_consistencies(descr) + self._impl_convert_requires(descr) + + def __getstate__(self, export=False): + slots = set() for subclass in self.__class__.__mro__: if subclass is not object: slots.update(subclass.__slots__) - slots -= frozenset(['_children', '_readonly', '_cache_paths', - '__weakref__']) - exported_object = {} - for attr in slots: - try: - value = getattr(self, attr) - if value is not None: - if attr == '_consistencies': - value = self._impl_convert_consistencies(value, descr) - elif attr == '_requires': - value = self._impl_convert_requires(value, descr) - exported_object[attr] = value - except AttributeError: - pass - return exported_object + slots -= frozenset(['_children', '_cache_paths', '__weakref__']) + states = {} + for slot in slots: + # remove variable if save variable converted in _state_xxxx variable + if '_state' + slot not in slots: + if slot.startswith('_state'): + # should exists + states[slot] = getattr(self, slot) + # remove _state_xxx variable + self.__delattr__(slot) + else: + try: + states[slot] = getattr(self, slot) + except AttributeError: + pass + return states class Option(BaseOption): @@ -530,7 +548,7 @@ else: class SymLinkOption(BaseOption): - __slots__ = ('_name', '_opt') + __slots__ = ('_name', '_opt', '_state_opt') _opt_type = 'symlink' def __init__(self, name, opt): @@ -548,11 +566,9 @@ class SymLinkOption(BaseOption): else: return getattr(self._opt, name) - def impl_export(self, descr): - export = super(SymLinkOption, self).impl_export(descr) - export['_opt'] = descr.impl_get_path_by_opt(self._opt) - del(export['_impl_informations']) - return export + def _impl_getstate(self, descr): + super(SymLinkOption, self)._impl_getstate(descr) + self._state_opt = descr.impl_get_path_by_opt(self._opt) class IPOption(Option): @@ -774,8 +790,9 @@ class OptionDescription(BaseOption): The `OptionsDescription` objects lives in the `tiramisu.config.Config`. """ __slots__ = ('_name', '_requires', '_cache_paths', '_group_type', - '_properties', '_children', '_consistencies', - '_calc_properties', '__weakref__', '_readonly', '_impl_informations') + '_state_group_type', '_properties', '_children', + '_consistencies', '_calc_properties', '__weakref__', + '_readonly', '_impl_informations') _opt_type = 'optiondescription' def __init__(self, name, doc, children, requires=None, properties=None): @@ -980,23 +997,23 @@ class OptionDescription(BaseOption): return False return True - def _impl_convert_group_type(self, value, cache): - if isinstance(cache, dict): - value = str(value) - else: - value = getattr(groups, value) - return value - - def impl_export(self, descr=None): + def _impl_getstate(self, descr=None): if descr is None: + self.impl_build_cache() descr = self - export = super(OptionDescription, self).impl_export(descr) - export['_group_type'] = self._impl_convert_group_type( - export['_group_type'], descr) - export['options'] = [] + super(OptionDescription, self)._impl_getstate(descr) + self._state_group_type = str(self._group_type) for option in self.impl_getchildren(): - export['options'].append(option.impl_export(descr)) - return export + option._impl_getstate(descr) + + def __getstate__(self, export=False): + if not export: + self._impl_getstate() + states = super(OptionDescription, self).__getstate__(True) + states['_state_children'] = [] + for option in self.impl_getchildren(): + states['_state_children'].append(option.__getstate__(True)) + return states def validate_requires_arg(requires, name):