owners are *real* objects now
authorgwen <gremond@cadoles.com>
Mon, 10 Dec 2012 13:10:05 +0000 (14:10 +0100)
committergwen <gremond@cadoles.com>
Mon, 10 Dec 2012 13:10:05 +0000 (14:10 +0100)
test/test_option_consistency.py
test/test_option_owner.py
test/test_option_setting.py
test/test_parsing_group.py
tiramisu/config.py
tiramisu/option.py
tiramisu/setting.py

index f333ea2..eb1a852 100644 (file)
@@ -3,6 +3,7 @@ from py.test import raises
 
 from tiramisu.config import *
 from tiramisu.option import *
+from tiramisu.setting import settings
 
 def make_description():
     gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
@@ -60,14 +61,6 @@ def test_identical_paths():
     descr = make_description_duplicates()
     raises(ConflictConfigError, "cfg = Config(descr)")
 
-#def test_identical_for_names():
-#    """if there is something that
-#    have the same name, an exection is raised
-#    """
-#    descr = make_description_duplicates()
-#    raises(ConflictConfigError, "cfg = Config(descr)")
-
-
 def make_description2():
     gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
     gcdummy = BoolOption('dummy', 'dummy', default=False)
@@ -97,8 +90,7 @@ def make_description2():
                                            intoption, boolop])
     return descr
 
-# FIXME: XXX would you mind putting the multi validations anywhere else
-# than in the requires !!!
+# FIXME: il faudra tester les validations sur les multis
 #def test_multi_constraints():
 #    "a multi in a constraint has to have the same length"
 #    descr = make_description2()
@@ -213,3 +205,47 @@ def test_disabled_with_group():
     cfg.int = 1
     raises(PropertiesOptionError, "cfg.gc.name")
     assert gcgroup._is_disabled()
+#____________________________________________________________
+
+def make_description_callback():
+    gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
+    gcdummy = BoolOption('dummy', 'dummy', callback="toto")
+    objspaceoption = ChoiceOption('objspace', 'Object space',
+                                ['std', 'thunk'], 'std')
+    booloption = BoolOption('bool', 'Test boolean option', default=True)
+    intoption = IntOption('int', 'Test int option', default=0)
+    floatoption = FloatOption('float', 'Test float option', default=2.3)
+    stroption = StrOption('str', 'Test string option', default="abc")
+    boolop = BoolOption('boolop', 'Test boolean option op', default=True)
+    wantref_option = BoolOption('wantref', 'Test requires', default=False,
+                                    requires=['boolop'])
+    wantframework_option = BoolOption('wantframework', 'Test requires',
+                                      default=False,
+                                      requires=['boolop'])
+    gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
+    descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
+                                           wantref_option, stroption,
+                                           wantframework_option,
+                                           intoption, boolop])
+    return descr
+
+def test_has_callback():
+    descr = make_description_callback()
+    # here the owner is 'default'
+    config = Config(descr)
+    config.bool = False
+    # because dummy has a callback
+    dummy = config.unwrap_from_path('gc.dummy')
+    settings.freeze()
+    dummy.freeze()
+    raises(TypeError, "config.gc.dummy = True")
+
+def test_freeze_and_has_callback_with_setoption():
+    descr = make_description_callback()
+    config = Config(descr)
+    config.bool = False
+    settings.freeze()
+    dummy = config.unwrap_from_path('gc.dummy')
+    dummy.freeze()
+    raises(TypeError, "config.gc.setoption('dummy', True, 'gen_config')")
+#____________________________________________________________
index a3ae1b5..8131c84 100644 (file)
@@ -3,11 +3,11 @@ import autopath
 from py.test import raises
 from tiramisu.config import *
 from tiramisu.option import *
-from tiramisu.setting import settings
+from tiramisu.setting import settings, owners
 
 def make_description():
     gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
-    gcdummy = BoolOption('dummy', 'dummy', callback="toto")
+    gcdummy = BoolOption('dummy', 'dummy', default=False)
     objspaceoption = ChoiceOption('objspace', 'Object space',
                                 ['std', 'thunk'], 'std')
     booloption = BoolOption('bool', 'Test boolean option', default=True)
