an OptionDescription can be serialized
authorEmmanuel Garette <egarette@cadoles.com>
Mon, 2 Sep 2013 13:01:49 +0000 (15:01 +0200)
committerEmmanuel Garette <egarette@cadoles.com>
Mon, 2 Sep 2013 13:01:49 +0000 (15:01 +0200)
tiramisu/option.py

index 7f457a3..4327938 100644 (file)
@@ -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 self._consistencies is None:
+            self._state_consistencies = None
+        else:
+            new_value = []
+            for consistency in self._consistencies:
+                if isinstance(cache, dict):
+                    new_value.append((consistency[0], cache[consistency[1]]))
+                else:
+                    new_value.append((consistency[0],
+                                      cache.impl_get_path_by_opt(
+                                          consistency[1])))
             if isinstance(cache, dict):
-                new_value = (consistency[0], cache[consistency[1]])
+                pass
             else:
-                new_value = (consistency[0], cache.impl_get_path_by_opt(
-                    consistency[1]))
-        return tuple(new_value)
+                self._state_consistencies = tuple(new_value)
 
-    def _impl_convert_requires(self, value, cache):
+    def _impl_convert_requires(self, 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 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))
-        return tuple(new_value)
-
-    def impl_export(self, descr):
-        descr.impl_build_cache()
-        # add _opt_type (not in __slots__)
-        slots = set(['_opt_type'])
+        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():
+            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():
-            export['options'].append(option.impl_export(descr))
-        return export
+            states['_state_children'].append(option.__getstate__(True))
+        return states
 
 
 def validate_requires_arg(requires, name):