settings are in a separate object
authorgwen <gremond@cadoles.com>
Mon, 19 Nov 2012 09:45:03 +0000 (10:45 +0100)
committergwen <gremond@cadoles.com>
Mon, 19 Nov 2012 09:45:03 +0000 (10:45 +0100)
test/test_option_owner.py
test/test_option_type.py
test/test_option_with_special_name.py
tiramisu/config.py
tiramisu/option.py
tiramisu/setting.py [new file with mode: 0644]

index 6a4703b..a3ae1b5 100644 (file)
@@ -3,6 +3,7 @@ import autopath
 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')
@@ -48,25 +49,6 @@ def make_description2():
                                            intoption, boolop])
     return descr
 
-#def test_override_are_default_owner():
-#    "config.override() implies that the owner is 'default' again"
-#    descr = make_description2()
-#    config = Config(descr)
-#    config.bool = False
-#    # default
-#    assert config.gc._cfgimpl_value_owners['dummy'] == 'default'
-#    # user
-#    config.gc.dummy = True
-#    assert config.gc._cfgimpl_value_owners['dummy'] == 'user'
-#    assert config._cfgimpl_values['gc']._cfgimpl_value_owners['dummy'] == 'user'
-#    #Options have an available default setting and can give it back
-#    assert config._cfgimpl_descr._children[0]._children[1].getdefault() == False
-#    config.override({'gc.dummy':True})
-#    assert config.gc._cfgimpl_value_owners['dummy'] == 'default'
-#    # user again
-#    config.gc.dummy = False
-#    assert config.gc._cfgimpl_value_owners['dummy'] == 'user'
-
 def test_has_callback():
     descr = make_description()
     # here the owner is 'default'
@@ -74,7 +56,7 @@ def test_has_callback():
     config.bool = False
     # because dummy has a callback
     dummy = config.unwrap_from_path('gc.dummy')
-    config.cfgimpl_freeze()
+    settings.freeze()
     dummy.freeze()
     raises(TypeError, "config.gc.dummy = True")
 
@@ -83,12 +65,7 @@ def test_freeze_and_has_callback_with_setoption():
     descr = make_description()
     config = Config(descr)
     config.bool = False
-    config.cfgimpl_freeze()
+    settings.freeze()
     dummy = config.unwrap_from_path('gc.dummy')
     dummy.freeze()
     raises(TypeError, "config.gc.setoption('dummy', True, 'gen_config')")
-
-#def test_cannot_override():
-#    descr = make_description()
-#    config = Config(descr, bool=False)
-#    raises(TypeError, "config.override({'gc.dummy': True})")
index d19920f..bba0845 100644 (file)
@@ -1,10 +1,11 @@
 # coding: utf-8
-"frozen and hidden values" 
+"frozen and hidden values"
 import autopath
 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')
@@ -23,12 +24,12 @@ def make_description():
     wantframework_option = BoolOption('wantframework', 'Test requires',
                                       default=False,
                                       requires=[('gc.name', 'framework')])
-    
+
     # ____________________________________________________________
     booloptiontwo = BoolOption('booltwo', 'Test boolean option two', default=False)
     subgroup = OptionDescription('subgroup', '', [booloptiontwo])
     # ____________________________________________________________