@@ -15,57 +15,36 @@ def make_description():
     floatoption = FloatOption('float', 'Test float option', default=2.3)
     stroption = StrOption('str', 'Test string option', default="abc")
     boolop = BoolOption('boolop', 'Test boolean option op', default=True)
-    wantref_option = BoolOption('wantref', 'Test requires', default=False,
-                                    requires=['boolop'])
+    wantref_option = BoolOption('wantref', 'Test requires', default=False)
     wantframework_option = BoolOption('wantframework', 'Test requires',
-                                      default=False,
-                                      requires=['boolop'])
+                                      default=False)
+
     gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
-    descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
+    descr = OptionDescription('tiram', '', [gcgroup, booloption, objspaceoption,
                                            wantref_option, stroption,
                                            wantframework_option,
                                            intoption, boolop])
     return descr
 
-def make_description2():
-    gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
+def test_default_owner():
     gcdummy = BoolOption('dummy', 'dummy', default=False)
-    objspaceoption = ChoiceOption('objspace', 'Object space',
-                                ['std', 'thunk'], 'std')
-    booloption = BoolOption('bool', 'Test boolean option', default=True)
-    intoption = IntOption('int', 'Test int option', default=0)
-    floatoption = FloatOption('float', 'Test float option', default=2.3)
-    stroption = StrOption('str', 'Test string option', default="abc")
-    boolop = BoolOption('boolop', 'Test boolean option op', default=True)
-    wantref_option = BoolOption('wantref', 'Test requires', default=False,
-                                    requires=['boolop'])
-    wantframework_option = BoolOption('wantframework', 'Test requires',
-                                      default=False,
-                                      requires=['boolop'])
-    gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
-    descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
-                                           wantref_option, stroption,
-                                           wantframework_option,
-                                           intoption, boolop])
-    return descr
+    descr = OptionDescription('tiramisu', '', [gcdummy])
+    cfg = Config(descr)
+    assert cfg.dummy == False
+    dm = cfg.unwrap_from_path('dummy')
+    assert dm.getowner(cfg) == 'default'
+    dm.setowner(cfg, owners.user)
+    assert dm.getowner(cfg) == owners.user
 
-def test_has_callback():
-    descr = make_description()
-    # here the owner is 'default'
-    config = Config(descr)
-    config.bool = False
-    # because dummy has a callback
-    dummy = config.unwrap_from_path('gc.dummy')
-    settings.freeze()
-    dummy.freeze()
-    raises(TypeError, "config.gc.dummy = True")
+def test_owner_is_not_a_string():
+    gcdummy = BoolOption('dummy', 'dummy', default=False)
+    descr = OptionDescription('tiramisu', '', [gcdummy])
+    cfg = Config(descr)
+    assert cfg.dummy == False
+    dm = cfg.unwrap_from_path('dummy')
+    assert dm.getowner(cfg) == owners.default
+    assert dm.getowner(cfg) == 'default'
+    assert isinstance(dm.getowner(cfg), owners.Owner)
+    dm.setowner(cfg, owners.user)
 
-#____________________________________________________________
-def test_freeze_and_has_callback_with_setoption():
-    descr = make_description()
-    config = Config(descr)
-    config.bool = False
-    settings.freeze()
-    dummy = config.unwrap_from_path('gc.dummy')
-    dummy.freeze()
-    raises(TypeError, "config.gc.setoption('dummy', True, 'gen_config')")
+    assert dm.getowner(cfg) == 'user'
index eb5fa44..2997178 100644 (file)
@@ -51,10 +51,10 @@ def test_reset():
     config = Config(descr)
     config.string = "foo"
     assert config.string == "foo"
-    assert config._cfgimpl_value_owners['string'] == 'user'
+    assert config._cfgimpl_value_owners['string'] == owners.user
     config.unwrap_from_path("string").reset(config)
     assert config.string == 'string'
-    assert config._cfgimpl_value_owners['string'] == 'default'
+    assert config._cfgimpl_value_owners['string'] == owners.default
 
 def test_reset_with_multi():
     s = StrOption("string", "", default=["string"], default_multi="string" , multi=True)
@@ -250,7 +250,7 @@ def test_setoption_from_option():
     booloption = BoolOption('bool', 'Test boolean option', default=True)
     descr = OptionDescription('descr', '', [booloption])
     cfg = Config(descr)
