import re
import sys
from IPy import IP
+from types import FunctionType
+from tiramisu.setting import log
-from tiramisu.error import ConfigError
+from tiramisu.error import ConfigError, ContextError
from tiramisu.i18n import _
-from .baseoption import Option
+from .baseoption import Option, validate_callback
+from tiramisu.autolib import carry_out_calculation
class ChoiceOption(Option):
"""
__slots__ = tuple()
- def __init__(self, name, doc, values, default=None, default_multi=None,
- requires=None, multi=False, callback=None,
- callback_params=None, open_values=False, validator=None,
- validator_params=None, properties=None, warnings_only=False):
+ def __init__(self, name, doc, values, default=None,
+ values_params=None, default_multi=None, requires=None,
+ multi=False, callback=None, callback_params=None,
+ open_values=False, validator=None, validator_params=None,
+ properties=None, warnings_only=False):
"""
:param values: is a list of values the option can possibly take
"""
- if not isinstance(values, tuple):
- raise TypeError(_('values must be a tuple for {0}').format(name))
+ if isinstance(values, FunctionType):
+ validate_callback(values, values_params, 'values')
+ elif not isinstance(values, tuple):
+ raise TypeError(_('values must be a tuple or a function for {0}'
+ ).format(name))
if open_values not in (True, False):
raise TypeError(_('open_values must be a boolean for '
'{0}').format(name))
self._extra = {'_choice_open_values': open_values,
- '_choice_values': values}
+ '_choice_values': values,
+ '_choice_values_params': values_params}
super(ChoiceOption, self).__init__(name, doc, default=default,
default_multi=default_multi,
callback=callback,
properties=properties,
warnings_only=warnings_only)
- def impl_get_values(self):
- return self._extra['_choice_values']
+ def impl_get_values(self, context):
+ #FIXME cache? but in context...
+ values = self._extra['_choice_values']
+ if isinstance(values, FunctionType):
+ values_params = self._extra['_choice_values_params']
+ if values_params is None:
+ values_params = {}
+ values = carry_out_calculation(self, config=context,
+ callback=values,
+ callback_params=values_params)
+ if not isinstance(values, list):
+ raise ConfigError(_('calculated values for {0} is not a list'
+ '').format(self.impl_getname()))
+ return values
def impl_is_openvalues(self):
return self._extra['_choice_open_values']
- def _validate(self, value):
- if not self.impl_is_openvalues() and not value in self.impl_get_values():
- raise ValueError(_('value {0} is not permitted, '
- 'only {1} is allowed'
- '').format(value, self._extra['_choice_values']))
+ def _validate(self, value, context=None):
+ try:
+ values = self.impl_get_values(context)
+ if not self.impl_is_openvalues() and \
+ not value in values:
+ raise ValueError(_('value {0} is not permitted, '
+ 'only {1} is allowed'
+ '').format(value,
+ values))
+ except ContextError:
+ log.debug('ChoiceOption validation, disabled because no context')
class BoolOption(Option):
"represents a choice between ``True`` and ``False``"
__slots__ = tuple()
- def _validate(self, value):
+ def _validate(self, value, context=None):
if not isinstance(value, bool):
raise ValueError(_('invalid boolean'))
"represents a choice of an integer"
__slots__ = tuple()
- def _validate(self, value):
+ def _validate(self, value, context=None):
if not isinstance(value, int):
raise ValueError(_('invalid integer'))
"represents a choice of a floating point number"
__slots__ = tuple()
- def _validate(self, value):
+ def _validate(self, value, context=None):
if not isinstance(value, float):
raise ValueError(_('invalid float'))
"represents the choice of a string"
__slots__ = tuple()
- def _validate(self, value):
+ def _validate(self, value, context=None):
if not isinstance(value, str):
raise ValueError(_('invalid string'))
__slots__ = tuple()
_empty = u''
- def _validate(self, value):
+ def _validate(self, value, context=None):
if not isinstance(value, unicode):
raise ValueError(_('invalid unicode'))
properties=properties,
warnings_only=warnings_only)
- def _validate(self, value):
+ def _validate(self, value, context=None):
# sometimes an ip term starts with a zero
# but this does not fit in some case, for example bind does not like it
try:
properties=properties,
warnings_only=warnings_only)
- def _validate(self, value):
+ def _validate(self, value, context=None):
if self._extra['_allow_range'] and ":" in str(value):
value = str(value).split(':')
if len(value) != 2:
"represents the choice of a network"
__slots__ = tuple()
- def _validate(self, value):
+ def _validate(self, value, context=None):
try:
IP(value)
except ValueError:
"represents the choice of a netmask"
__slots__ = tuple()
- def _validate(self, value):
+ def _validate(self, value, context=None):
try:
IP('0.0.0.0/{0}'.format(value))
except ValueError:
class BroadcastOption(Option):
__slots__ = tuple()
- def _validate(self, value):
+ def _validate(self, value, context=None):
try:
IP('{0}/32'.format(value))
except ValueError:
properties=properties,
warnings_only=warnings_only)
- def _validate(self, value):
+ def _validate(self, value, context=None):
if self._extra['_allow_ip'] is True:
try:
IP('{0}/32'.format(value))
__slots__ = tuple()
username_re = re.compile(r"^[\w!#$%&'*+\-/=?^`{|}~.]+$")
- def _validate(self, value):
+ def _validate(self, value, context=None):
splitted = value.split('@', 1)
try:
username, domain = splitted
proto_re = re.compile(r'(http|https)://')
path_re = re.compile(r"^[a-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$")
- def _validate(self, value):
+ def _validate(self, value, context=None):
match = self.proto_re.search(value)
if not match:
raise ValueError(_('invalid url, must start with http:// or '
#regexp build with 'man 8 adduser' informations
username_re = re.compile(r"^[a-z_][a-z0-9_-]{0,30}[$a-z0-9_-]{0,1}$")
- def _validate(self, value):
+ def _validate(self, value, context=None):
match = self.username_re.search(value)
if not match:
raise ValueError(_('invalid username'))
__slots__ = tuple()
path_re = re.compile(r"^[a-zA-Z0-9\-\._~/+]+$")
- def _validate(self, value):
+ def _validate(self, value, context=None):
match = self.path_re.search(value)
if not match:
raise ValueError(_('invalid filename'))