diff --git a/test/test_option_consistency.py b/test/test_option_consistency.py index 39b9707..32e7cd0 100644 --- a/test/test_option_consistency.py +++ b/test/test_option_consistency.py @@ -102,6 +102,12 @@ def test_consistency_warnings_only_option(): api.option('a').value.reset() api.option('b').value.set(1) raises(ValueError, "api.option('a').value.set(1)") + # + api.property.add('demoting_error_warning') + warnings.simplefilter("always", ValueWarning) + with warnings.catch_warnings(record=True) as w: + api.option('a').value.set(1) + assert len(w) == 1 def test_consistency_not_equal(): @@ -117,6 +123,12 @@ def test_consistency_not_equal(): api.option('a').value.set(1) raises(ValueError, "api.option('b').value.set(1)") api.option('b').value.set(2) + # + api.property.add('demoting_error_warning') + warnings.simplefilter("always", ValueWarning) + with warnings.catch_warnings(record=True) as w: + api.option('b').value.set(1) + assert len(w) == 1 def test_consistency_not_equal_many_opts(): @@ -148,6 +160,15 @@ def test_consistency_not_equal_many_opts(): api.option('d').value.set(3) raises(ValueError, "api.option('c').value.set(3)") raises(ValueError, "api.option('e').value.set(3)") + # + api.property.add('demoting_error_warning') + warnings.simplefilter("always", ValueWarning) + with warnings.catch_warnings(record=True) as w: + api.option('c').value.set(3) + assert len(w) == 1 + with warnings.catch_warnings(record=True) as w: + api.option('e').value.set(3) + assert len(w) == 1 def test_consistency_not_equal_many_opts_one_disabled(): @@ -180,6 +201,11 @@ def test_consistency_not_equal_many_opts_one_disabled(): raises(ValueError, "api.option('a').value.set(3)") raises(ValueError, "api.option('c').value.set(3)") raises(ValueError, "api.option('e').value.set(3)") + # + api.property.add('demoting_error_warning') + with warnings.catch_warnings(record=True) as w: + api.option('c').value.set(3) + assert len(w) == 1 def test_consistency_not_in_config_1(): @@ -247,6 +273,11 @@ def test_consistency_mix(): raises(ValueError, "cfg.option('c.c').value.set([1, 2])") raises(ValueError, "cfg.option('c.d', 0).value.set(1)") raises(ValueError, "cfg.option('c.d', 1).value.set(4)") + # + cfg.property.add('demoting_error_warning') + with warnings.catch_warnings(record=True) as w: + cfg.option('c.d', 1).value.set(4) + assert len(w) == 1 def test_consistency_not_equal_submulti(): @@ -346,6 +377,11 @@ def test_consistency_not_equal_masterslaves_default(): raises(ValueError, "api.option('a.a').value.set([1])") api.option('a.a').value.set([2]) api.option('a.a').value.reset() + # + api.property.add('demoting_error_warning') + with warnings.catch_warnings(record=True) as w: + api.option('a.a').value.set([1]) + assert len(w) == 1 def test_consistency_not_equal_multi(): @@ -365,6 +401,11 @@ def test_consistency_not_equal_multi(): api.option('a').value.set([2, 3]) raises(ValueError, "api.option('a').value.set([2, 3, 3])") raises(ValueError, "api.option('b').value.set([2, 3])") + # + api.property.add('demoting_error_warning') + with warnings.catch_warnings(record=True) as w: + api.option('b').value.set([2, 3]) + assert len(w) == 1 def test_consistency_not_equal_multi_default1(): @@ -406,6 +447,11 @@ def test_consistency_not_equal_multi_default_modif(): assert api.option('b').value.get() == [1, 2] raises(ValueError, "api.option('a').value.set([1])") raises(ValueError, "api.option('b').value.set([1, 2, 1])") + # + api.property.add('demoting_error_warning') + with warnings.catch_warnings(record=True) as w: + api.option('b').value.set([1, 2, 1]) + assert len(w) == 1 def test_consistency_default(): @@ -438,6 +484,11 @@ def test_consistency_default_diff(): assert api.option('a').owner.get() == owner raises(ValueError, "api.option('a').value.reset()") assert api.option('a').owner.get() == owner + # + api.property.add('demoting_error_warning') + with warnings.catch_warnings(record=True) as w: + api.option('a').value.reset() + assert len(w) == 1 def test_consistency_ip_netmask(): @@ -457,6 +508,11 @@ def test_consistency_ip_netmask(): api.option('b').value.reset() api.option('a').value.set('192.168.1.255') raises(ValueError, "api.option('b').value.set('255.255.255.0')") + # + api.property.add('demoting_error_warning') + with warnings.catch_warnings(record=True) as w: + api.option('b').value.set('255.255.255.0') + assert len(w) == 1 def test_consistency_ip_netmask_invalid(): @@ -477,6 +533,11 @@ def test_consistency_network_netmask(): api.option('a').value.set('192.168.1.0') api.option('b').value.set('255.255.255.0') raises(ValueError, "api.option('a').value.set('192.168.1.1')") + # + api.property.add('demoting_error_warning') + with warnings.catch_warnings(record=True) as w: + api.option('a').value.set('192.168.1.1') + assert len(w) == 1 def test_consistency_network_netmask_invalid(): @@ -535,6 +596,11 @@ def test_consistency_ip_netmask_multi(): api.option('a.b', 0).value.set('255.255.255.255') api.option('a.b', 0).value.set('255.255.255.0') raises(ValueError, "api.option('a.a').value.set(['192.168.1.0'])") + # + api.property.add('demoting_error_warning') + with warnings.catch_warnings(record=True) as w: + api.option('a.a').value.set(['192.168.1.0']) + assert len(w) == 1 def test_consistency_network_netmask_multi(): @@ -816,6 +882,11 @@ def test_consistency_disabled_transitive_2(): api.option('a').value.set('192.168.1.1') api.property.pop('disabled') raises(ValueError, "api.option('a').value.set('192.168.2.1')") + # + api.property.add('demoting_error_warning') + with warnings.catch_warnings(record=True) as w: + api.option('a').value.set('192.168.2.1') + assert len(w) == 1 def return_val(*args, **kwargs): diff --git a/test/test_option_validator.py b/test/test_option_validator.py index 3a80325..75909f7 100644 --- a/test/test_option_validator.py +++ b/test/test_option_validator.py @@ -114,6 +114,12 @@ def test_validator(): except ValueError as err: msg = _('"{0}" is an invalid {1} for "{2}", {3}').format('val', _('string'), 'opt2', 'test error return_false') assert str(err) == msg + api.property.add('demoting_error_warning') + warnings.simplefilter("always", ValueWarning) + with warnings.catch_warnings(record=True) as w: + api.option('opt2').value.set('val') + assert len(w) == 1 + assert str(w[0].message) == msg def test_validator_params(): @@ -124,6 +130,11 @@ def test_validator_params(): api = Config(root) assert api.option('opt1').value.get() == 'val' raises(ValueError, "api.option('opt2').value.set('val')") + api.property.add('demoting_error_warning') + warnings.simplefilter("always", ValueWarning) + with warnings.catch_warnings(record=True) as w: + api.option('opt2').value.set('val') + assert len(w) == 1 def test_validator_params_value_values(): @@ -303,6 +314,11 @@ def test_validator_params_context_value(): assert api.option('opt2').value.get() == 'val' api.option('opt1').value.set('no') raises(ValueError, "assert api.option('opt2').value.get()") + api.property.add('demoting_error_warning') + warnings.simplefilter("always", ValueWarning) + with warnings.catch_warnings(record=True) as w: + api.option('opt2').value.get() + assert len(w) == 1 def test_validator_params_key(): @@ -321,6 +337,11 @@ def test_validator_params_option(): assert api.option('opt1').value.get() == 'val' api.option('opt0').value.set('val') raises(ValueError, "api.option('opt1').value.get()") + api.property.add('demoting_error_warning') + warnings.simplefilter("always", ValueWarning) + with warnings.catch_warnings(record=True) as w: + api.option('opt1').value.get() + assert len(w) == 1 def test_validator_multi(): @@ -331,6 +352,11 @@ def test_validator_multi(): api.option('opt1').value.set(['val']) assert api.option('opt1').value.get() == ['val'] raises(ValueError, "api.option('opt1').value.set(['val', 'val1'])") + api.property.add('demoting_error_warning') + warnings.simplefilter("always", ValueWarning) + with warnings.catch_warnings(record=True) as w: + api.option('opt1').value.set(['val', 'val1']) + assert len(w) == 1 def test_validator_warning(): @@ -405,6 +431,12 @@ def test_validator_warning_disabled(): api.option('opt2').value.set('val') api.option('opt3').value.set(['val', 'val1', 'val']) assert w == [] + # + api.property.add('demoting_error_warning') + warnings.simplefilter("always", ValueWarning) + with warnings.catch_warnings(record=True) as w: + api.option('opt2').value.set(1) + assert len(w) == 1 def test_validator_warning_master_slave(): diff --git a/tiramisu/error.py b/tiramisu/error.py index 4ed1c56..1fb3b6a 100644 --- a/tiramisu/error.py +++ b/tiramisu/error.py @@ -154,62 +154,26 @@ class ConstError(TypeError): pass -#Warning -class ValueWarning(UserWarning): - """Option could warn user and not raise ValueError. - - Example: - - >>> import warnings - >>> from tiramisu.error import ValueWarning - >>> from tiramisu.option import StrOption, OptionDescription - >>> from tiramisu import Config - >>> warnings.simplefilter("always", ValueWarning) - >>> def a(val): - ... raise ValueError('pouet') - ... - >>> s=StrOption('s', '', validator=a, warnings_only=True) - >>> o=OptionDescription('o', '', [s]) - >>> c=Config(o) - >>> c.s = 'val' - StrOption:0: ValueWarning: invalid value val for option s: pouet - >>> with warnings.catch_warnings(record=True) as w: - ... c.s = 'val' - ... - >>> w[0].message.opt() == s - True - >>> print(str(w[0].message)) - invalid value val for option s: pouet - """ - def __init__(self, - msg, - opt): - self.opt = opt - self.value_error = msg - super(ValueWarning, self).__init__(msg) - - -class ValueErrorWarning(ValueWarning): - def __init__(self, - value_error): - super(ValueErrorWarning, self).__init__(value_error, value_error.opt) - - -class ValueOptionError(ValueError): +class _CommonError: def __init__(self, val, display_type, opt, err_msg): - self.prefix = _('"{0}" is an invalid {1} for "{2}"' - '').format(val, - display_type, - opt.impl_get_display_name()) + self.val = val + self.display_type = display_type self.opt = weakref.ref(opt) self.err_msg = err_msg + super().__init__(self.err_msg) def __str__(self): - msg = self.prefix + try: + msg = self.prefix + except AttributeError: + self.prefix = self.tmpl.format(self.val, + self.display_type, + self.opt().impl_get_display_name()) + msg = self.prefix if self.err_msg: if msg: msg += ', {}'.format(self.err_msg) @@ -220,5 +184,17 @@ class ValueOptionError(ValueError): return msg +class ValueWarning(_CommonError, UserWarning): + tmpl = _('attention, "{0}" could be an invalid {1} for "{2}"') + + +class ValueOptionError(_CommonError, ValueError): + tmpl = _('"{0}" is an invalid {1} for "{2}"') + + +class ValueErrorWarning(ValueWarning): + tmpl = _('"{0}" is an invalid {1} for "{2}"') + + class APIError(Exception): pass diff --git a/tiramisu/option/option.py b/tiramisu/option/option.py index 16f0754..fae71a2 100644 --- a/tiramisu/option/option.py +++ b/tiramisu/option/option.py @@ -299,14 +299,10 @@ class Option(BaseOption): is_warnings_only) except ValueError as err: if is_warnings_only: - msg = _('attention, "{0}" could be an invalid {1} for "{2}"' - '').format(val, - self._display_name, - self.impl_get_display_name()) - err_msg = '{0}'.format(err) - if err_msg: - msg += ', {}'.format(err_msg) - warnings.warn_explicit(ValueWarning(msg, weakref.ref(self)), + warnings.warn_explicit(ValueWarning(_value, + self._display_name, + self, + err_msg = '{0}'.format(err)), ValueWarning, self.__class__.__name__, 0) else: @@ -355,7 +351,7 @@ class Option(BaseOption): self._display_name, option_bag.ori_option, '{0}'.format(err)) - warnings.warn_explicit(ValueOptionError(val, + warnings.warn_explicit(ValueErrorWarning(val, self._display_name, option_bag.ori_option, '{0}'.format(err)), @@ -636,12 +632,10 @@ class Option(BaseOption): context) except ValueError as err: if warnings_only: - msg = _('attention, "{0}" could be an invalid {1} for "{2}", {3}' - '').format(value, - self._display_name, - current_opt.impl_get_display_name(), - err) - warnings.warn_explicit(ValueWarning(msg, weakref.ref(current_opt)), + warnings.warn_explicit(ValueWarning(value, + self._display_name, + current_opt, + "{}".format(err)), ValueWarning, self.__class__.__name__, 0) else: