diff --git a/test/test_mandatory.py b/test/test_mandatory.py index 6ed8084..b28a620 100644 --- a/test/test_mandatory.py +++ b/test/test_mandatory.py @@ -400,7 +400,6 @@ def test_mandatory_warnings_ro(): config.str = 'a' config.read_only() assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str1', 'unicode2', 'str3'] - assert list(config.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) == ['str1', 'unicode2', 'str3'] try: delete_session('config', config.impl_getsessionid()) except ValueError: @@ -417,7 +416,6 @@ def test_mandatory_warnings_rw(): assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3'] config.str = 'a' assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str1', 'unicode2', 'str3'] - assert list(config.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) == ['str1', 'unicode2', 'str3'] try: delete_session('config', 'man100') except ValueError: @@ -435,7 +433,6 @@ def test_mandatory_warnings_disabled(): assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3'] setting[descr.str].append('disabled') assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str1', 'unicode2', 'str3'] - assert list(config.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) == ['str1', 'unicode2', 'str3'] try: delete_session('config', 'man101') except ValueError: @@ -453,8 +450,7 @@ def test_mandatory_warnings_hidden(): config.str assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3'] setting[descr.str].append('hidden') - assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str1', 'unicode2', 'str3'] - assert list(config.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) == ['str', 'str1', 'unicode2', 'str3'] + assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3'] try: delete_session('config', 'man102') except ValueError: @@ -673,10 +669,8 @@ def test_mandatory_warnings_validate(): config = Config(descr, session_id='man111') config.str = '' raises(ValueError, "list(config.cfgimpl_get_values().mandatory_warnings())") - assert list(config.cfgimpl_get_values().mandatory_warnings(validate=False)) == ['str', 'str1', 'str3', 'unicode1', 'int1'] config.str = 'test' raises(ValueError, "list(config.cfgimpl_get_values().mandatory_warnings())") - assert list(config.cfgimpl_get_values().mandatory_warnings(validate=False)) == ['str1', 'str3'] try: delete_session('config', 'man111') except ValueError: @@ -689,8 +683,7 @@ def test_mandatory_warnings_validate_empty(): config = Config(descr, session_id='man112') config.str = '' config.read_only() - raises(ConfigError, "list(config.cfgimpl_get_values().mandatory_warnings())") - assert list(config.cfgimpl_get_values().mandatory_warnings(validate=False)) == ['str', 'str1', 'str3', 'unicode1'] + assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'str3', 'unicode1'] try: delete_session('config', 'man112') except ValueError: diff --git a/test/test_option_calculation.py b/test/test_option_calculation.py index 9da8103..d4fa050 100644 --- a/test/test_option_calculation.py +++ b/test/test_option_calculation.py @@ -477,7 +477,7 @@ def test_callback_master_and_slaves_master4(): cfg.read_write() cfg.cfgimpl_get_settings().append('expert') cfg.cfgimpl_get_settings().setpermissive(('expert',)) - assert list(cfg.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) == [] + assert list(cfg.cfgimpl_get_values().mandatory_warnings()) == [] def test_consistency_master_and_slaves_master_mandatory_transitive(): @@ -498,7 +498,7 @@ def test_consistency_master_and_slaves_master_mandatory_transitive(): cfg.read_write() raises(PropertiesOptionError, "cfg.val1.val1") raises(PropertiesOptionError, "cfg.val3.val3") - assert list(cfg.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) == [] + assert list(cfg.cfgimpl_get_values().mandatory_warnings()) == [] def test_consistency_master_and_slaves_master_mandatory_non_transitive(): @@ -517,7 +517,7 @@ def test_consistency_master_and_slaves_master_mandatory_non_transitive(): maconfig = OptionDescription('rootconfig', '', [interface1, interface2]) cfg = Config(maconfig) cfg.read_write() - assert list(cfg.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) == ["val1.val1"] + assert list(cfg.cfgimpl_get_values().mandatory_warnings()) == ["val1.val1"] def test_callback_master_and_slaves_master_list(): diff --git a/test/test_option_consistency.py b/test/test_option_consistency.py index 37dcc9b..f83e135 100644 --- a/test/test_option_consistency.py +++ b/test/test_option_consistency.py @@ -551,6 +551,24 @@ def test_consistency_broadcast_error(): raises(ConfigError, "c.a = ['192.168.1.0']") +def test_consistency_broadcast_warnings(): + warnings.simplefilter("always", ValueWarning) + a = NetworkOption('a', '', properties=('mandatory', 'disabled')) + b = NetmaskOption('b', '', properties=('mandatory', 'disabled')) + c = NetmaskOption('c', '', properties=('mandatory', 'disabled')) + od = OptionDescription('a', '', [a, b, c]) + b.impl_add_consistency('network_netmask', a, warnings_only=True) + c = Config(od) + with warnings.catch_warnings(record=True) as w: + c.a = '192.168.1.4' + c.b = '255.255.255.0' + assert len(w) == 1 + c.read_write() + with warnings.catch_warnings(record=True) as w: + list(c.cfgimpl_get_values().mandatory_warnings()) + assert len(w) == 0 + + def test_consistency_broadcast_default_1(): a = NetworkOption('a', '', '192.168.1.0') b = NetmaskOption('b', '', '255.255.255.128') diff --git a/tiramisu/option/baseoption.py b/tiramisu/option/baseoption.py index f7baa7f..0b656aa 100644 --- a/tiramisu/option/baseoption.py +++ b/tiramisu/option/baseoption.py @@ -403,6 +403,7 @@ class Option(OnlyOption): all_cons_vals.append(value) else: #if context, calculate value, otherwise get default value + path = None if context is not undefined: if isinstance(opt, DynSymLinkOption): path = opt.impl_getpath(context) @@ -437,7 +438,8 @@ class Option(OnlyOption): def impl_validate(self, value, context=undefined, validate=True, force_index=None, force_submulti_index=None, - current_opt=undefined, is_multi=None): + current_opt=undefined, is_multi=None, + display_warnings=True): """ :param value: the option's value :param context: Config's context @@ -507,16 +509,18 @@ class Option(OnlyOption): self.impl_get_display_name()) return ValueError(msg) warning = None - error = calculation_validator(_value) - if not error: - error = self._second_level_validation(_value, self._is_warnings_only()) - if error: - if debug: - log.debug(_('do_validation for {0}: error in value').format( - self.impl_getname()), exc_info=True) - if self._is_warnings_only(): - warning = error - error = None + error = None + if display_warnings: + error = calculation_validator(_value) + if not error: + error = self._second_level_validation(_value, self._is_warnings_only()) + if error: + if debug: + log.debug(_('do_validation for {0}: error in value').format( + self.impl_getname()), exc_info=True) + if self._is_warnings_only(): + warning = error + error = None if error is None and warning is None: # if context launch consistency validation #if context is not undefined: @@ -524,7 +528,8 @@ class Option(OnlyOption): _index, submulti_index) if ret: if isinstance(ret, ValueWarning): - warning = ret + if display_warnings: + warning = ret elif isinstance(ret, ValueError): error = ret else: @@ -991,12 +996,14 @@ class DynSymLinkOption(object): return base_path + '.' + self._dyn def impl_validate(self, value, context=undefined, validate=True, - force_index=None, force_submulti_index=None, is_multi=None): + force_index=None, force_submulti_index=None, is_multi=None, + display_warnings=True): return self._impl_getopt().impl_validate(value, context, validate, force_index, force_submulti_index, current_opt=self, - is_multi=is_multi) + is_multi=is_multi, + display_warnings=display_warnings) def impl_is_dynsymlinkoption(self): return True diff --git a/tiramisu/value.py b/tiramisu/value.py index 0a25dec..300f19e 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -203,7 +203,7 @@ class Values(object): allow_empty_list = True else: allow_empty_list = False - isempty = (not allow_empty_list and value == []) or \ + isempty = value is None or (not allow_empty_list and value == []) or \ None in value or empty in value else: isempty = value is None or value == empty @@ -225,7 +225,7 @@ class Values(object): setting_properties=undefined, self_properties=undefined, index=None, submulti_index=undefined, from_masterslave=False, with_meta=True, masterlen=undefined, check_frozen=False, - returns_raise=False, session=None): + returns_raise=False, session=None, display_warnings=True): context = self._getcontext() settings = context.cfgimpl_get_settings() if path is None: @@ -284,7 +284,8 @@ class Values(object): submulti_index=submulti_index, check_frozen=check_frozen, returns_raise=returns_raise, - session=session) + session=session, + display_warnings=display_warnings) if isinstance(val, Exception): if returns_raise: return val @@ -307,7 +308,7 @@ class Values(object): with_meta=True, setting_properties=undefined, self_properties=undefined, masterlen=undefined, check_frozen=False, returns_raise=False, - session=None): + session=None, display_warnings=True): """same has getitem but don't touch the cache index is None for slave value, if value returned is not a list, just return [] """ @@ -357,7 +358,8 @@ class Values(object): err = opt.impl_validate(value, context, 'validator' in setting_properties, force_index=force_index, - force_submulti_index=force_submulti_index) + force_submulti_index=force_submulti_index, + display_warnings=display_warnings) if err: config_error = err value = None @@ -602,15 +604,10 @@ class Values(object): def del_information(self, key, raises=True): self._p_.del_information(key, raises) - def mandatory_warnings(self, force_permissive=False, validate=True): + def mandatory_warnings(self): """convenience function to trace Options that are mandatory and where no value has been set - :param force_permissive: do raise with permissives properties - :type force_permissive: `bool` - :param validate: validate value when calculating properties - :type validate: `bool` - :returns: generator of mandatory Option's path """ context = self._getcontext() @@ -627,7 +624,7 @@ class Values(object): if opt.impl_is_optiondescription(): if not settings.validate_properties(opt, True, False, path=path, - force_permissive=force_permissive, + force_permissive=True, setting_properties=setting_properties): for path in _mandatory_warnings(opt, currpath + [name]): yield path @@ -641,21 +638,19 @@ class Values(object): if 'mandatory' in self_properties or 'empty' in self_properties: err = self._get_cached_value(opt, path=path, trusted_cached_properties=False, - force_permissive=force_permissive, + force_permissive=True, setting_properties=setting_properties, self_properties=self_properties, - validate=validate, returns_raise=True) + validate=True, returns_raise=True, + display_warnings=False) if not isinstance(err, Exception): pass elif isinstance(err, PropertiesOptionError): if err.proptype == ['mandatory']: yield path elif isinstance(err, ConfigError): - if validate: - raise err - else: - #assume that uncalculated value is an empty value - yield path + #assume that uncalculated value is an empty value + yield path else: raise err