-    booloption.setoption(cfg, False, 'owner')
+    booloption.setoption(cfg, False)
     assert cfg.bool == False
 #____________________________________________________________
 def test_dwim_set():
@@ -348,14 +348,11 @@ def test_accepts_multiple_changes_from_option():
     config.string = "egg"
     assert s.getdefault() == "string"
     assert config.string == "egg"
-    s.setoption(config, 'blah', "default")
+    s.setoption(config, 'blah')
     assert s.getdefault() == "string"
     assert config.string == "blah"
-    s.setoption(config, 'bol', "user")
+    s.setoption(config, 'bol')
     assert config.string == 'bol'
-#    config.override({'string': "blurp"})
-#    assert config.string == 'blurp'
-#    assert s.getdefault() == 'blurp'
 
 def test_allow_multiple_changes_from_config():
     """
@@ -367,28 +364,13 @@ def test_allow_multiple_changes_from_config():
     suboption = OptionDescription("bip", "", [s2])
     descr = OptionDescription("options", "", [s, suboption])
     config = Config(descr)
-    config.setoption("string", 'blah', "user")
-    config.setoption("string", "oh", "user")
+    config.setoption("string", 'blah', owners.user)
+    config.setoption("string", "oh", owners.user)
     assert config.string == "oh"
     config.set(string2= 'blah')
     assert config.bip.string2 == 'blah'
 # ____________________________________________________________
-
-#def test_overrides_are_defaults():
-#    descr = OptionDescription("test", "", [
-#        BoolOption("b1", "", default=False),
-#        BoolOption("b2", "", default=False),
-#        ])
-#    # overrides here
-#    config = Config(descr)
-#    config.b2 = True
-#    assert config.b2
-#    # test with a require
-#    config.b1 = True
-#    assert config.b2
-
- # ____________________________________________________________
- # accessing a value by the get method
+# accessing a value by the get method
 def test_access_by_get():
     descr = make_description()
     cfg = Config(descr)
index d9c2e00..10c7a93 100644 (file)
@@ -57,7 +57,13 @@ def test_get_group_type():
     descr = make_description()
     config = Config(descr)
     grp = config.unwrap_from_path('creole.general')
-    assert grp.get_group_type() == "family"
+    assert grp.get_group_type() == groups.family
+    assert grp.get_group_type() == 'family'
+    assert isinstance(grp.get_group_type(), groups.GroupName)
+    grp.set_group_type(groups.default)
+    assert isinstance(grp.get_group_type(), groups.DefaultGroupName)
+    assert grp.get_group_type() == groups.default
+    assert grp.get_group_type() == 'default'
 
 def test_iter_on_groups():
     descr = make_description()
index 1b69006..fbfdb69 100644 (file)
@@ -26,7 +26,7 @@ from tiramisu.error import (PropertiesOptionError, ConfigError, NotFoundError,
     MandatoryError, MethodCallError, NoValueReturned)
 from tiramisu.option import (OptionDescription, Option, SymLinkOption,
     Multi, apply_requires)
-from tiramisu.setting import settings, groups
+from tiramisu.setting import settings, groups, owners
 
 # ____________________________________________________________
 class Config(object):
@@ -81,7 +81,7 @@ class Config(object):
                     childdef = child.getdefault()
                     self._cfgimpl_values[child._name] = childdef
                     self._cfgimpl_previous_values[child._name] = childdef
-                child.setowner(self, 'default')
+                child.setowner(self, owners.default)
             elif isinstance(child, OptionDescription):
                 self._validate_duplicates(child._children)
                 self._cfgimpl_values[child._name] = Config(child, parent=self)
@@ -100,7 +100,7 @@ class Config(object):
                                 copy(child.getdefault()), config=self, opt=child)
                     else:
                         self._cfgimpl_values[child._name] = copy(child.getdefault())
-                    child.setowner(self, 'default')
+                    child.setowner(self, owners.default)
             elif isinstance(child, OptionDescription):
                 if child._name not in self._cfgimpl_values:
                     self._cfgimpl_values[child._name] = Config(child, parent=self)
@@ -117,7 +117,7 @@ class Config(object):
             return setattr(homeconfig, name, value)
         if type(getattr(self._cfgimpl_descr, name)) != SymLinkOption:
             self._validate(name, getattr(self._cfgimpl_descr, name))
-        self.setoption(name, value, settings.owner)
+        self.setoption(name, value, owners.user)
 
     def _validate(self, name, opt_or_descr, permissive=False):
         "validation for the setattr and the getattr"
@@ -263,7 +263,7 @@ class Config(object):
                         raise ConfigError('invalid calculated value returned'
                             ' for option {0}'.format(name))
                     self._cfgimpl_values[name] = _result
-                    opt_or_descr.setowner(self, 'default')
+                    opt_or_descr.setowner(self, owners.default)
             # frozen and force default
             if not opt_or_descr.has_callback() and opt_or_descr.is_forced_on_freeze():
                 value = opt_or_descr.getdefault()
@@ -272,7 +272,7 @@ class Config(object):
                                 use_default_multi=True,
                                 default_multi=opt_or_descr.getdefault_multi())
                 self._cfgimpl_values[name] = value
-                opt_or_descr.setowner(self, 'default')
+                opt_or_descr.setowner(self, owners.default)
             self._test_mandatory(name, opt_or_descr)
         value = self._cfgimpl_values[name]
         self._valid_len(name, value)
@@ -307,17 +307,14 @@ class Config(object):
     def setoption(self, name, value, who=None):
         """effectively modifies the value of an Option()
         (typically called by the __setattr__)
