merge ValueWarning | ValueOptionError | ValueErrorWarning

This commit is contained in:
Emmanuel Garette 2019-02-12 21:08:53 +01:00
parent a59d25fc14
commit 526fe892d0
4 changed files with 135 additions and 62 deletions

View file

@ -102,6 +102,12 @@ def test_consistency_warnings_only_option():
api.option('a').value.reset() api.option('a').value.reset()
api.option('b').value.set(1) api.option('b').value.set(1)
raises(ValueError, "api.option('a').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(): def test_consistency_not_equal():
@ -117,6 +123,12 @@ def test_consistency_not_equal():
api.option('a').value.set(1) api.option('a').value.set(1)
raises(ValueError, "api.option('b').value.set(1)") raises(ValueError, "api.option('b').value.set(1)")
api.option('b').value.set(2) 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(): def test_consistency_not_equal_many_opts():
@ -148,6 +160,15 @@ def test_consistency_not_equal_many_opts():
api.option('d').value.set(3) api.option('d').value.set(3)
raises(ValueError, "api.option('c').value.set(3)") raises(ValueError, "api.option('c').value.set(3)")
raises(ValueError, "api.option('e').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(): 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('a').value.set(3)")
raises(ValueError, "api.option('c').value.set(3)") raises(ValueError, "api.option('c').value.set(3)")
raises(ValueError, "api.option('e').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(): 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.c').value.set([1, 2])")
raises(ValueError, "cfg.option('c.d', 0).value.set(1)") raises(ValueError, "cfg.option('c.d', 0).value.set(1)")
raises(ValueError, "cfg.option('c.d', 1).value.set(4)") 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(): 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])") raises(ValueError, "api.option('a.a').value.set([1])")
api.option('a.a').value.set([2]) api.option('a.a').value.set([2])
api.option('a.a').value.reset() 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(): def test_consistency_not_equal_multi():
@ -365,6 +401,11 @@ def test_consistency_not_equal_multi():
api.option('a').value.set([2, 3]) api.option('a').value.set([2, 3])
raises(ValueError, "api.option('a').value.set([2, 3, 3])") raises(ValueError, "api.option('a').value.set([2, 3, 3])")
raises(ValueError, "api.option('b').value.set([2, 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(): 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] assert api.option('b').value.get() == [1, 2]
raises(ValueError, "api.option('a').value.set([1])") raises(ValueError, "api.option('a').value.set([1])")
raises(ValueError, "api.option('b').value.set([1, 2, 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(): def test_consistency_default():
@ -438,6 +484,11 @@ def test_consistency_default_diff():
assert api.option('a').owner.get() == owner assert api.option('a').owner.get() == owner
raises(ValueError, "api.option('a').value.reset()") raises(ValueError, "api.option('a').value.reset()")
assert api.option('a').owner.get() == owner 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(): def test_consistency_ip_netmask():
@ -457,6 +508,11 @@ def test_consistency_ip_netmask():
api.option('b').value.reset() api.option('b').value.reset()
api.option('a').value.set('192.168.1.255') api.option('a').value.set('192.168.1.255')
raises(ValueError, "api.option('b').value.set('255.255.255.0')") 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(): 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('a').value.set('192.168.1.0')
api.option('b').value.set('255.255.255.0') api.option('b').value.set('255.255.255.0')
raises(ValueError, "api.option('a').value.set('192.168.1.1')") 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(): 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.255')
api.option('a.b', 0).value.set('255.255.255.0') api.option('a.b', 0).value.set('255.255.255.0')
raises(ValueError, "api.option('a.a').value.set(['192.168.1.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(): 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.option('a').value.set('192.168.1.1')
api.property.pop('disabled') api.property.pop('disabled')
raises(ValueError, "api.option('a').value.set('192.168.2.1')") 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): def return_val(*args, **kwargs):

View file

@ -114,6 +114,12 @@ def test_validator():
except ValueError as err: except ValueError as err:
msg = _('"{0}" is an invalid {1} for "{2}", {3}').format('val', _('string'), 'opt2', 'test error return_false') msg = _('"{0}" is an invalid {1} for "{2}", {3}').format('val', _('string'), 'opt2', 'test error return_false')
assert str(err) == msg 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(): def test_validator_params():
@ -124,6 +130,11 @@ def test_validator_params():
api = Config(root) api = Config(root)
assert api.option('opt1').value.get() == 'val' assert api.option('opt1').value.get() == 'val'
raises(ValueError, "api.option('opt2').value.set('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(): def test_validator_params_value_values():
@ -303,6 +314,11 @@ def test_validator_params_context_value():
assert api.option('opt2').value.get() == 'val' assert api.option('opt2').value.get() == 'val'
api.option('opt1').value.set('no') api.option('opt1').value.set('no')
raises(ValueError, "assert api.option('opt2').value.get()") 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(): def test_validator_params_key():
@ -321,6 +337,11 @@ def test_validator_params_option():
assert api.option('opt1').value.get() == 'val' assert api.option('opt1').value.get() == 'val'
api.option('opt0').value.set('val') api.option('opt0').value.set('val')
raises(ValueError, "api.option('opt1').value.get()") 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(): def test_validator_multi():
@ -331,6 +352,11 @@ def test_validator_multi():
api.option('opt1').value.set(['val']) api.option('opt1').value.set(['val'])
assert api.option('opt1').value.get() == ['val'] assert api.option('opt1').value.get() == ['val']
raises(ValueError, "api.option('opt1').value.set(['val', 'val1'])") 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(): def test_validator_warning():
@ -405,6 +431,12 @@ def test_validator_warning_disabled():
api.option('opt2').value.set('val') api.option('opt2').value.set('val')
api.option('opt3').value.set(['val', 'val1', 'val']) api.option('opt3').value.set(['val', 'val1', 'val'])
assert w == [] 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(): def test_validator_warning_master_slave():

View file

@ -154,62 +154,26 @@ class ConstError(TypeError):
pass pass
#Warning class _CommonError:
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):
def __init__(self, def __init__(self,
val, val,
display_type, display_type,
opt, opt,
err_msg): err_msg):
self.prefix = _('"{0}" is an invalid {1} for "{2}"' self.val = val
'').format(val, self.display_type = display_type
display_type,
opt.impl_get_display_name())
self.opt = weakref.ref(opt) self.opt = weakref.ref(opt)
self.err_msg = err_msg self.err_msg = err_msg
super().__init__(self.err_msg)
def __str__(self): 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 self.err_msg:
if msg: if msg:
msg += ', {}'.format(self.err_msg) msg += ', {}'.format(self.err_msg)
@ -220,5 +184,17 @@ class ValueOptionError(ValueError):
return msg 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): class APIError(Exception):
pass pass

View file

@ -299,14 +299,10 @@ class Option(BaseOption):
is_warnings_only) is_warnings_only)
except ValueError as err: except ValueError as err:
if is_warnings_only: if is_warnings_only:
msg = _('attention, "{0}" could be an invalid {1} for "{2}"' warnings.warn_explicit(ValueWarning(_value,
'').format(val, self._display_name,
self._display_name, self,
self.impl_get_display_name()) err_msg = '{0}'.format(err)),
err_msg = '{0}'.format(err)
if err_msg:
msg += ', {}'.format(err_msg)
warnings.warn_explicit(ValueWarning(msg, weakref.ref(self)),
ValueWarning, ValueWarning,
self.__class__.__name__, 0) self.__class__.__name__, 0)
else: else:
@ -355,7 +351,7 @@ class Option(BaseOption):
self._display_name, self._display_name,
option_bag.ori_option, option_bag.ori_option,
'{0}'.format(err)) '{0}'.format(err))
warnings.warn_explicit(ValueOptionError(val, warnings.warn_explicit(ValueErrorWarning(val,
self._display_name, self._display_name,
option_bag.ori_option, option_bag.ori_option,
'{0}'.format(err)), '{0}'.format(err)),
@ -636,12 +632,10 @@ class Option(BaseOption):
context) context)
except ValueError as err: except ValueError as err:
if warnings_only: if warnings_only:
msg = _('attention, "{0}" could be an invalid {1} for "{2}", {3}' warnings.warn_explicit(ValueWarning(value,
'').format(value, self._display_name,
self._display_name, current_opt,
current_opt.impl_get_display_name(), "{}".format(err)),
err)
warnings.warn_explicit(ValueWarning(msg, weakref.ref(current_opt)),
ValueWarning, ValueWarning,
self.__class__.__name__, 0) self.__class__.__name__, 0)
else: else: