diff --git a/test/api/test_owner.py b/test/api/test_owner.py index b446b5b..17fde29 100644 --- a/test/api/test_owner.py +++ b/test/api/test_owner.py @@ -6,7 +6,8 @@ from .autopath import do_autopath do_autopath() from tiramisu import Config, StrOption, OptionDescription, MasterSlaves, DynOptionDescription, \ getapi -from tiramisu.error import PropertiesOptionError +from tiramisu.error import PropertiesOptionError, APIError +from collections import OrderedDict ICON = u'\u2937' OPTIONS_TYPE = {'str': {'type': str, @@ -57,6 +58,7 @@ def autocheck_owner_without_value(api, path, **kwargs): raises(PropertiesOptionError, "api.owner.get(path)") else: raises(PropertiesOptionError, "api.owner.get(path, 0)") + raises(APIError, "api.unrestraint.owner.get(path)") if not kwargs.get('propertyerror', False): if not isslave: assert api.permissive.owner.get(path) == 'default' @@ -69,6 +71,7 @@ def autocheck_owner_without_value(api, path, **kwargs): raises(PropertiesOptionError, "api.permissive.owner.get(path, 0)") # check if default owner + raises(APIError, "api.unrestraint.owner.isdefault(path)") if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False): assert api.owner.isdefault(path) else: @@ -83,15 +86,6 @@ def autocheck_owner_without_value(api, path, **kwargs): def autocheck_value(api, path, **kwargs): """set and get values """ - print('=============') - try: - print(api.permissive.owner.get(path)) - except Exception as pouet: - try: - print(api.permissive.owner.get(path, 0)) - except Exception as pouet: - print(pouet) - pass # check if is a multi, a master or a slave if not kwargs.get('propertyerror', False): multi = api.permissive.option.ismulti(path) @@ -99,9 +93,9 @@ def autocheck_value(api, path, **kwargs): isslave = api.permissive.option.isslave(path) else: raises(PropertiesOptionError, "api.permissive.option.ismulti(path)") - multi = False - ismaster = False - isslave = False + multi = api.unrestraint.option.ismulti(path) + ismaster = api.unrestraint.option.ismaster(path) + isslave = api.unrestraint.option.isslave(path) # set default value (different if value is multi or not) if not multi: @@ -125,6 +119,7 @@ def autocheck_value(api, path, **kwargs): # test default value (should be empty) with permissive # cannot test for slave (we cannot get all values for a slave) + raises(APIError, "api.unrestraint.value.get(path)") if not isslave: if not kwargs.get('propertyerror', False): assert api.permissive.value.get(path) == empty_value @@ -176,6 +171,12 @@ def autocheck_value(api, path, **kwargs): raises(PropertiesOptionError, "api.permissive.value.get(path)") # set a value with permissive + if ismaster: + raises(APIError, "api.unrestraint.value.set(path, second_value[1])") + elif isslave: + raises(APIError, "api.unrestraint.value.append(path, second_value[1])") + else: + raises(APIError, "api.unrestraint.value.set(path, second_value)") if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False): if ismaster: raises(IndexError, "api.permissive.value.set(path, 1, second_value[1])") @@ -228,15 +229,6 @@ def autocheck_value(api, path, **kwargs): else: raises(PropertiesOptionError, "api.value.get(path)") raises(PropertiesOptionError, "api.permissive.value.get(path)") - print('=============') - try: - print(api.permissive.owner.get(path)) - except Exception as pouet: - try: - print(api.permissive.owner.get(path, 0)) - except Exception as pouet: - print(pouet) - pass @autocheck @@ -248,9 +240,9 @@ def autocheck_reset_value(api, path, **kwargs): isslave = api.permissive.option.isslave(path) else: raises(PropertiesOptionError, "api.permissive.option.ismulti(path)") - multi = False - ismaster = False - isslave = False + multi = api.unrestraint.option.ismulti(path) + ismaster = api.unrestraint.option.ismaster(path) + isslave = api.unrestraint.option.isslave(path) # set default value (different if value is multi or not) if not multi: @@ -329,7 +321,7 @@ def autocheck_reset_value(api, path, **kwargs): @autocheck def autocheck_value2(*args, **kwargs): - """reset value + """re set value """ autocheck_value(*args, **kwargs) @@ -345,8 +337,8 @@ def autocheck_property(api, path, **kwargs): else: raises(PropertiesOptionError, "api.permissive.option.ismulti(path)") raises(PropertiesOptionError, "api.permissive.option.isslave(path)") - multi = False - isslave = False + multi = api.unrestraint.option.ismulti(path) + isslave = api.unrestraint.option.isslave(path) # define properties properties = ['prop1', 'prop2'] @@ -372,6 +364,10 @@ def autocheck_property(api, path, **kwargs): raises(PropertiesOptionError, "api.property.get(path)") # get properties with permissive + if not isslave: + raises(APIError, "api.unrestraint.property.get(path)") + else: + raises(APIError, "api.unrestraint.property.get(path, 0)") if not kwargs.get('propertyerror', False): if not isslave: assert set(api.permissive.property.get(path)) == set(default_props) @@ -455,8 +451,8 @@ def autocheck_reset_property(api, path, **kwargs): else: raises(PropertiesOptionError, "api.permissive.option.ismulti(path)") raises(PropertiesOptionError, "api.permissive.option.isslave(path)") - multi = False - isslave = False + multi = api.unrestraint.option.ismulti(path) + isslave = api.unrestraint.option.isslave(path) # define properties properties = ['prop1', 'prop2'] @@ -506,6 +502,8 @@ def autocheck_reset_property(api, path, **kwargs): assert set(api.permissive.property.get(path, 1)) == set(properties) # reset properties with permissive + raises(APIError, "api.unrestraint.property.set(path, properties)") + raises(APIError, "api.unrestraint.property.reset(path)") if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False): api.permissive.property.set(path, properties) api.permissive.property.reset(path) @@ -544,7 +542,7 @@ def autocheck_owner_with_value(api, path, **kwargs): isslave = api.permissive.option.isslave(path) else: raises(PropertiesOptionError, "api.permissive.option.isslave(path)") - isslave = False + isslave = api.unrestraint.option.isslave(path) # get owner without permissive if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False): @@ -565,9 +563,6 @@ def autocheck_owner_with_value(api, path, **kwargs): if not isslave: assert api.permissive.owner.get(path) == 'user' else: - print('--------') - print(api.permissive.owner.get(path, 0)) - print(api.permissive.value.get(path, 0)) assert api.permissive.owner.get(path, 0) == 'default' assert api.permissive.owner.get(path, 1) == 'user' else: @@ -645,6 +640,36 @@ def autocheck_set_owner(api, path, **kwargs): assert api.permissive.owner.get(path, 1) == 'new_user1' +@autocheck +def autocheck_option(api, path, **kwargs): + expected_name = path.split('.')[-1] + if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False): + current_name = api.option.getname(path) + assert current_name == api.permissive.option.getname(path) + assert current_name == api.unrestraint.option.getname(path) + doc = api.option.getdoc(path) + assert doc == api.permissive.option.getdoc(path) + assert doc == api.unrestraint.option.getdoc(path) + elif not kwargs.get('propertyerror', False): + raises(PropertiesOptionError, "api.option.getname(path)") + current_name = api.permissive.option.getname(path) + assert current_name == api.unrestraint.option.getname(path) + raises(PropertiesOptionError, "api.option.getdoc(path)") + doc = api.permissive.option.getdoc(path) + assert doc == api.unrestraint.option.getdoc(path) + else: + raises(PropertiesOptionError, "api.option.getname(path)") + raises(PropertiesOptionError, "api.permissive.option.getname(path)") + current_name = api.unrestraint.option.getname(path) + raises(PropertiesOptionError, "api.option.getdoc(path)") + raises(PropertiesOptionError, "api.permissive.option.getdoc(path)") + doc = api.unrestraint.option.getdoc(path) + assert current_name == expected_name + if expected_name.endswith('val1') or expected_name.endswith('val2'): + expected_name = expected_name[:-4] + assert doc == "{}'s option".format(expected_name) + + def check_all(api, path, multi, **kwargs): text = u' {} launch tests for {}'.format(ICON, path) if multi: @@ -729,39 +754,39 @@ def make_api(options, multi): DICT_PATHS = [ #test a config without optiondescription - {'first': 'first', - 'second': 'second_disabled', - 'third': 'third_hidden'}, + OrderedDict({'first': 'first', + 'second': 'second_disabled', + 'third': 'third_hidden'}), #test a config with an optiondescription - {'subod.first': 'subod.first', - 'subod.second': 'subod.second_disabled', - 'subod.third': 'subod.third_hidden'}, + OrderedDict({'subod.first': 'subod.first', + 'subod.second': 'subod.second_disabled', + 'subod.third': 'subod.third_hidden'}), #test a config with two optiondescription - {'subod.subsubod.first': 'subod.subsubod.first', - 'subod.subsubod.second': 'subod.subsubod.second_disabled', - 'subod.subsubod.third': 'subod.subsubod.third_hidden'}, + OrderedDict({'subod.subsubod.first': 'subod.subsubod.first', + 'subod.subsubod.second': 'subod.subsubod.second_disabled', + 'subod.subsubod.third': 'subod.subsubod.third_hidden'}), #test a config with mix of different optiondescription - {'first': 'first', - 'subod.second': 'subod.second_disabled', - 'subod.subsubod.third': 'subod.subsubod.third_hidden'}, + OrderedDict({'first': 'first', + 'subod.second': 'subod.second_disabled', + 'subod.subsubod.third': 'subod.subsubod.third_hidden'}), #test a config with masterslaves - {'first.first': 'first_master.first', - 'first.second': 'first_master.second_disabled', - 'first.third': 'first_master.third_hidden'}, + OrderedDict({'first.first': 'first_master.first', + 'first.second': 'first_master.second_disabled', + 'first.third': 'first_master.third_hidden'}), ##test a config with dynoption - {'subodval1.firstval1': 'subod_dyn.first', - 'subodval1.secondval1': 'subod_dyn.second_disabled', - 'subodval1.thirdval1': 'subod_dyn.third_hidden', - 'subodval2.firstval2': None, - 'subodval2.secondval2': None, - 'subodval2.thirdval2': None}, + OrderedDict({'subodval1.firstval1': 'subod_dyn.first', + 'subodval1.secondval1': 'subod_dyn.second_disabled', + 'subodval1.thirdval1': 'subod_dyn.third_hidden', + 'subodval2.firstval2': None, + 'subodval2.secondval2': None, + 'subodval2.thirdval2': None}), #test a config with dynoption subdir - {'subod.subodval1.firstval1': 'subod.subod_dyn.first', - 'subod.subodval1.secondval1': 'subod.subod_dyn.second_disabled', - 'subod.subodval1.thirdval1': 'subod.subod_dyn.third_hidden', - 'subod.subodval2.firstval2': None, - 'subod.subodval2.secondval2': None, - 'subod.subodval2.thirdval2': None} + OrderedDict({'subod.subodval1.firstval1': 'subod.subod_dyn.first', + 'subod.subodval1.secondval1': 'subod.subod_dyn.second_disabled', + 'subod.subodval1.thirdval1': 'subod.subod_dyn.third_hidden', + 'subod.subodval2.firstval2': None, + 'subod.subodval2.secondval2': None, + 'subod.subodval2.thirdval2': None}) ] @@ -794,16 +819,15 @@ def test_tree_od_permissive(): """permissive when optiondescription is hidden """ tpaths = [ - {'subod.subsubod.first': 'subod.subsubod_hidden.first', - 'subod.subsubod.second': 'subod.subsubod_hidden.second', - 'subod.subsubod.third': 'subod.subsubod_hidden.third_hidden'}, - {'subod.subodval1.firstval1': 'subod.subod_dyn_hidden.first', - 'subod.subodval1.secondval1': 'subod.subod_dyn_hidden.second', - 'subod.subodval1.thirdval1': 'subod.subod_dyn_hidden.third_hidden', - 'subod.subodval2.firstval2': None, - 'subod.subodval2.secondval2': None, - 'subod.subodval2.thirdval2': None - } + OrderedDict({'subod.subsubod.first': 'subod.subsubod_hidden.first', + 'subod.subsubod.second': 'subod.subsubod_hidden.second', + 'subod.subsubod.third': 'subod.subsubod_hidden.third_hidden'}), + OrderedDict({'subod.subodval1.firstval1': 'subod.subod_dyn_hidden.first', + 'subod.subodval1.secondval1': 'subod.subod_dyn_hidden.second', + 'subod.subodval1.thirdval1': 'subod.subod_dyn_hidden.third_hidden', + 'subod.subodval2.firstval2': None, + 'subod.subodval2.secondval2': None, + 'subod.subodval2.thirdval2': None}) ] for paths in tpaths: lpaths = list(paths.keys()) diff --git a/tiramisu/api.py b/tiramisu/api.py index e9c4eee..cfa5789 100644 --- a/tiramisu/api.py +++ b/tiramisu/api.py @@ -57,9 +57,22 @@ def resetter(func): class CommonTiramisu(object): icon = '\u2937' tmpl_help = u' {} {}: {}' + allow_unrestraint = False + + def __init__(self, config, force_permissive, force_unrestraint): + if not self.allow_unrestraint: + self._unrestraint_not_allowed(force_unrestraint) + + def _unrestraint_not_allowed(self, force_unrestraint): + if force_unrestraint: + name = self.__class__.__name__[11:].lower() + raise APIError(_('{} cannot be unrestraint').format(name)) def _get_obj_by_path(self, path, index=None): + validate = not self.force_unrestraint return self.config.unwrap_from_path(path, + validate=validate, + validate_properties=validate, force_permissive=self.force_permissive, index=index) @@ -70,7 +83,7 @@ class CommonTiramisu(object): if not hasattr(CommonTiramisu, name): raise APIError(_('unknown method {}').format(name)) else: - super(CommonTiramisu).__getattribute__(name) + super(CommonTiramisu, self).__getattribute__(name) def _help(self): txt = [] @@ -84,10 +97,13 @@ class CommonTiramisu(object): class TiramisuAPIOption(CommonTiramisu): """get information from an option""" + allow_unrestraint = True - def __init__(self, config, force_permissive): + def __init__(self, config, force_permissive, force_unrestraint): + super(TiramisuAPIOption, self).__init__(config, force_permissive, force_unrestraint) self.config = config self.force_permissive = force_permissive + self.force_unrestraint = force_unrestraint if config: self.values = self.config.cfgimpl_get_values() @@ -111,13 +127,23 @@ class TiramisuAPIOption(CommonTiramisu): opt = self._get_obj_by_path(path) return opt.impl_is_master_slaves('slave') + def getname(self, path): + opt = self._get_obj_by_path(path) + return opt.impl_getname() + + def getdoc(self, path): + opt = self._get_obj_by_path(path) + return opt.impl_get_display_name() + class TiramisuAPIOwner(CommonTiramisu): """manager option's owner""" - def __init__(self, config, force_permissive): + def __init__(self, config, force_permissive, force_unrestraint): + super(TiramisuAPIOwner, self).__init__(config, force_permissive, force_unrestraint) self.config = config self.force_permissive = force_permissive + self.force_unrestraint = force_unrestraint if config: self.values = self.config.cfgimpl_get_values() @@ -194,9 +220,11 @@ class TiramisuAPIOwner(CommonTiramisu): class TiramisuAPIProperty(CommonTiramisu): """manager option's property""" - def __init__(self, config, force_permissive): + def __init__(self, config, force_permissive, force_unrestraint): + super(TiramisuAPIProperty, self).__init__(config, force_permissive, force_unrestraint) self.config = config self.force_permissive = force_permissive + self.force_unrestraint = force_unrestraint if config: self.settings = config.cfgimpl_get_settings() @@ -229,9 +257,11 @@ class TiramisuAPIProperty(CommonTiramisu): class TiramisuAPIValue(CommonTiramisu): """manager option's value""" - def __init__(self, config, force_permissive): + def __init__(self, config, force_permissive, force_unrestraint): + super(TiramisuAPIValue, self).__init__(config, force_permissive, force_unrestraint) self.config = config self.force_permissive = force_permissive + self.force_unrestraint = force_unrestraint def append(self, path, value=undefined): opt = self._get_obj_by_path(path) @@ -288,19 +318,19 @@ class TiramisuAPIValue(CommonTiramisu): force_permissive=self.force_permissive) def _slave_reset(self, path, index): - #self._get_obj_by_path(path) - multi = self.config.getattr(path, - force_permissive=self.force_permissive) - del(multi[index]) + self._get_obj_by_path(path) + #FIXME ... _p_ ... + self.config.cfgimpl_get_values()._p_.resetvalue_index(path, index) class TiramisuAPI(object): icon = '\u2937' tmpl_help = ' {} {}: {}' - def __init__(self, config, force_permissive=False): + def __init__(self, config, force_permissive=False, force_unrestraint=False): self.config = config self.force_permissive = force_permissive + self.force_unrestraint = force_unrestraint #FIXME ? self.config.read_write() self.config.cfgimpl_get_settings().setpermissive(('hidden',)) @@ -316,9 +346,12 @@ class TiramisuAPI(object): def __getattr__(self, subfunc): if subfunc in self.registers: return self.registers[subfunc](self.config, - self.force_permissive) + self.force_permissive, + self.force_unrestraint) elif subfunc == 'permissive': - return TiramisuAPI(self.config, force_permissive=True) + return TiramisuAPI(self.config, force_permissive=True, force_unrestraint=self.force_unrestraint) + elif subfunc == 'unrestraint': + return TiramisuAPI(self.config, force_permissive=self.force_permissive, force_unrestraint=True) elif subfunc == 'help': return self._help() else: diff --git a/tiramisu/config.py b/tiramisu/config.py index f82bd74..cbb224a 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -194,13 +194,15 @@ class SubConfig(object): reset_all_cache() def cfgimpl_get_home_by_path(self, path, force_permissive=False, - returns_raise=False, _setting_properties=undefined): + returns_raise=False, _setting_properties=undefined, + validate_properties=True): """:returns: tuple (config, name)""" path = path.split('.') for step in path[:-1]: self = self.getattr(step, force_permissive=force_permissive, returns_raise=returns_raise, + validate_properties=validate_properties, _setting_properties=_setting_properties) if isinstance(self, Exception): return self, None @@ -382,7 +384,8 @@ class SubConfig(object): def getattr(self, name, force_permissive=False, validate=True, _setting_properties=undefined, _self_properties=undefined, index=None, - returns_raise=False, returns_option=False): + returns_raise=False, returns_option=False, + validate_properties=True): """ attribute notation mechanism for accessing the value of an option :param name: attribute name @@ -397,6 +400,7 @@ class SubConfig(object): if '.' in name: homeconfig, name = self.cfgimpl_get_home_by_path( name, force_permissive=force_permissive, + validate_properties=validate_properties, returns_raise=returns_raise, _setting_properties=_setting_properties) if isinstance(homeconfig, Exception): cfg = homeconfig @@ -405,7 +409,8 @@ class SubConfig(object): validate=validate, _setting_properties=_setting_properties, _self_properties=_self_properties, - index=index, returns_raise=returns_raise) + index=index, returns_raise=returns_raise, + validate_properties=validate_properties) else: option = self.cfgimpl_get_description().__getattr__(name, context=context) @@ -417,6 +422,7 @@ class SubConfig(object): force_permissive=force_permissive, setting_properties=_setting_properties, self_properties=_self_properties, + validate_properties=validate_properties, index=index) elif option._is_symlinkoption(): # pragma: no dynoptiondescription cover path = context.cfgimpl_get_description().impl_get_path_by_opt( @@ -425,18 +431,20 @@ class SubConfig(object): force_permissive=force_permissive, _setting_properties=_setting_properties, _self_properties=_self_properties, + validate_properties=validate_properties, index=index, returns_raise=True) elif option.impl_is_optiondescription(): - props = self.cfgimpl_get_settings().validate_properties( - option, True, False, path=subpath, - force_permissive=force_permissive, - self_properties=_self_properties, - setting_properties=_setting_properties) - if props: - if returns_raise: - return props - else: - raise props + if validate_properties: + props = self.cfgimpl_get_settings().validate_properties( + option, True, False, path=subpath, + force_permissive=force_permissive, + self_properties=_self_properties, + setting_properties=_setting_properties) + if props: + if returns_raise: + return props + else: + raise props return SubConfig(option, self._impl_context, subpath) else: if validate: @@ -454,6 +462,7 @@ class SubConfig(object): force_permissive=force_permissive, setting_properties=_setting_properties, self_properties=_self_properties, + validate_properties=validate_properties, index=index) if not returns_raise and isinstance(cfg, Exception): raise cfg @@ -727,7 +736,8 @@ class _CommonConfig(SubConfig): return self.cfgimpl_get_values().getowner(opt, index=index, force_permissive=force_permissive) - def unwrap_from_path(self, path, force_permissive=False, index=None): + def unwrap_from_path(self, path, force_permissive=False, index=None, + validate_properties=True, validate=True): """convenience method to extract and Option() object from the Config() and it is **fast**: finds the option directly in the appropriate namespace @@ -737,8 +747,14 @@ class _CommonConfig(SubConfig): context = self._cfgimpl_get_context() if '.' in path: self, path = self.cfgimpl_get_home_by_path(path, + validate_properties=validate_properties, force_permissive=force_permissive) - return self.getattr(path, force_permissive=force_permissive, index=index, returns_option=True) + return self.getattr(path, + validate_properties=validate_properties, + validate=validate, + force_permissive=force_permissive, + index=index, + returns_option=True) def cfgimpl_get_path(self, dyn=True): return None