mandatory is a true property (no more MandatoryError) + tests

This commit is contained in:
2013-04-16 22:44:16 +02:00
parent 6097f3af84
commit 656b751995
7 changed files with 293 additions and 92 deletions

View File

@ -22,7 +22,7 @@
# ____________________________________________________________
#from inspect import getmembers, ismethod
from tiramisu.error import (PropertiesOptionError, ConfigError,
AmbigousOptionError, MandatoryError)
AmbigousOptionError)
from tiramisu.option import OptionDescription, Option, SymLinkOption
from tiramisu.setting import groups, Setting, apply_requires
from tiramisu.value import Values
@ -79,13 +79,13 @@ class SubConfig(object):
return homeconfig.__setattr__(name, value)
child = getattr(self._cfgimpl_descr, name)
if type(child) != SymLinkOption:
self._validate(name, getattr(self._cfgimpl_descr, name), force_permissive=force_permissive)
self._validate(name, getattr(self._cfgimpl_descr, name), value,
force_permissive=force_permissive)
self.setoption(name, child, value)
else:
child.setoption(self.cfgimpl_get_context(), value)
def _validate(self, name, opt_or_descr, force_permissive=False):
"validation for the setattr and the getattr"
def _validate_descr(self, name, opt_or_descr, force_permissive=False, is_raise=True):
if not isinstance(opt_or_descr, Option) and \
not isinstance(opt_or_descr, OptionDescription):
raise TypeError(_('unexpected object: {0}').format(repr(opt_or_descr)))
@ -98,6 +98,24 @@ class SubConfig(object):
properties = properties - set(self.cfgimpl_get_settings().get_permissive())
properties = properties - set(self.cfgimpl_get_settings().get_permissive(opt_or_descr))
properties = list(properties)
if is_raise:
if properties != []:
raise PropertiesOptionError(_("trying to access"
" to an option named: {0} with properties"
" {1}").format(name, str(properties)),
properties)
else:
return properties
def _validate(self, name, opt_or_descr, value, force_permissive=False,
force_properties=None):
"validation for the setattr and the getattr"
properties = self._validate_descr(name, opt_or_descr,
force_permissive=force_permissive,
is_raise=False)
if self.cfgimpl_get_context().cfgimpl_get_values().is_mandatory_err(
opt_or_descr, value, force_properties=force_properties):
properties.append('mandatory')
if properties != []:
raise PropertiesOptionError(_("trying to access"
" to an option named: {0} with properties"
@ -130,8 +148,8 @@ class SubConfig(object):
rootconfig = self.cfgimpl_get_context()
path = rootconfig.cfgimpl_get_description().get_path_by_opt(opt_or_descr.opt)
return rootconfig._getattr(path, validate=validate)
self._validate(name, opt_or_descr, force_permissive=force_permissive)
if isinstance(opt_or_descr, OptionDescription):
self._validate_descr(name, opt_or_descr, force_permissive=force_permissive)
children = self.cfgimpl_get_description()._children
if opt_or_descr not in children[1]:
raise AttributeError(_("{0} with name {1} object has "
@ -143,9 +161,12 @@ class SubConfig(object):
if name.startswith('_cfgimpl_'):
# if it were in __dict__ it would have been found already
object.__getattr__(self, name)
return self.cfgimpl_get_values()._getitem(opt_or_descr,
force_properties=force_properties,
validate=validate)
value = self.cfgimpl_get_values()._getitem(opt_or_descr,
validate=validate)
self._validate(name, opt_or_descr, value,
force_permissive=force_permissive,
force_properties=force_properties)
return value
def setoption(self, name, child, value):
"""effectively modifies the value of an Option()
@ -258,13 +279,12 @@ class SubConfig(object):
__repr__ = __str__
def getpaths(self, include_groups=False, allpaths=False, mandatory=False):
def getpaths(self, include_groups=False, allpaths=False):
"""returns a list of all paths in self, recursively, taking care of
the context of properties (hidden/disabled)
:param include_groups: if true, OptionDescription are included
:param allpaths: all the options (event the properties protected ones)
:param mandatory: includes the mandatory options
:returns: list of all paths
"""
paths = []
@ -274,9 +294,6 @@ class SubConfig(object):
else:
try:
getattr(self, path)
except MandatoryError:
if mandatory:
paths.append(path)
except PropertiesOptionError:
pass
else:
@ -421,12 +438,11 @@ class Config(SubConfig):
if len(candidates) == 1:
name = '.'.join(candidates[0])
homeconfig, name = self.cfgimpl_get_home_by_path(name)
try:
getattr(homeconfig, name)
except MandatoryError:
pass
except PropertiesOptionError, e:
raise e # HiddenOptionError or DisabledOptionError
getattr(homeconfig, name)
#except MandatoryError:
# pass
#except PropertiesOptionError, e:
# raise e # HiddenOptionError or DisabledOptionError
child = getattr(homeconfig._cfgimpl_descr, name)
homeconfig.setoption(name, child, value)
elif len(candidates) > 1:
@ -534,7 +550,6 @@ def mandatory_warnings(config):
for path in config.cfgimpl_get_description().getpaths(include_groups=True):
try:
config._getattr(path, force_properties=('mandatory',))
except MandatoryError:
yield path
except PropertiesOptionError:
pass
except PropertiesOptionError, err:
if err.proptype == ['mandatory']:
yield path

View File

@ -1,3 +1,25 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# The original `Config` design model is unproudly borrowed from
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
#ValueError if function's parameter not correct
# or if not logical
# or if validation falied
@ -34,11 +56,6 @@ class RequirementRecursionError(StandardError):
pass
class MandatoryError(Exception):
"mandatory error"
pass
class MultiTypeError(Exception):
"""multi must be a list
or error with multi length"""

View File

@ -78,7 +78,7 @@ class Option(BaseInformation):
"""
__slots__ = ('_name', '_requires', '_multi', '_validator', '_default_multi',
'_default', '_properties', '_callback', '_multitype',
'_master_slaves', '_consistencies')
'_master_slaves', '_consistencies', '_empty')
def __init__(self, name, doc, default=None, default_multi=None,
requires=None, multi=False, callback=None,
@ -110,6 +110,7 @@ class Option(BaseInformation):
validate_requires_arg(requires, self._name)
self._requires = requires
self._multi = multi
self._empty = ''
self._consistencies = None
if validator is not None:
if type(validator) != FunctionType:

View File

@ -17,7 +17,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# ____________________________________________________________
from tiramisu.error import MandatoryError, MultiTypeError, ConfigError
from tiramisu.error import MultiTypeError, ConfigError
from tiramisu.setting import owners, multitypes
from tiramisu.autolib import carry_out_calculation
from tiramisu.i18n import _
@ -67,36 +67,25 @@ class Values(object):
def _is_empty(self, opt, value):
"convenience method to know if an option is empty"
#FIXME: buggy ?
#if value is not None:
# return False
if (not opt.is_multi() and value is None) or \
empty = opt._empty
if (not opt.is_multi() and (value is None or value == empty)) or \
(opt.is_multi() and (value == [] or
None in self._get_value(opt))):
None in value or empty in value)):
return True
if self.is_default_owner(opt) and opt.is_empty_by_default():
return True
return False
def _test_mandatory(self, opt, value, force_properties=None):
def is_mandatory_err(self, opt, value, force_properties=None):
setting = self.context.cfgimpl_get_settings()
if force_properties is None:
set_mandatory = setting.has_property('mandatory')
else:
set_mandatory = setting.has_property('mandatory')
if force_properties is not None:
set_mandatory = ('mandatory' in force_properties or
setting.has_property('mandatory'))
if setting.has_property('mandatory', opt, False) and set_mandatory:
if self._is_empty(opt, value) and opt.is_empty_by_default():
raise MandatoryError(_("option: {0} is mandatory "
"and shall have a value").format(opt._name))
#empty value
if opt.is_multi():
for val in value:
if val == '':
raise MandatoryError(_("option: {0} is mandatory "
"and shall have not empty value").format(opt._name))
else:
if value == '':
raise MandatoryError(_("option: {0} is mandatory "
"and shall have not empty value").format(opt._name))
set_mandatory)
if set_mandatory and setting.has_property('mandatory', opt, False) and \
self._is_empty(opt, value):
return True
return False
def fill_multi(self, opt, result):
"""fills a multi option with default and calculated values
@ -118,7 +107,7 @@ class Values(object):
def __getitem__(self, opt):
return self._getitem(opt)
def _getitem(self, opt, force_properties=None, validate=True):
def _getitem(self, opt, validate=True):
# options with callbacks
value = self._get_value(opt)
setting = self.context.cfgimpl_get_settings()
@ -142,13 +131,12 @@ class Values(object):
value = opt.getdefault()
if opt.is_multi():
value = self.fill_multi(opt, value)
self._test_mandatory(opt, value, force_properties)
if validate and not opt.validate(value, self.context, setting.has_property('validator')):
raise ValueError(_('invalid calculated value returned'
' for option {0}: {1}').format(opt._name, value))
if self.is_default_owner(opt) and \
setting.has_property('force_store_value', opt, False):
self.setitem(opt, value)
self.setitem(opt, value, validate=validate)
return value
def __setitem__(self, opt, value):
@ -182,7 +170,6 @@ class Values(object):
if type(value) == list:
raise MultiTypeError(_("the type of the value {0} which is multi shall "
"be Multi and not list").format(str(value)))
self._test_mandatory(opt, value)
self.values[opt] = (self.context.cfgimpl_get_settings().getowner(), value)
def __contains__(self, opt):