-    
+
     gcgroup = OptionDescription('gc', '', [subgroup, gcoption, gcdummy, floatoption])
     descr = OptionDescription('trs', '', [gcgroup, booloption, objspaceoption,
                                            wantref_option, stroption,
@@ -52,7 +53,7 @@ def make_description_freeze():
     wantframework_option = BoolOption('wantframework', 'Test requires',
                                       default=False,
                                       requires=['boolop'])
-    
+
     gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
     descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption,
                                            wantref_option, stroption,
@@ -74,7 +75,7 @@ def test_frozen_value():
     s = StrOption("string", "", default="string")
     descr = OptionDescription("options", "", [s])
     config = Config(descr)
-    config.cfgimpl_freeze()
+    settings.freeze()
     s.freeze()
     raises(TypeError, 'config.string = "egg"')
 
@@ -82,7 +83,7 @@ def test_freeze():
     "freeze a whole configuration object"
     descr = make_description()
     conf = Config(descr)
-    conf.cfgimpl_freeze()
+    settings.freeze()
     name = conf.unwrap_from_path("gc.name")
     name.freeze()
     raises(TypeError, "conf.gc.name = 'framework'")
@@ -115,7 +116,7 @@ def test_group_is_hidden():
     assert config.gc.float == 2.3
     #dummy est en hide
     raises(PropertiesOptionError, "config.gc.dummy == False")
-    
+
 def test_global_show():
     descr = make_description()
     config = Config(descr)
@@ -133,4 +134,3 @@ def test_with_many_subgroups():
     assert name == "booltwo"
     option = getattr(homeconfig._cfgimpl_descr, name)
     assert option._is_hidden()
-
index 0d6b538..03c2557 100644 (file)
@@ -4,6 +4,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')
@@ -39,6 +40,6 @@ def test_root_config_answers_ok():
     boolop = BoolOption('boolop', 'Test boolean option op', default=True)
     descr = OptionDescription('tiramisu', '', [gcdummy, boolop])
     cfg = Config(descr)
-    cfg.cfgimpl_enable_property('hiddend') #cfgimpl_hide()
+    settings.enable_property('hiddend') #cfgimpl_hide()
     assert cfg.dummy == False
     assert cfg.boolop  == True
index 0b8dbbe..ac33645 100644 (file)
@@ -26,23 +26,11 @@ from tiramisu.error import (PropertiesOptionError, ConfigError, NotFoundError,
     MandatoryError, MethodCallError, NoValueReturned)
 from tiramisu.option import (OptionDescription, Option, SymLinkOption,
     group_types, Multi, apply_requires)
-
-# ______________________________________________________________________
-# generic owner. 'default' is the general config owner after init time
-default_owner = 'user'
+from tiramisu.setting import settings
 
 # ____________________________________________________________
 class Config(object):
     "main configuration management entry"
-    #properties attribute: the name of a property enables this property
-    _cfgimpl_properties = ['hidden', 'disabled']
-    _cfgimpl_permissive = []
-    #mandatory means: a mandatory option has to have a value that is not None
-    _cfgimpl_mandatory = True
-    _cfgimpl_frozen = True
-    #enables validation function for options if set
-    _cfgimpl_validator = False
-    _cfgimpl_owner = default_owner
     _cfgimpl_toplevel = None
 
     def __init__(self, descr, parent=None):
@@ -62,7 +50,6 @@ class Config(object):
         self._cfgimpl_warnings = []
         self._cfgimpl_toplevel = self._cfgimpl_get_toplevel()
         '`freeze()` allows us to carry out this calculation again if necessary'
-        self._cfgimpl_frozen = self._cfgimpl_toplevel._cfgimpl_frozen
         self._cfgimpl_build()
 
     def _validate_duplicates(self, children):
@@ -100,11 +87,6 @@ class Config(object):
                 self._cfgimpl_values[child._name] = Config(child, parent=self)
 #        self.override(overrides)
 
-    def cfgimpl_set_permissive(self, permissive):
-        if not isinstance(permissive, list):
-            raise TypeError('permissive must be a list')
-        self._cfgimpl_permissive = permissive
-
     def cfgimpl_update(self):
         """dynamically adds `Option()` or `OptionDescription()`
         """
@@ -123,38 +105,6 @@ class Config(object):
                 if child._name not in self._cfgimpl_values:
                     self._cfgimpl_values[child._name] = Config(child, parent=self)
 
-    def cfgimpl_set_owner(self, owner):
-        ":param owner: sets the default value for owner at the Config level"
-        self._cfgimpl_owner = owner
-        for child in self._cfgimpl_descr._children:
-            if isinstance(child, OptionDescription):
-                self._cfgimpl_values[child._name].cfgimpl_set_owner(owner)
-    # ____________________________________________________________
-    # properties methods
-    def _cfgimpl_has_properties(self):
-        "has properties means the Config's properties attribute is not empty"
-        return bool(len(self._cfgimpl_properties))
-
-    def _cfgimpl_has_property(self, propname):
-        """has property propname in the Config's properties attribute
-        :param property: string wich is the name of the property"""
-        return propname in self._cfgimpl_properties
-
-    def cfgimpl_enable_property(self, propname):
-        "puts property propname in the Config's properties attribute"
-        if self._cfgimpl_parent != None:
-            raise MethodCallError("this method root_hide() shall not be"
-                                  "used with non-root Config() object")
-        if propname not in self._cfgimpl_properties:
-            self._cfgimpl_properties.append(propname)
-
-    def cfgimpl_disable_property(self, propname):
-        "deletes property propname in the Config's properties attribute"
-        if self._cfgimpl_parent != None:
-            raise MethodCallError("this method root_hide() shall not be"
-                                  "used with non-root Config() object")
-        if self._cfgimpl_has_property(propname):
-            self._cfgimpl_properties.remove(propname)
     # ____________________________________________________________
     # attribute methods
     def __setattr__(self, name, value):
@@ -167,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, self._cfgimpl_owner)
+        self.setoption(name, value, settings.owner)
 
     def _validate(self, name, opt_or_descr, permissive=False):
         "validation for the setattr and the getattr"
@@ -177,10 +127,10 @@ class Config(object):
             raise TypeError('Unexpected object: {0}'.format(repr(opt_or_descr)))
         properties = copy(opt_or_descr.properties)
         for proper in copy(properties):
-            if not self._cfgimpl_toplevel._cfgimpl_has_property(proper):
+            if not settings.has_property(proper):
                 properties.remove(proper)
         if permissive:
-            for perm in self._cfgimpl_toplevel._cfgimpl_permissive:
+            for perm in settings.permissive:
                 if perm in properties:
                     properties.remove(perm)
         if properties != []:
@@ -199,8 +149,7 @@ class Config(object):
 
     def _test_mandatory(self, path, opt):
         # mandatory options
-        homeconfig = self._cfgimpl_get_toplevel()
-        mandatory = homeconfig._cfgimpl_mandatory
+        mandatory = settings.mandatory
         if opt.is_mandatory() and mandatory:
             if self._is_empty(opt) and \
                     opt.is_empty_by_default():
@@ -215,9 +164,9 @@ class Config(object):
         attribute notation mechanism for accessing the value of an option
         :param name: attribute name
         :param permissive: permissive doesn't raise some property error
-        (see ``_cfgimpl_permissive``)
+                          (see ``settings.permissive``)
         :return: option's value if name is an option name, OptionDescription
-        otherwise
+                 otherwise
         """
         # attribute access by passing a path,
         # for instance getattr(self, "creole.general.family.adresse_ip_eth0")
@@ -250,9 +199,9 @@ class Config(object):
                             return value
                     else:
                         return value
-                rootconfig = self._cfgimpl_get_toplevel()
                 try:
-                    result = opt_or_descr.getcallback_value(rootconfig)
+                    result = opt_or_descr.getcallback_value(
+                            self._cfgimpl_get_toplevel())
                 except NoValueReturned, err:
                     pass
                 else:
@@ -267,7 +216,7 @@ class Config(object):
                                 ' for option {0} : shall not be a list'.format(name))
                         _result = result
                     if _result != None and not opt_or_descr.validate(_result,
-                                rootconfig._cfgimpl_validator):
+                                settings.validator):
                         raise ConfigError('invalid calculated value returned'
                             ' for option {0}'.format(name))
                     self._cfgimpl_values[name] = _result
@@ -327,7 +276,7 @@ class Config(object):
         child = getattr(self._cfgimpl_descr, name)
         if type(child) != SymLinkOption:
             if who == None:
-                who = self._cfgimpl_owner
+                who = settings.owner
             if child.is_multi():
                 if type(value) != Multi:
                     if type(value) == list:
@@ -361,7 +310,7 @@ class Config(object):
                     pass
                 except Exception, e:
                     raise e # HiddenOptionError or DisabledOptionError
-                homeconfig.setoption(name, value, self._cfgimpl_owner)
+                homeconfig.setoption(name, value, settings.owner)
             elif len(candidates) > 1:
                 raise AmbigousOptionError(
                     'more than one option that ends with %s' % (key, ))
@@ -433,64 +382,6 @@ class Config(object):
         "Config implements its own warning pile"
         return self._cfgimpl_get_toplevel()._cfgimpl_warnings
     # ____________________________________________________________
-    # Config()'s status
-    def cfgimpl_freeze(self):
-        "cannot modify the frozen `Option`'s"
-        rootconfig = self._cfgimpl_get_toplevel()
-        rootconfig._cfgimpl_frozen = True
-        self._cfgimpl_frozen = True
-
-    def cfgimpl_unfreeze(self):
-        "can modify the Options that are frozen"
-        rootconfig = self._cfgimpl_get_toplevel()
-        rootconfig._cfgimpl_frozen = False
-        self._cfgimpl_frozen = False
-
-    def is_frozen(self):
-        "freeze flag at Config level"
-        rootconfig = self._cfgimpl_get_toplevel()
-        return rootconfig._cfgimpl_frozen
-
-    def cfgimpl_read_only(self):
-        "convenience method to freeze, hidde and disable"
-        self.cfgimpl_freeze()
-        rootconfig = self._cfgimpl_get_toplevel()
-        rootconfig.cfgimpl_disable_property('hidden')
-        rootconfig.cfgimpl_enable_property('disabled')
-        rootconfig._cfgimpl_mandatory = True
-        rootconfig._cfgimpl_validator = True
-
-    def cfgimpl_read_write(self):
-        "convenience method to freeze, hidde and disable"
-        self.cfgimpl_freeze()
-        rootconfig = self._cfgimpl_get_toplevel()
-        rootconfig.cfgimpl_enable_property('hidden')
-        rootconfig.cfgimpl_enable_property('disabled')
-        rootconfig._cfgimpl_mandatory = False
-
-    def cfgimpl_non_mandatory(self):
-        """mandatory at the Config level means that the Config raises an error
-        if a mandatory option is found"""
-        if self._cfgimpl_parent != None:
-            raise MethodCallError("this method root_mandatory shall"
-                                  " not be used with non-root Confit() object")
-        rootconfig = self._cfgimpl_get_toplevel()
-        rootconfig._cfgimpl_mandatory = False
-
-    def cfgimpl_mandatory(self):
-        """mandatory at the Config level means that the Config raises an error
-        if a mandatory option is found"""
-        if self._cfgimpl_parent != None:
-            raise MethodCallError("this method root_mandatory shall"
-                                  " not be used with non-root Confit() object")
-        rootconfig = self._cfgimpl_get_toplevel()
-        rootconfig._cfgimpl_mandatory = True
-
-    def is_mandatory(self):
-        "all mandatory Options shall have a value"
-        rootconfig = self._cfgimpl_get_toplevel()
-        return rootconfig._cfgimpl_mandatory
-    # ____________________________________________________________
     def getkey(self):
         return self._cfgimpl_descr.getkey(self)
 
@@ -685,8 +576,8 @@ def mandatory_warnings(config):
 
     :returns: generator of mandatory Option's path
     """
-    mandatory = config._cfgimpl_get_toplevel()._cfgimpl_mandatory
-    config._cfgimpl_get_toplevel()._cfgimpl_mandatory = True
+    mandatory = settings.mandatory
+    settings.mandatory = True
     for path in config._cfgimpl_descr.getpaths(include_groups=True):
         try:
             value = config._getattr(path, permissive=True)
@@ -694,4 +585,4 @@ def mandatory_warnings(config):
             yield path
         except PropertiesOptionError:
             pass
-    config._cfgimpl_get_toplevel()._cfgimpl_mandatory = mandatory
+    settings.mandatory = mandatory
index 5b865fc..259825b 100644 (file)
@@ -26,6 +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
 
 requires_actions = [('hide', 'show'), ('enable', 'disable'), ('freeze', 'unfreeze')]
 
@@ -63,7 +64,7 @@ class Multi(list):
 
     def setoption(self, value, key=None, who=None):
         if who is None:
-            who = self.config._cfgimpl_owner
+            who = settings.owner
         if value != None:
             if not self.child._validate(value):
                 raise ConfigError("invalid value {0} "
@@ -78,7 +79,7 @@ class Multi(list):
         return ret
 
     def pop(self, key):
-        self.child.setowner(self.config, self.config._cfgimpl_owner)
+        self.child.setowner(self.config, settings.owner)
         super(Multi, self).pop(key)
 # ____________________________________________________________
 #
@@ -257,7 +258,7 @@ class Option(HiddenBaseType, DisabledBaseType):
         :type who: string """
         name = self._name
         rootconfig = config._cfgimpl_get_toplevel()
-        if not self.validate(value, rootconfig._cfgimpl_validator):
+        if not self.validate(value, settings.validator):
             raise ConfigError('invalid value %s for option %s' % (value, name))
         if self.is_mandatory():
             # value shall not be '' for a mandatory option
@@ -266,14 +267,14 @@ class Option(HiddenBaseType, DisabledBaseType):
                 value = None
             if self.is_multi() and '' in value:
                 value = Multi([{'': None}.get(i, i) for i in value], config, self)
-            if config.is_mandatory() and ((self.is_multi() and value == []) or \
+            if settings.is_mandatory() and ((self.is_multi() and value == []) or \
                 (not self.is_multi() and value is None)):
                 raise MandatoryError('cannot change the value to %s for '
               'option %s' % (value, name))
         if name not in config._cfgimpl_values:
             raise AttributeError('unknown option %s' % (name))
 
-        if config.is_frozen() and self.is_frozen():
+        if settings.is_frozen() and self.is_frozen():
             raise TypeError('cannot change the value to %s for '
                'option %s this option is frozen' % (str(value), name))
         apply_requires(self, config)
diff --git a/tiramisu/setting.py b/tiramisu/setting.py
new file mode 100644 (file)
index 0000000..b8275f0
--- /dev/null
@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+"sets the options of the configuration objects Config object itself"
+# Copyright (C) 2012 Team tiramisu (see AUTHORS for all contributors)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# The original `Config` design model is unproudly borrowed from
+# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
+# the whole pypy projet is under MIT licence
+# ____________________________________________________________
+
+class Setting():
+    "``Config()``'s configuration options"
+    # properties attribute: the name of a property enables this property
+    properties = ['hidden', 'disabled']
+    # overrides the validations in the acces of the option values
+    permissive = []
+    # a mandatory option must have a value that is not None
+    mandatory = True
+    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):
+        "has properties means the Config's properties attribute is not empty"
+        return bool(len(self.properties))
+
+    def has_property(self, propname):
+        """has property propname in the Config's properties attribute
+        :param property: string wich is the name of the property"""
+        return propname in self.properties
+
+    def enable_property(self, propname):
+        "puts property propname in the Config's properties attribute"
+        if propname not in self.properties:
+            self.properties.append(propname)
+
+    def disable_property(self, propname):
+        "deletes property propname in the Config's properties attribute"
+        if self.has_property(propname):
+            self.properties.remove(propname)
+
+    def set_permissive(self, permissive):
+        if not isinstance(permissive, list):
+            raise TypeError('permissive must be a list')
+        self.permissive = permissive
+
+    def read_only(self):
+        "convenience method to freeze, hidde and disable"
+        self.freeze()
+        self.disable_property('hidden')
+        self.enable_property('disabled')
+        self.mandatory = True
+        self.validator = True
+
+    def read_write(self):
+        "convenience method to freeze, hidde and disable"
+        self.freeze()
+        self.enable_property('hidden')
+        self.enable_property('disabled')
+        self.mandatory = False
+
+    def non_mandatory(self):
+        """mandatory at the Config level means that the Config raises an error
+        if a mandatory option is found"""
+        self.mandatory = False
+
+    def mandatory(self):
+        """mandatory at the Config level means that the Config raises an error
+        if a mandatory option is found"""
+        self.mandatory = True
+
+    def is_mandatory(self):
+        "all mandatory Options shall have a value"
+        return self.mandatory
+
+    def freeze(self):
+        "cannot modify the frozen `Option`'s"
+        self.frozen = True
+
+    def unfreeze(self):
+        "can modify the Options that are frozen"
+        self.frozen = False
+
+    def is_frozen(self):
+        "freeze flag at Config level"
+        return self.frozen
+
+    def set_owner(self, owner):
+        ":param owner: sets the default value for owner at the Config level"
+        self.owner = owner
+
+# Setting is actually a singleton
+settings = Setting()