-
-        :param who: is an owner's name
-                    who is **not necessarily** a owner, because it cannot be a list
-        :type who: string
+        :param who : an object that lives in `setting.owners`
         """
         child = getattr(self._cfgimpl_descr, name)
         if type(child) != SymLinkOption:
             if who == None:
                 who = settings.owner
             if child.is_multi():
-                if who != 'default':
+                if not isinstance(who, owners.DefaultOwner):
                     if type(value) != Multi:
                         if type(value) == list:
                             value = Multi(value, self, child)
@@ -329,11 +326,15 @@ class Config(object):
                                         use_default_multi=True,
                                         default_multi=child.getdefault_multi())
                 self._valid_len(name, value)
-            child.setoption(self, value, who)
+            if not isinstance(who, owners.Owner):
+                raise TypeError("invalid owner [{0}] for option: {1}".format(
+                                str(who), name))
+            print "ssdfsdfsdfsdfsdf", type(child)
+            child.setoption(self, value)
             child.setowner(self, who)
         else:
             homeconfig = self._cfgimpl_get_toplevel()
-            child.setoption(homeconfig, value, who)
+            child.setoption(homeconfig, value)
 
     def set(self, **kwargs):
         """
@@ -355,7 +356,7 @@ class Config(object):
                     pass
                 except Exception, e:
                     raise e # HiddenOptionError or DisabledOptionError
-                homeconfig.setoption(name, value, settings.owner)
+                homeconfig.setoption(name, value, owners.user)
             elif len(candidates) > 1:
                 raise AmbigousOptionError(
                     'more than one option that ends with %s' % (key, ))
@@ -457,8 +458,8 @@ class Config(object):
         """iteration on groups objects only.
         All groups are returned if `group_type` is `None`, otherwise the groups
         can be filtered by categories (families, or whatever).
-        :param group_type: if defined, is an instance of `settings.GroupName`
-                           or `settings.MasterGroupName` that lives in
+        :param group_type: if defined, is an instance of `groups.GroupName`
+                           or `groups.MasterGroupName` that lives in
                            `settings.groups`
 
         """
index b5ca031..7f78717 100644 (file)
@@ -26,7 +26,7 @@ from tiramisu.error import (ConfigError, ConflictConfigError, NotFoundError,
     RequiresError, RequirementRecursionError, MandatoryError,
     PropertiesOptionError)
 from tiramisu.autolib import carry_out_calculation
-from tiramisu.setting import settings, groups
+from tiramisu.setting import settings, groups, owners
 
 requires_actions = [('hide', 'show'), ('enable', 'disable'), ('freeze', 'unfreeze')]
 
@@ -65,7 +65,7 @@ class Multi(list):
             super(Multi, self).__init__(lst)
 
     def __setitem__(self, key, value):
