use warnings instead of a new dictionary
This commit is contained in:
parent
f040d3da61
commit
f4677b9ef9
4 changed files with 112 additions and 69 deletions
|
@ -1,9 +1,11 @@
|
||||||
import autopath
|
import autopath
|
||||||
|
import warnings
|
||||||
from py.test import raises
|
from py.test import raises
|
||||||
|
|
||||||
from tiramisu.config import Config
|
from tiramisu.config import Config
|
||||||
from tiramisu.option import StrOption, OptionDescription
|
from tiramisu.option import StrOption, OptionDescription
|
||||||
from tiramisu.setting import groups
|
from tiramisu.setting import groups
|
||||||
|
from tiramisu.error import ValueWarning
|
||||||
|
|
||||||
|
|
||||||
def return_true(value, param=None):
|
def return_true(value, param=None):
|
||||||
|
@ -76,24 +78,36 @@ def test_validator_warning():
|
||||||
root = OptionDescription('root', '', [opt1, opt2, opt3])
|
root = OptionDescription('root', '', [opt1, opt2, opt3])
|
||||||
cfg = Config(root)
|
cfg = Config(root)
|
||||||
assert cfg.opt1 == 'val'
|
assert cfg.opt1 == 'val'
|
||||||
|
warnings.simplefilter("always", ValueWarning)
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
cfg.opt1 = 'val'
|
cfg.opt1 = 'val'
|
||||||
assert cfg.cfgimpl_get_values().has_warning() is False
|
assert w == []
|
||||||
|
#
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
cfg.opt2 = 'val'
|
cfg.opt2 = 'val'
|
||||||
assert cfg.cfgimpl_get_values().has_warning() is True
|
assert len(w) == 1
|
||||||
assert cfg.cfgimpl_get_values().get_warnings() == {opt2: 'invalid value val for option opt2: error'}
|
assert w[0].message.opt == opt2
|
||||||
assert cfg.cfgimpl_get_values().has_warning() is False
|
assert str(w[0].message) == 'invalid value val for option opt2: error'
|
||||||
|
#
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
cfg.opt3.append('val')
|
cfg.opt3.append('val')
|
||||||
assert cfg.cfgimpl_get_values().has_warning() is False
|
assert w == []
|
||||||
|
#
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
cfg.opt3.append('val1')
|
cfg.opt3.append('val1')
|
||||||
assert cfg.cfgimpl_get_values().has_warning() is True
|
assert len(w) == 1
|
||||||
assert cfg.cfgimpl_get_values().get_warnings() == {opt3: 'invalid value val1 for option opt3: error'}
|
assert w[0].message.opt == opt3
|
||||||
assert cfg.cfgimpl_get_values().has_warning() is False
|
assert str(w[0].message) == 'invalid value val1 for option opt3: error'
|
||||||
raises(ValueError, "cfg.opt2 = 1")
|
raises(ValueError, "cfg.opt2 = 1")
|
||||||
|
#
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
cfg.opt2 = 'val'
|
cfg.opt2 = 'val'
|
||||||
cfg.opt3.append('val')
|
cfg.opt3.append('val')
|
||||||
assert cfg.cfgimpl_get_values().has_warning() is True
|
assert len(w) == 2
|
||||||
assert cfg.cfgimpl_get_values().get_warnings() == {opt2: 'invalid value val for option opt2: error', opt3: 'invalid value val1 for option opt3: error'}
|
assert w[0].message.opt == opt2
|
||||||
assert cfg.cfgimpl_get_values().has_warning() is False
|
assert str(w[0].message) == 'invalid value val for option opt2: error'
|
||||||
|
assert w[1].message.opt == opt3
|
||||||
|
assert str(w[1].message) == 'invalid value val1 for option opt3: error'
|
||||||
|
|
||||||
|
|
||||||
def test_validator_warning_master_slave():
|
def test_validator_warning_master_slave():
|
||||||
|
@ -104,18 +118,38 @@ def test_validator_warning_master_slave():
|
||||||
assert interface1.impl_get_group_type() == groups.master
|
assert interface1.impl_get_group_type() == groups.master
|
||||||
root = OptionDescription('root', '', [interface1])
|
root = OptionDescription('root', '', [interface1])
|
||||||
cfg = Config(root)
|
cfg = Config(root)
|
||||||
|
warnings.simplefilter("always", ValueWarning)
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
cfg.ip_admin_eth0.ip_admin_eth0.append(None)
|
cfg.ip_admin_eth0.ip_admin_eth0.append(None)
|
||||||
assert cfg.cfgimpl_get_values().has_warning() is False
|
assert w == []
|
||||||
|
#
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
cfg.ip_admin_eth0.netmask_admin_eth0 = ['val1']
|
cfg.ip_admin_eth0.netmask_admin_eth0 = ['val1']
|
||||||
assert cfg.ip_admin_eth0.netmask_admin_eth0 == ['val1']
|
assert len(w) == 1
|
||||||
assert cfg.cfgimpl_get_values().has_warning() is True
|
assert w[0].message.opt == netmask_admin_eth0
|
||||||
assert cfg.cfgimpl_get_values().get_warnings() == {netmask_admin_eth0: 'invalid value val1 for option netmask_admin_eth0: error'}
|
assert str(w[0].message) == 'invalid value val1 for option netmask_admin_eth0: error'
|
||||||
|
#
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
cfg.ip_admin_eth0.ip_admin_eth0 = ['val']
|
cfg.ip_admin_eth0.ip_admin_eth0 = ['val']
|
||||||
assert cfg.ip_admin_eth0.ip_admin_eth0 == ['val']
|
assert len(w) == 1
|
||||||
assert cfg.cfgimpl_get_values().get_warnings() == {ip_admin_eth0: 'invalid value val for option ip_admin_eth0: error'}
|
assert w[0].message.opt == ip_admin_eth0
|
||||||
|
assert str(w[0].message) == 'invalid value val for option ip_admin_eth0: error'
|
||||||
|
#
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
cfg.ip_admin_eth0.ip_admin_eth0 = ['val', 'val1', 'val1']
|
cfg.ip_admin_eth0.ip_admin_eth0 = ['val', 'val1', 'val1']
|
||||||
assert cfg.cfgimpl_get_values().get_warnings() == {ip_admin_eth0: 'invalid value val for option ip_admin_eth0: error'}
|
assert len(w) == 1
|
||||||
|
assert w[0].message.opt == ip_admin_eth0
|
||||||
|
assert str(w[0].message) == 'invalid value val for option ip_admin_eth0: error'
|
||||||
|
#
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val', 'val1']
|
cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val', 'val1']
|
||||||
assert cfg.cfgimpl_get_values().get_warnings() == {ip_admin_eth0: 'invalid value val for option ip_admin_eth0: error'}
|
assert len(w) == 1
|
||||||
|
assert w[0].message.opt == ip_admin_eth0
|
||||||
|
assert str(w[0].message) == 'invalid value val for option ip_admin_eth0: error'
|
||||||
|
#
|
||||||
|
warnings.resetwarnings()
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val1', 'val']
|
cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val1', 'val']
|
||||||
assert cfg.cfgimpl_get_values().get_warnings() == {ip_admin_eth0: 'invalid value val for option ip_admin_eth0: error'}
|
assert len(w) == 1
|
||||||
|
assert w[0].message.opt == ip_admin_eth0
|
||||||
|
assert str(w[0].message) == 'invalid value val for option ip_admin_eth0: error'
|
||||||
|
|
|
@ -61,3 +61,35 @@ class SlaveError(Exception):
|
||||||
class ConstError(TypeError):
|
class ConstError(TypeError):
|
||||||
"no uniq value in _NameSpace"
|
"no uniq value in _NameSpace"
|
||||||
pass
|
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.config import Config
|
||||||
|
>>> warnings.simplefilter("always", ValueWarning)
|
||||||
|
>>> def a(val):
|
||||||
|
... raise ValueError('pouet')
|
||||||
|
...
|
||||||
|
>>> s=StrOption('s', '', validator=a, only_warning=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
|
||||||
|
super(ValueWarning, self).__init__(msg)
|
||||||
|
|
|
@ -25,8 +25,9 @@ import sys
|
||||||
from copy import copy, deepcopy
|
from copy import copy, deepcopy
|
||||||
from types import FunctionType
|
from types import FunctionType
|
||||||
from IPy import IP
|
from IPy import IP
|
||||||
|
import warnings
|
||||||
|
|
||||||
from tiramisu.error import ConflictError
|
from tiramisu.error import ConflictError, ValueWarning
|
||||||
from tiramisu.setting import groups, multitypes
|
from tiramisu.setting import groups, multitypes
|
||||||
from tiramisu.i18n import _
|
from tiramisu.i18n import _
|
||||||
from tiramisu.autolib import carry_out_calculation
|
from tiramisu.autolib import carry_out_calculation
|
||||||
|
@ -474,7 +475,6 @@ class Option(BaseOption):
|
||||||
def do_validation(_value, _index=None):
|
def do_validation(_value, _index=None):
|
||||||
if _value is None:
|
if _value is None:
|
||||||
return
|
return
|
||||||
ret_validation = None
|
|
||||||
try:
|
try:
|
||||||
# valid with self._validator
|
# valid with self._validator
|
||||||
val_validator(_value)
|
val_validator(_value)
|
||||||
|
@ -486,12 +486,13 @@ class Option(BaseOption):
|
||||||
msg = _("invalid value {0} for option {1}: {2}").format(
|
msg = _("invalid value {0} for option {1}: {2}").format(
|
||||||
_value, self._name, err)
|
_value, self._name, err)
|
||||||
if self._only_warning:
|
if self._only_warning:
|
||||||
ret_validation = msg
|
warnings.warn_explicit(ValueWarning(msg, self),
|
||||||
|
ValueWarning,
|
||||||
|
self.__class__.__name__, 0)
|
||||||
else:
|
else:
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
# option validation
|
# option validation
|
||||||
self._validate(_value)
|
self._validate(_value)
|
||||||
return ret_validation
|
|
||||||
|
|
||||||
# generic calculation
|
# generic calculation
|
||||||
if context is not None:
|
if context is not None:
|
||||||
|
|
|
@ -33,7 +33,7 @@ class Values(object):
|
||||||
but the values are physicaly located here, in `Values`, wich is also
|
but the values are physicaly located here, in `Values`, wich is also
|
||||||
responsible of a caching utility.
|
responsible of a caching utility.
|
||||||
"""
|
"""
|
||||||
__slots__ = ('context', '_warning', '_p_', '__weakref__')
|
__slots__ = ('context', '_p_', '__weakref__')
|
||||||
|
|
||||||
def __init__(self, context, storage):
|
def __init__(self, context, storage):
|
||||||
"""
|
"""
|
||||||
|
@ -45,7 +45,6 @@ class Values(object):
|
||||||
self.context = weakref.ref(context)
|
self.context = weakref.ref(context)
|
||||||
# the storage type is dictionary or sqlite3
|
# the storage type is dictionary or sqlite3
|
||||||
self._p_ = storage
|
self._p_ = storage
|
||||||
self._warning = {}
|
|
||||||
|
|
||||||
def _getdefault(self, opt):
|
def _getdefault(self, opt):
|
||||||
"""
|
"""
|
||||||
|
@ -107,9 +106,9 @@ class Values(object):
|
||||||
path = self._get_opt_path(opt)
|
path = self._get_opt_path(opt)
|
||||||
if self._p_.hasvalue(path):
|
if self._p_.hasvalue(path):
|
||||||
setting = self.context().cfgimpl_get_settings()
|
setting = self.context().cfgimpl_get_settings()
|
||||||
self._setwarning(opt.impl_validate(opt.impl_getdefault(),
|
opt.impl_validate(opt.impl_getdefault(),
|
||||||
self.context(),
|
self.context(),
|
||||||
'validator' in setting), opt)
|
'validator' in setting)
|
||||||
self.context().cfgimpl_reset_cache()
|
self.context().cfgimpl_reset_cache()
|
||||||
if (opt.impl_is_multi() and
|
if (opt.impl_is_multi() and
|
||||||
opt.impl_get_multitype() == multitypes.master):
|
opt.impl_get_multitype() == multitypes.master):
|
||||||
|
@ -231,8 +230,7 @@ class Values(object):
|
||||||
else:
|
else:
|
||||||
value = self._getvalue(opt, path, validate)
|
value = self._getvalue(opt, path, validate)
|
||||||
if config_error is None and validate:
|
if config_error is None and validate:
|
||||||
self._setwarning(opt.impl_validate(value, self.context(),
|
opt.impl_validate(value, self.context(), 'validator' in setting)
|
||||||
'validator' in setting), opt)
|
|
||||||
if config_error is None and self._is_default_owner(path) and \
|
if config_error is None and self._is_default_owner(path) and \
|
||||||
'force_store_value' in setting[opt]:
|
'force_store_value' in setting[opt]:
|
||||||
self.setitem(opt, value, path, is_write=False)
|
self.setitem(opt, value, path, is_write=False)
|
||||||
|
@ -253,9 +251,8 @@ class Values(object):
|
||||||
# is_write is, for example, used with "force_store_value"
|
# is_write is, for example, used with "force_store_value"
|
||||||
# user didn't change value, so not write
|
# user didn't change value, so not write
|
||||||
# valid opt
|
# valid opt
|
||||||
self._setwarning(opt.impl_validate(value, self.context(),
|
opt.impl_validate(value, self.context(),
|
||||||
'validator' in self.context(
|
'validator' in self.context().cfgimpl_get_settings())
|
||||||
).cfgimpl_get_settings()), opt)
|
|
||||||
if opt.impl_is_multi() and not isinstance(value, Multi):
|
if opt.impl_is_multi() and not isinstance(value, Multi):
|
||||||
value = Multi(value, self.context, opt, path, setitem=True)
|
value = Multi(value, self.context, opt, path, setitem=True)
|
||||||
self._setvalue(opt, path, value, force_permissive=force_permissive,
|
self._setvalue(opt, path, value, force_permissive=force_permissive,
|
||||||
|
@ -374,26 +371,6 @@ class Values(object):
|
||||||
def __setstate__(self, states):
|
def __setstate__(self, states):
|
||||||
self._p_ = states['_p_']
|
self._p_ = states['_p_']
|
||||||
|
|
||||||
def _setwarning(self, msg, opt):
|
|
||||||
if msg is not None:
|
|
||||||
self._warning[opt] = msg
|
|
||||||
|
|
||||||
def has_warning(self):
|
|
||||||
"""If option is "only_warning", validation error is store in
|
|
||||||
self._warning.
|
|
||||||
has_warning just indicate that a warning message is store
|
|
||||||
"""
|
|
||||||
return self._warning != {}
|
|
||||||
|
|
||||||
def get_warnings(self):
|
|
||||||
"""Get last warnings messages in self._warning.
|
|
||||||
We can get only one time those messages.
|
|
||||||
:returns: {opt: msg, opt1: msg1}
|
|
||||||
"""
|
|
||||||
ret = self._warning
|
|
||||||
self._warning = {}
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
# multi types
|
# multi types
|
||||||
|
@ -564,9 +541,8 @@ class Multi(list):
|
||||||
def _validate(self, value):
|
def _validate(self, value):
|
||||||
if value is not None:
|
if value is not None:
|
||||||
try:
|
try:
|
||||||
self.context().cfgimpl_get_values()._setwarning(
|
|
||||||
self.opt.impl_validate(value, context=self.context(),
|
self.opt.impl_validate(value, context=self.context(),
|
||||||
force_no_multi=True), self.opt)
|
force_no_multi=True)
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
raise ValueError(_("invalid value {0} "
|
raise ValueError(_("invalid value {0} "
|
||||||
"for option {1}: {2}"
|
"for option {1}: {2}"
|
||||||
|
|
Loading…
Reference in a new issue