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 warnings
|
||||
from py.test import raises
|
||||
|
||||
from tiramisu.config import Config
|
||||
from tiramisu.option import StrOption, OptionDescription
|
||||
from tiramisu.setting import groups
|
||||
from tiramisu.error import ValueWarning
|
||||
|
||||
|
||||
def return_true(value, param=None):
|
||||
|
@ -76,24 +78,36 @@ def test_validator_warning():
|
|||
root = OptionDescription('root', '', [opt1, opt2, opt3])
|
||||
cfg = Config(root)
|
||||
assert cfg.opt1 == 'val'
|
||||
warnings.simplefilter("always", ValueWarning)
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
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'
|
||||
assert cfg.cfgimpl_get_values().has_warning() is True
|
||||
assert cfg.cfgimpl_get_values().get_warnings() == {opt2: 'invalid value val for option opt2: error'}
|
||||
assert cfg.cfgimpl_get_values().has_warning() is False
|
||||
assert len(w) == 1
|
||||
assert w[0].message.opt == opt2
|
||||
assert str(w[0].message) == 'invalid value val for option opt2: error'
|
||||
#
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
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')
|
||||
assert cfg.cfgimpl_get_values().has_warning() is True
|
||||
assert cfg.cfgimpl_get_values().get_warnings() == {opt3: 'invalid value val1 for option opt3: error'}
|
||||
assert cfg.cfgimpl_get_values().has_warning() is False
|
||||
assert len(w) == 1
|
||||
assert w[0].message.opt == opt3
|
||||
assert str(w[0].message) == 'invalid value val1 for option opt3: error'
|
||||
raises(ValueError, "cfg.opt2 = 1")
|
||||
#
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.opt2 = 'val'
|
||||
cfg.opt3.append('val')
|
||||
assert cfg.cfgimpl_get_values().has_warning() is True
|
||||
assert cfg.cfgimpl_get_values().get_warnings() == {opt2: 'invalid value val for option opt2: error', opt3: 'invalid value val1 for option opt3: error'}
|
||||
assert cfg.cfgimpl_get_values().has_warning() is False
|
||||
assert len(w) == 2
|
||||
assert w[0].message.opt == opt2
|
||||
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():
|
||||
|
@ -104,18 +118,38 @@ def test_validator_warning_master_slave():
|
|||
assert interface1.impl_get_group_type() == groups.master
|
||||
root = OptionDescription('root', '', [interface1])
|
||||
cfg = Config(root)
|
||||
warnings.simplefilter("always", ValueWarning)
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
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']
|
||||
assert cfg.ip_admin_eth0.netmask_admin_eth0 == ['val1']
|
||||
assert cfg.cfgimpl_get_values().has_warning() is True
|
||||
assert cfg.cfgimpl_get_values().get_warnings() == {netmask_admin_eth0: 'invalid value val1 for option netmask_admin_eth0: error'}
|
||||
assert len(w) == 1
|
||||
assert w[0].message.opt == netmask_admin_eth0
|
||||
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']
|
||||
assert cfg.ip_admin_eth0.ip_admin_eth0 == ['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'
|
||||
#
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
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']
|
||||
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']
|
||||
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):
|
||||
"no uniq value in _NameSpace"
|
||||
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 types import FunctionType
|
||||
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.i18n import _
|
||||
from tiramisu.autolib import carry_out_calculation
|
||||
|
@ -474,7 +475,6 @@ class Option(BaseOption):
|
|||
def do_validation(_value, _index=None):
|
||||
if _value is None:
|
||||
return
|
||||
ret_validation = None
|
||||
try:
|
||||
# valid with self._validator
|
||||
val_validator(_value)
|
||||
|
@ -486,12 +486,13 @@ class Option(BaseOption):
|
|||
msg = _("invalid value {0} for option {1}: {2}").format(
|
||||
_value, self._name, err)
|
||||
if self._only_warning:
|
||||
ret_validation = msg
|
||||
warnings.warn_explicit(ValueWarning(msg, self),
|
||||
ValueWarning,
|
||||
self.__class__.__name__, 0)
|
||||
else:
|
||||
raise ValueError(msg)
|
||||
# option validation
|
||||
self._validate(_value)
|
||||
return ret_validation
|
||||
|
||||
# generic calculation
|
||||
if context is not None:
|
||||
|
|
|
@ -33,7 +33,7 @@ class Values(object):
|
|||
but the values are physicaly located here, in `Values`, wich is also
|
||||
responsible of a caching utility.
|
||||
"""
|
||||
__slots__ = ('context', '_warning', '_p_', '__weakref__')
|
||||
__slots__ = ('context', '_p_', '__weakref__')
|
||||
|
||||
def __init__(self, context, storage):
|
||||
"""
|
||||
|
@ -45,7 +45,6 @@ class Values(object):
|
|||
self.context = weakref.ref(context)
|
||||
# the storage type is dictionary or sqlite3
|
||||
self._p_ = storage
|
||||
self._warning = {}
|
||||
|
||||
def _getdefault(self, opt):
|
||||
"""
|
||||
|
@ -107,9 +106,9 @@ class Values(object):
|
|||
path = self._get_opt_path(opt)
|
||||
if self._p_.hasvalue(path):
|
||||
setting = self.context().cfgimpl_get_settings()
|
||||
self._setwarning(opt.impl_validate(opt.impl_getdefault(),
|
||||
opt.impl_validate(opt.impl_getdefault(),
|
||||
self.context(),
|
||||
'validator' in setting), opt)
|
||||
'validator' in setting)
|
||||
self.context().cfgimpl_reset_cache()
|
||||
if (opt.impl_is_multi() and
|
||||
opt.impl_get_multitype() == multitypes.master):
|
||||
|
@ -231,8 +230,7 @@ class Values(object):
|
|||
else:
|
||||
value = self._getvalue(opt, path, validate)
|
||||
if config_error is None and validate:
|
||||
self._setwarning(opt.impl_validate(value, self.context(),
|
||||
'validator' in setting), opt)
|
||||
opt.impl_validate(value, self.context(), 'validator' in setting)
|
||||
if config_error is None and self._is_default_owner(path) and \
|
||||
'force_store_value' in setting[opt]:
|
||||
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"
|
||||
# user didn't change value, so not write
|
||||
# valid opt
|
||||
self._setwarning(opt.impl_validate(value, self.context(),
|
||||
'validator' in self.context(
|
||||
).cfgimpl_get_settings()), opt)
|
||||
opt.impl_validate(value, self.context(),
|
||||
'validator' in self.context().cfgimpl_get_settings())
|
||||
if opt.impl_is_multi() and not isinstance(value, Multi):
|
||||
value = Multi(value, self.context, opt, path, setitem=True)
|
||||
self._setvalue(opt, path, value, force_permissive=force_permissive,
|
||||
|
@ -374,26 +371,6 @@ class Values(object):
|
|||
def __setstate__(self, states):
|
||||
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
|
||||
|
@ -564,9 +541,8 @@ class Multi(list):
|
|||
def _validate(self, value):
|
||||
if value is not None:
|
||||
try:
|
||||
self.context().cfgimpl_get_values()._setwarning(
|
||||
self.opt.impl_validate(value, context=self.context(),
|
||||
force_no_multi=True), self.opt)
|
||||
force_no_multi=True)
|
||||
except ValueError as err:
|
||||
raise ValueError(_("invalid value {0} "
|
||||
"for option {1}: {2}"
|
||||
|
|
Loading…
Reference in a new issue