serialize new callback
authorEmmanuel Garette <egarette@cadoles.com>
Fri, 20 Sep 2013 21:47:40 +0000 (23:47 +0200)
committerEmmanuel Garette <egarette@cadoles.com>
Fri, 20 Sep 2013 21:47:40 +0000 (23:47 +0200)
test/test_state.py
tiramisu/option.py

index 03ab670..ea1956c 100644 (file)
@@ -3,6 +3,10 @@ from tiramisu.option import BoolOption, UnicodeOption, SymLinkOption, \
 from pickle import dumps, loads
 
 
+def return_value(value=None):
+        return value
+
+
 def _get_slots(opt):
     slots = set()
     for subclass in opt.__class__.__mro__:
@@ -65,6 +69,18 @@ def _diff_opt(opt1, opt2):
                 for index, consistency in enumerate(val1):
                     assert consistency[0] == val2[index][0]
                     assert consistency[1]._name == val2[index][1]._name
+        elif attr == '_callback':
+            assert val1[0] == val2[0]
+            if val1[1] is not None:
+                for key, values in val1[1].items():
+                    for idx, value in enumerate(values):
+                        if isinstance(value, tuple):
+                            assert val1[1][key][idx][0]._name == val2[1][key][idx][0]._name
+                            assert val1[1][key][idx][1] == val2[1][key][idx][1]
+                        else:
+                            assert val1[1][key][idx] == val2[1][key][idx]
+            else:
+                assert val1[1] == val2[1]
         else:
             assert val1 == val2
 
@@ -104,6 +120,23 @@ def test_diff_opt_cache():
     _diff_opt(o1.o.s, q.o.s)
 
 
+def test_diff_opt_callback():
+    b = BoolOption('b', '', callback=return_value)
+    b2 = BoolOption('b2', '', callback=return_value, callback_params={'': ('yes',)})
+    b3 = BoolOption('b3', '', callback=return_value, callback_params={'': ('yes', (b, False)), 'value': ('no',)})
+    o = OptionDescription('o', '', [b, b2, b3])
+    o1 = OptionDescription('o1', '', [o])
+    o1.impl_build_cache()
+
+    a = dumps(o1)
+    q = loads(a)
+    _diff_opt(o1, q)
+    _diff_opt(o1.o, q.o)
+    _diff_opt(o1.o.b, q.o.b)
+    _diff_opt(o1.o.b2, q.o.b2)
+    _diff_opt(o1.o.b3, q.o.b3)
+
+
 def test_no_state_attr():
     # all _state_xxx attributes should be deleted
     b = BoolOption('b', '')
index 0c7e732..89d960a 100644 (file)
@@ -188,9 +188,11 @@ class BaseOption(object):
                         _list_cons = []
                         for _con in _cons:
                             if load:
-                                _list_cons.append(descr.impl_get_opt_by_path(_con))
+                                _list_cons.append(
+                                    descr.impl_get_opt_by_path(_con))
                             else:
-                                _list_cons.append(descr.impl_get_path_by_opt(_con))
+                                _list_cons.append(
+                                    descr.impl_get_path_by_opt(_con))
                         new_value[key].append((key_cons, tuple(_list_cons)))
             if load:
                 del(self._state_consistencies)
@@ -322,7 +324,8 @@ class Option(BaseOption):
     Reminder: an Option object is **not** a container for the value.
     """
     __slots__ = ('_multi', '_validator', '_default_multi', '_default',
-                 '_callback', '_multitype', '_master_slaves', '__weakref__')
+                 '_state_callback', '_callback', '_multitype',
+                 '_master_slaves', '__weakref__')
     _empty = ''
 
     def __init__(self, name, doc, default=None, default_multi=None,
@@ -558,6 +561,57 @@ class Option(BaseOption):
                                "must be different as {2} option"
                                "").format(value, self._name, optname))
 
+    def _impl_convert_callbacks(self, descr, load=False):
+        if not load and self._callback is None:
+            self._state_callback = None
+        elif load and self._state_callback is None:
+            self._callback = None
+            del(self._state_callback)
+        else:
+            if load:
+                callback, callback_params = self._state_callback
+            else:
+                callback, callback_params = self._callback
+            if callback_params is not None:
+                cllbck_prms = {}
+                for key, values in callback_params.items():
+                    vls = []
+                    for value in values:
+                        if isinstance(value, tuple):
+                            if load:
+                                value = (descr.impl_get_opt_by_path(value[0]),
+                                         value[1])
+                            else:
+                                value = (descr.impl_get_path_by_opt(value[0]),
+                                         value[1])
+                        vls.append(value)
+                    cllbck_prms[key] = tuple(vls)
+            else:
+                cllbck_prms = None
+
+            if load:
+                del(self._state_callback)
+                self._callback = (callback, cllbck_prms)
+            else:
+                self._state_callback = (callback, cllbck_prms)
+
+    # serialize
+    def _impl_getstate(self, descr):
+        """the under the hood stuff that need to be done
+        before the serialization.
+        """
+        self._stated = True
+        self._impl_convert_callbacks(descr)
+        super(Option, self)._impl_getstate(descr)
+
+    # unserialize
+    def _impl_setstate(self, descr):
+        """the under the hood stuff that need to be done
+        before the serialization.
+        """
+        self._impl_convert_callbacks(descr, load=True)
+        super(Option, self)._impl_setstate(descr)
+
 
 class ChoiceOption(Option):
     """represents a choice out of several objects.
@@ -1287,4 +1341,5 @@ def validate_callback(callback, callback_params, type_):
                     if force_permissive not in [True, False]:
                         raise ValueError(_('{0}_params should have a boolean'
                                            'not a {0} for second argument'
-                                           ).format(type_, type(force_permissive)))
+                                           ).format(type_, type(
+                                               force_permissive)))