-        return self._setvalue(value, key, who=settings.owner)
+        return self._setvalue(value, key, who=owners.user)
 
     def append(self, value, add_master=True):
         """the list value can be updated (appened)
@@ -307,13 +307,13 @@ class Option(HiddenBaseType, DisabledBaseType):
         """
         :param config: *must* be only the **parent** config
                        (not the toplevel config)
-        :param owner: is a **real** owner, that is a name or a list
-                       which is allowable here
+        :param owner: is a **real** owner, that is an object
+                      that lives in setting.owners
         """
         name = self._name
-        if not type(owner) == str:
-            raise ConfigError("invalid type for owner option: {0}".format(
-                    name))
+        if not isinstance(owner, owners.Owner):
+            raise ConfigError("invalid type owner for option: {0}".format(
+                    str(name)))
         config._cfgimpl_value_owners[name] = owner
 
     def getowner(self, config):
@@ -323,7 +323,7 @@ class Option(HiddenBaseType, DisabledBaseType):
     def reset(self, config):
         """resets the default value and owner
         """
-        config.setoption(self._name, self.getdefault(), 'default')
+        config.setoption(self._name, self.getdefault(), owners.default)
 
     def is_default_owner(self, config):
         """
@@ -333,11 +333,10 @@ class Option(HiddenBaseType, DisabledBaseType):
         """
         return self.getowner(config) == 'default'
 
-    def setoption(self, config, value, who):
+    def setoption(self, config, value):
         """changes the option's value with the value_owner's who
         :param config: the parent config is necessary here to store the value
-        :param who : is **not necessarily** a owner because it cannot be a list
-        :type who: string """
+        """
         name = self._name
         rootconfig = config._cfgimpl_get_toplevel()
         if not self.validate(value, settings.validator):
@@ -446,7 +445,7 @@ class SymLinkOption(object):
         self.path = path
         self.opt = opt
 
-    def setoption(self, config, value, who):
+    def setoption(self, config, value):
         setattr(config, self.path, value)
 
     def __getattr__(self, name):
index 927fae3..39e84f9 100644 (file)
@@ -42,6 +42,10 @@ class GroupModule(_const):
         *normal* means : groups that are not master
         """
         pass
+    class DefaultGroupName(GroupName):
+        """groups that are default (typically 'default')"""
+        pass
+
     class MasterGroupName(GroupName):
         """allowed normal group (OptionDescription) names
         *master* means : groups that have the 'master' attribute set
@@ -54,16 +58,44 @@ def populate_groups():
     "populates the available groups in the appropriate namespaces"
     _available_group_names = ('default', 'family', 'group')
     _available_groups_with_a_master = ('group', )
+    _available_default_groups = ('default', )
     # populates normal or master groups
     for grp in _available_group_names:
         if grp in _available_groups_with_a_master:
             setattr(groups, grp, groups.MasterGroupName(grp))
+        elif grp in _available_default_groups:
+            setattr(groups, grp, groups.DefaultGroupName(grp))
         else:
             setattr(groups, grp, groups.GroupName(grp))
 # names are in the module now
 populate_groups()
 # ____________________________________________________________
+class OwnerModule(_const):
+    """emulates a module to manage unique owner names.
+
+    owners are living in `Config._cfgimpl_value_owners`
+    """
+    class Owner(str):
+        """allowed owner names
+        """
+        pass
+    class DefaultOwner(Owner):
+        """groups that are default (typically 'default')"""
+        pass
+# setting.owners (emulates a module)
+owners = OwnerModule()
 
+def populate_owners():
+    """populates the available owners in the appropriate namespaces
+
+    - 'user' is the generic is the generic owner.
+    - 'default' is the config owner after init time
+    """
+    setattr(owners, 'default', owners.DefaultOwner('default'))
+    setattr(owners,'user', owners.Owner('user'))
+# names are in the module now
+populate_owners()
+#____________________________________________________________
 class Setting():
     "``Config()``'s configuration options"
     # properties attribute: the name of a property enables this property
@@ -75,8 +107,6 @@ class Setting():
     frozen = True
     # enables validation function for options if set
     validator = False
-    # generic owner. 'default' is the general config owner after init time
-    owner = 'user'
     # ____________________________________________________________
     # properties methods
     def has_properties(self):