Compare commits

..

10 Commits

48 changed files with 512 additions and 120 deletions

View File

@ -34,11 +34,38 @@ def mode_factory():
modes = mode_factory()
CONVERT_OPTION = {'number': dict(opttype="IntOption", func=int),
'float': dict(opttype="FloatOption", func=float),
'choice': dict(opttype="ChoiceOption"),
'string': dict(opttype="StrOption"),
'password': dict(opttype="PasswordOption"),
'mail': dict(opttype="EmailOption"),
'boolean': dict(opttype="BoolOption"),
'symlink': dict(opttype="SymLinkOption"),
'filename': dict(opttype="FilenameOption"),
'date': dict(opttype="DateOption"),
'unix_user': dict(opttype="UsernameOption"),
'ip': dict(opttype="IPOption", initkwargs={'allow_reserved': True}),
'local_ip': dict(opttype="IPOption", initkwargs={'private_only': True, 'warnings_only': True}),
'netmask': dict(opttype="NetmaskOption"),
'network': dict(opttype="NetworkOption"),
'broadcast': dict(opttype="BroadcastOption"),
'netbios': dict(opttype="DomainnameOption", initkwargs={'type': 'netbios', 'warnings_only': True}),
'domain': dict(opttype="DomainnameOption", initkwargs={'type': 'domainname', 'allow_ip': False}),
'hostname': dict(opttype="DomainnameOption", initkwargs={'type': 'hostname', 'allow_ip': False}),
'web_address': dict(opttype="URLOption", initkwargs={'allow_ip': True, 'allow_without_dot': True}),
'port': dict(opttype="PortOption", initkwargs={'allow_private': True}),
'mac': dict(opttype="MACOption"),
'cidr': dict(opttype="IPOption", initkwargs={'cidr': True}),
'network_cidr': dict(opttype="NetworkOption", initkwargs={'cidr': True}),
}
# a CreoleObjSpace's attribute has some annotations
# that shall not be present in the exported (flatened) XML
ERASED_ATTRIBUTES = ('redefine', 'exists', 'fallback', 'optional', 'remove_check', 'namespace',
'remove_condition', 'path', 'instance_mode', 'index', 'is_in_leadership',
'level', 'remove_fill')
'level', 'remove_fill', 'xmlfiles')
ERASED_CONTAINER_ATTRIBUTES = ('id', 'container', 'group_id', 'group', 'container_group')
FORCE_CHOICE = {'oui/non': ['oui', 'non'],
@ -56,8 +83,6 @@ KEY_TYPE = {'variable': 'symlink',
'URLOption': 'web_address',
'FilenameOption': 'filename'}
CONVERSION = {'number': int}
FREEZE_AUTOFREEZE_VARIABLE = 'module_instancie'
PROPERTIES = ('hidden', 'frozen', 'auto_freeze', 'auto_save', 'force_default_on_freeze',
@ -108,7 +133,7 @@ class GroupAnnotator:
self.manage_follower(namespace,
leader_family_name,
variable,
leader_name,
leadership_name,
follower_names,
leader_space,
leader_is_hidden,
@ -125,9 +150,14 @@ class GroupAnnotator:
# if variable.hidden:
# leader_is_hidden = True
else:
leader_space = self.objectspace.Leadership()
leader_space = self.objectspace.Leadership(variable.xmlfiles)
if hasattr(group, 'name'):
leadership_name = group.name
else:
leadership_name = leader_name
leader_is_hidden = self.manage_leader(leader_space,
leader_family_name,
leadership_name,
leader_name,
namespace,
variable,
@ -142,6 +172,7 @@ class GroupAnnotator:
def manage_leader(self,
leader_space: 'Leadership',
leader_family_name: str,
leadership_name: str,
leader_name: str,
namespace: str,
variable: 'Variable',
@ -152,7 +183,7 @@ class GroupAnnotator:
if variable.multi is not True:
raise DictConsistencyError(_('the variable {} in a group must be multi').format(variable.name))
leader_space.variable = []
leader_space.name = leader_name
leader_space.name = leadership_name
leader_space.hidden = variable.hidden
if variable.hidden:
leader_is_hidden = True
@ -167,9 +198,9 @@ class GroupAnnotator:
leader_space.doc = variable.description
else:
leader_space.doc = variable.name
leader_path = namespace + '.' + leader_family_name + '.' + leader_name
leadership_path = namespace + '.' + leader_family_name + '.' + leadership_name
self.objectspace.paths.add_family(namespace,
leader_path,
leadership_path,
leader_space,
)
leader_family = self.objectspace.space.variables[namespace].family[leader_family_name]
@ -233,7 +264,7 @@ class ServiceAnnotator:
families = {}
for idx, service_name in enumerate(self.objectspace.space.services.service.keys()):
service = self.objectspace.space.services.service[service_name]
new_service = self.objectspace.service()
new_service = self.objectspace.service(service.xmlfiles)
for elttype, values in vars(service).items():
if not isinstance(values, (dict, list)) or elttype in ERASED_ATTRIBUTES:
setattr(new_service, elttype, values)
@ -242,6 +273,7 @@ class ServiceAnnotator:
path = '.'.join(['services', service_name, eltname])
family = self.gen_family(eltname,
path,
service.xmlfiles,
)
if isinstance(values, dict):
values = list(values.values())
@ -258,8 +290,9 @@ class ServiceAnnotator:
def gen_family(self,
name,
path,
xmlfiles
):
family = self.objectspace.family()
family = self.objectspace.family(xmlfiles)
family.name = normalize_family(name)
family.doc = name
family.mode = None
@ -307,7 +340,10 @@ class ServiceAnnotator:
if not self.objectspace.paths.family_is_defined(subpath):
break
idx += 1
family = self.gen_family(c_name, subpath)
family = self.gen_family(c_name,
subpath,
elt.xmlfiles,
)
family.variable = []
listname = '{}list'.format(name)
activate_path = '.'.join([subpath, 'activate'])
@ -345,7 +381,7 @@ class ServiceAnnotator:
elt,
path,
):
variable = self.objectspace.variable()
variable = self.objectspace.variable(elt.xmlfiles)
variable.name = normalize_family(key)
variable.mode = None
if key == 'name':
@ -370,7 +406,7 @@ class ServiceAnnotator:
variable.multi = None
else:
variable.doc = key
val = self.objectspace.value()
val = self.objectspace.value(elt.xmlfiles)
val.type = type_
val.name = value
variable.value = [val]
@ -454,7 +490,7 @@ class VariableAnnotator:
for value in variable.value:
if not hasattr(value, 'type'):
value.type = variable.type
value.name = CONVERSION.get(value.type, str)(value.name)
value.name = CONVERT_OPTION.get(value.type, {}).get('func', str)(value.name)
for key, value in RENAME_ATTIBUTES.items():
setattr(variable, value, getattr(variable, key))
setattr(variable, key, None)
@ -469,23 +505,28 @@ class VariableAnnotator:
path,
):
if variable.type in FORCE_CHOICE:
check = self.objectspace.check()
check = self.objectspace.check(variable.xmlfiles)
check.name = 'valid_enum'
check.target = path
check.namespace = namespace
check.param = []
for value in FORCE_CHOICE[variable.type]:
param = self.objectspace.param()
param = self.objectspace.param(variable.xmlfiles)
param.text = value
check.param.append(param)
if not hasattr(self.objectspace.space, 'constraints'):
self.objectspace.space.constraints = self.objectspace.constraints()
self.objectspace.space.constraints = self.objectspace.constraints(variable.xmlfiles)
self.objectspace.space.constraints.namespace = namespace
if not hasattr(self.objectspace.space.constraints, 'check'):
self.objectspace.space.constraints.check = []
self.objectspace.space.constraints.check.append(check)
variable.type = 'string'
def _valid_type(variable):
if variable.type not in CONVERT_OPTION:
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
raise DictConsistencyError(_(f'unvalid type "{variable.type}" for variable "{variable.name}" in {xmlfiles}'))
if not hasattr(self.objectspace.space, 'variables'):
return
for families in self.objectspace.space.variables.values():
@ -515,6 +556,7 @@ class VariableAnnotator:
follower,
path,
)
_valid_type(follower)
else:
path = '{}.{}.{}'.format(namespace, normalize_family(family.name), variable.name)
_convert_variable(variable,
@ -524,6 +566,7 @@ class VariableAnnotator:
variable,
path,
)
_valid_type(variable)
def convert_helps(self):
if not hasattr(self.objectspace.space, 'help'):
@ -542,14 +585,14 @@ class VariableAnnotator:
def convert_auto_freeze(self): # pylint: disable=C0111
def _convert_auto_freeze(variable, namespace):
if variable.auto_freeze:
new_condition = self.objectspace.condition()
new_condition = self.objectspace.condition(variable.xmlfiles)
new_condition.name = 'auto_hidden_if_not_in'
new_condition.namespace = namespace
new_condition.source = FREEZE_AUTOFREEZE_VARIABLE
new_param = self.objectspace.param()
new_param = self.objectspace.param(variable.xmlfiles)
new_param.text = 'oui'
new_condition.param = [new_param]
new_target = self.objectspace.target()
new_target = self.objectspace.target(variable.xmlfiles)
new_target.type = 'variable'
path = variable.namespace + '.' + normalize_family(family.name) + '.' + variable.name
new_target.name = path
@ -583,7 +626,8 @@ class VariableAnnotator:
subpath = self.objectspace.paths.get_variable_path(separator.name,
separator.namespace,
)
raise DictConsistencyError(_('{} already has a separator').format(subpath))
xmlfiles = self.objectspace.display_xmlfiles(separator.xmlfiles)
raise DictConsistencyError(_(f'{subpath} already has a separator in {xmlfiles}'))
option.separator = separator.text
del family.separators
@ -622,7 +666,8 @@ class ConstraintAnnotator:
remove_indexes = []
for check_idx, check in enumerate(self.objectspace.space.constraints.check):
if not check.name in self.functions:
raise DictConsistencyError(_('cannot find check function {}').format(check.name))
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'cannot find check function "{check.name}" in {xmlfiles}'))
if hasattr(check, 'param'):
param_option_indexes = []
for idx, param in enumerate(check.param):
@ -630,7 +675,8 @@ class ConstraintAnnotator:
if param.optional is True:
param_option_indexes.append(idx)
else:
raise DictConsistencyError(_(f'unknown param {param.text} in check'))
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'cannot find check param "{param.text}" in {xmlfiles}'))
if param.type != 'variable':
param.notraisepropertyerror = None
param_option_indexes = list(set(param_option_indexes))
@ -766,7 +812,7 @@ class ConstraintAnnotator:
for listvar in listvars:
variable = self.objectspace.paths.get_variable_obj(listvar)
type_ = 'variable'
new_target = self.objectspace.target()
new_target = self.objectspace.target(variable.xmlfiles)
new_target.type = type_
new_target.name = listvar
new_target.index = target.index
@ -891,7 +937,7 @@ class ConstraintAnnotator:
if hasattr(leader_or_variable, actions[0]) and getattr(leader_or_variable, actions[0]) is True:
continue
for idx, action in enumerate(actions):
prop = self.objectspace.property_()
prop = self.objectspace.property_(leader_or_variable.xmlfiles)
prop.type = 'calculation'
prop.inverse = inverse
prop.source = condition.source
@ -924,10 +970,10 @@ class ConstraintAnnotator:
}
choices = []
for value in values:
choice = self.objectspace.choice()
choice = self.objectspace.choice(variable.xmlfiles)
try:
if value is not None:
choice.name = CONVERSION.get(type_, str)(value)
choice.name = CONVERT_OPTION[type_].get('func', str)(value)
else:
choice.name = value
except:
@ -942,13 +988,13 @@ class ConstraintAnnotator:
for value in variable.value:
value.type = type_
try:
cvalue = CONVERSION.get(type_, str)(value.name)
cvalue = CONVERT_OPTION[type_].get('func', str)(value.name)
except:
raise DictConsistencyError(_(f'unable to change type of value "{value}" is not a valid "{type_}" for "{variable.name}"'))
if cvalue not in choices:
raise DictConsistencyError(_('value "{}" of variable "{}" is not in list of all expected values ({})').format(value.name, variable.name, choices))
else:
new_value = self.objectspace.value()
new_value = self.objectspace.value(variable.xmlfiles)
new_value.name = choices[0]
new_value.type = type_
variable.value = [new_value]
@ -973,26 +1019,30 @@ class ConstraintAnnotator:
else:
raise DictConsistencyError(_(f'unknown parameter {param.text} in check "valid_entier" for variable {check.target}'))
else:
check_ = self.objectspace.check()
check_ = self.objectspace.check(variable.xmlfiles)
if name == 'valid_differ':
name = 'valid_not_equal'
elif name == 'valid_network_netmask':
params_len = 1
if len(check.param) != params_len:
raise DictConsistencyError(_('{} must have {} param').format(name, params_len))
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'))
elif name == 'valid_ipnetmask':
params_len = 1
if len(check.param) != params_len:
raise DictConsistencyError(_('{} must have {} param').format(name, params_len))
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'))
name = 'valid_ip_netmask'
elif name == 'valid_broadcast':
params_len = 2
if len(check.param) != params_len:
raise DictConsistencyError(_('{} must have {} param').format(name, params_len))
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'))
elif name == 'valid_in_network':
params_len = 2
if len(check.param) != params_len:
raise DictConsistencyError(_('{} must have {} param').format(name, params_len))
if len(check.param) not in (1, 2):
params_len = 2
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'))
check_.name = name
check_.warnings_only = check.warnings_only
if hasattr(check, 'param'):
@ -1026,7 +1076,8 @@ class ConstraintAnnotator:
)
if suffix is not None:
raise DictConsistencyError(_(f'Cannot add fill function to "{fill.target}" only with the suffix "{suffix}"'))
value = self.objectspace.value()
variable = self.objectspace.paths.get_variable_obj(fill.target)
value = self.objectspace.value(variable.xmlfiles)
value.type = 'calculation'
value.name = fill.name
if hasattr(fill, 'param'):
@ -1058,7 +1109,6 @@ class ConstraintAnnotator:
for param_idx in param_to_delete:
fill.param.pop(param_idx)
value.param = fill.param
variable = self.objectspace.paths.get_variable_obj(fill.target)
variable.value = [value]
del self.objectspace.space.constraints.fill
@ -1066,6 +1116,7 @@ class ConstraintAnnotator:
if hasattr(self.objectspace.space.constraints, 'index'):
del self.objectspace.space.constraints.index
del self.objectspace.space.constraints.namespace
del self.objectspace.space.constraints.xmlfiles
if vars(self.objectspace.space.constraints):
raise Exception('constraints again?')
del self.objectspace.space.constraints
@ -1126,7 +1177,7 @@ class FamilyAnnotator:
# if the variable is mandatory and doesn't have any value
# then the variable's mode is set to 'basic'
if not hasattr(variable, 'value') and variable.type == 'boolean':
new_value = self.objectspace.value()
new_value = self.objectspace.value(variable.xmlfiles)
new_value.name = True
new_value.type = 'boolean'
variable.value = [new_value]

View File

@ -131,6 +131,7 @@
<!ELEMENT group (follower+)>
<!ATTLIST group leader CDATA #REQUIRED>
<!ATTLIST group name CDATA #IMPLIED>
<!ATTLIST group description CDATA #IMPLIED>
<!ELEMENT param (#PCDATA)>

View File

@ -59,7 +59,10 @@ CONVERT_EXPORT = {'Leadership': 'leader',
# _____________________________________________________________________________
# special types definitions for the Object Space's internal representation
class RootCreoleObject:
""
def __init__(self, xmlfiles):
if not isinstance(xmlfiles, list):
xmlfiles = [xmlfiles]
self.xmlfiles = xmlfiles
class CreoleObjSpace:
@ -157,12 +160,14 @@ class CreoleObjSpace:
self.fill_removed = []
self.check_removed = []
self.condition_removed = []
self.xml_parse_document(document,
self.xml_parse_document(xmlfile,
document,
self.space,
namespace,
)
def xml_parse_document(self,
xmlfile,
document,
space,
namespace,
@ -179,7 +184,7 @@ class CreoleObjSpace:
continue
if child.tag == 'family':
if child.attrib['name'] in family_names:
raise DictConsistencyError(_('Family {} is set several times').format(child.attrib['name']))
raise DictConsistencyError(_(f'Family "{child.attrib["name"]}" is set several times in "{xmlfile}"'))
family_names.append(child.attrib['name'])
if child.tag == 'variables':
child.attrib['name'] = namespace
@ -188,16 +193,18 @@ class CreoleObjSpace:
continue
# variable objects creation
try:
variableobj = self.generate_variableobj(child,
space,
namespace,
)
variableobj = self.generate_variableobj(xmlfile,
child,
space,
namespace,
)
except SpaceObjShallNotBeUpdated:
continue
self.set_text_to_obj(child,
variableobj,
)
self.set_xml_attributes_to_obj(child,
self.set_xml_attributes_to_obj(xmlfile,
child,
variableobj,
)
self.variableobj_tree_visitor(child,
@ -215,26 +222,29 @@ class CreoleObjSpace:
child,
)
if list(child) != []:
self.xml_parse_document(child,
self.xml_parse_document(xmlfile,
child,
variableobj,
namespace,
)
def generate_variableobj(self,
child,
space,
namespace,
):
xmlfile,
child,
space,
namespace,
):
"""
instanciates or creates Creole Object Subspace objects
"""
variableobj = getattr(self, child.tag)()
variableobj = getattr(self, child.tag)(xmlfile)
if isinstance(variableobj, self.Redefinable):
variableobj = self.create_or_update_redefinable_object(child.attrib,
space,
child,
namespace,
)
variableobj = self.create_or_update_redefinable_object(xmlfile,
child.attrib,
space,
child,
namespace,
)
elif isinstance(variableobj, self.Atom) and child.tag in vars(space):
# instanciates an object from the CreoleObjSpace's builtins types
# example : child.tag = constraints -> a self.Constraints() object is created
@ -248,6 +258,7 @@ class CreoleObjSpace:
return variableobj
def create_or_update_redefinable_object(self,
xmlfile,
subspace,
space,
child,
@ -281,15 +292,17 @@ class CreoleObjSpace:
name = child.text
else:
name = subspace['name']
if self.is_already_exists(name,
space,
child,
namespace,
):
existed_var = self.is_already_exists(name,
space,
child,
namespace,
)
if existed_var:
default_redefine = child.tag in FORCE_REDEFINABLES
redefine = self.convert_boolean(subspace.get('redefine', default_redefine))
exists = self.convert_boolean(subspace.get('exists', True))
if redefine is True:
existed_var.xmlfiles.append(xmlfile)
return self.translate_in_space(name,
space,
child,
@ -297,12 +310,21 @@ class CreoleObjSpace:
)
elif exists is False:
raise SpaceObjShallNotBeUpdated()
raise DictConsistencyError(_(f'Already present in another XML file, {name} cannot be re-created'))
xmlfiles = self.display_xmlfiles(existed_var.xmlfiles)
raise DictConsistencyError(_(f'"{child.tag}" named "{name}" cannot be re-created in "{xmlfile}", already defined in {xmlfiles}'))
redefine = self.convert_boolean(subspace.get('redefine', False))
exists = self.convert_boolean(subspace.get('exists', False))
if redefine is False or exists is True:
return getattr(self, child.tag)()
raise DictConsistencyError(_(f'Redefined object: {name} does not exist yet'))
return getattr(self, child.tag)(xmlfile)
raise DictConsistencyError(_(f'Redefined object in "{xmlfile}": "{name}" does not exist yet'))
def display_xmlfiles(self,
xmlfiles: list,
) -> str:
if len(xmlfiles) == 1:
return '"' + xmlfiles[0] + '"'
else:
return '"' + '", "'.join(xmlfiles[:-1]) + '"' + ' and ' + '"' + xmlfiles[-1] + '"'
def create_tree_structure(self,
space,
@ -329,16 +351,25 @@ class CreoleObjSpace:
raise OperationError(_("Creole object {} "
"has a wrong type").format(type(variableobj)))
def is_already_exists(self, name, space, child, namespace):
def is_already_exists(self,
name: str,
space: str,
child,
namespace: str,
):
if isinstance(space, self.family): # pylint: disable=E1101
if namespace != Config['variable_namespace']:
name = space.path + '.' + name
return self.paths.path_is_defined(name)
if self.paths.path_is_defined(name):
return self.paths.get_variable_obj(name)
return
if child.tag == 'family':
norm_name = normalize_family(name)
else:
norm_name = name
return norm_name in getattr(space, child.tag, {})
children = getattr(space, child.tag, {})
if norm_name in children:
return children[norm_name]
def convert_boolean(self, value): # pylint: disable=R0201
"""Boolean coercion. The Creole XML may contain srings like `True` or `False`
@ -451,6 +482,7 @@ class CreoleObjSpace:
variableobj.text = text
def set_xml_attributes_to_obj(self,
xmlfile,
child,
variableobj,
):
@ -463,7 +495,8 @@ class CreoleObjSpace:
# UNREDEFINABLE concerns only 'variable' node so we can fix name
# to child.attrib['name']
name = child.attrib['name']
raise DictConsistencyError(_(f'cannot redefine attribute {attr} for variable {name}'))
xmlfiles = self.display_xmlfiles(variableobj.xmlfiles[:-1])
raise DictConsistencyError(_(f'cannot redefine attribute "{attr}" for variable "{name}" in "{xmlfile}", already defined in {xmlfiles}'))
if attr in self.booleans_attributs:
val = self.convert_boolean(val)
if not (attr == 'name' and getattr(variableobj, 'name', None) != None):

View File

@ -13,7 +13,8 @@ class Path:
def __init__(self):
self.variables = {}
self.families = {}
self.full_paths = {}
self.full_paths_families = {}
self.full_paths_variables = {}
# Family
def add_family(self,
@ -23,7 +24,7 @@ class Path:
) -> str: # pylint: disable=C0111
if '.' not in name and namespace == Config['variable_namespace']:
full_name = '.'.join([namespace, name])
self.full_paths[name] = full_name
self.full_paths_families[name] = full_name
else:
full_name = name
if full_name in self.families and self.families[full_name]['variableobj'] != variableobj:
@ -41,8 +42,8 @@ class Path:
check_name=False,
allow_dot=True,
)
if '.' not in name and current_namespace == Config['variable_namespace'] and name in self.full_paths:
name = self.full_paths[name]
if '.' not in name and current_namespace == Config['variable_namespace'] and name in self.full_paths_families:
name = self.full_paths_families[name]
if current_namespace is None: # pragma: no cover
raise OperationError('current_namespace must not be None')
dico = self.families[name]
@ -55,8 +56,8 @@ class Path:
def get_family_obj(self,
name: str,
) -> 'Family': # pylint: disable=C0111
if '.' not in name and name in self.full_paths:
name = self.full_paths[name]
if '.' not in name and name in self.full_paths_families:
name = self.full_paths_families[name]
if name not in self.families:
raise DictConsistencyError(_('unknown family {}').format(name))
dico = self.families[name]
@ -65,7 +66,7 @@ class Path:
def family_is_defined(self,
name: str,
) -> str: # pylint: disable=C0111
if '.' not in name and name not in self.families and name in self.full_paths:
if '.' not in name and name not in self.families and name in self.full_paths_families:
return True
return name in self.families
@ -88,7 +89,7 @@ class Path:
dico['variableobj'],
)
if namespace == Config['variable_namespace']:
self.full_paths[name] = new_path
self.full_paths_variables[name] = new_path
else:
name = new_path
dico = self._get_variable(name)
@ -110,7 +111,7 @@ class Path:
) -> str: # pylint: disable=C0111
if '.' not in name:
full_name = '.'.join([namespace, family, name])
self.full_paths[name] = full_name
self.full_paths_variables[name] = full_name
else:
full_name = name
if namespace == Config['variable_namespace']:
@ -176,7 +177,7 @@ class Path:
def path_is_defined(self,
name: str,
) -> str: # pylint: disable=C0111
if '.' not in name and name not in self.variables and name in self.full_paths:
if '.' not in name and name not in self.variables and name in self.full_paths_variables:
return True
return name in self.variables
@ -186,8 +187,8 @@ class Path:
) -> str:
if name not in self.variables:
if name not in self.variables:
if '.' not in name and name in self.full_paths:
name = self.full_paths[name]
if '.' not in name and name in self.full_paths_variables:
name = self.full_paths_variables[name]
if name not in self.variables:
for var_name, variable in self.variables.items():
if variable['is_dynamic'] and name.startswith(var_name):
@ -195,9 +196,9 @@ class Path:
raise Exception('This option is dynamic, should use "with_suffix" attribute')
return variable, name[len(var_name):]
if '.' not in name:
for var_name, path in self.full_paths.items():
for var_name, path in self.full_paths_variables.items():
if name.startswith(var_name):
variable = self.variables[self.full_paths[var_name]]
variable = self.variables[self.full_paths_variables[var_name]]
if variable['is_dynamic']:
if not with_suffix:
raise Exception('This option is dynamic, should use "with_suffix" attribute')

View File

@ -4,7 +4,7 @@ flattened XML specific
from .config import Config
from .i18n import _
from .error import LoaderError
from .annotator import ERASED_ATTRIBUTES
from .annotator import ERASED_ATTRIBUTES, CONVERT_OPTION
FUNC_TO_DICT = ['valid_not_equal']
@ -12,32 +12,6 @@ FORCE_INFORMATIONS = ['help', 'test', 'separator', 'manage']
ATTRIBUTES_ORDER = ('name', 'doc', 'default', 'multi')
CONVERT_OPTION = {'number': dict(opttype="IntOption", func=int),
'choice': dict(opttype="ChoiceOption"),
'string': dict(opttype="StrOption"),
'password': dict(opttype="PasswordOption"),
'mail': dict(opttype="EmailOption"),
'boolean': dict(opttype="BoolOption"),
'symlink': dict(opttype="SymLinkOption"),
'filename': dict(opttype="FilenameOption"),
'date': dict(opttype="DateOption"),
'unix_user': dict(opttype="UsernameOption"),
'ip': dict(opttype="IPOption", initkwargs={'allow_reserved': True}),
'local_ip': dict(opttype="IPOption", initkwargs={'private_only': True, 'warnings_only': True}),
'netmask': dict(opttype="NetmaskOption"),
'network': dict(opttype="NetworkOption"),
'broadcast': dict(opttype="BroadcastOption"),
'netbios': dict(opttype="DomainnameOption", initkwargs={'type': 'netbios', 'warnings_only': True}),
'domain': dict(opttype="DomainnameOption", initkwargs={'type': 'domainname', 'allow_ip': False}),
'hostname': dict(opttype="DomainnameOption", initkwargs={'type': 'hostname', 'allow_ip': False}),
'web_address': dict(opttype="URLOption", initkwargs={'allow_ip': True, 'allow_without_dot': True}),
'port': dict(opttype="PortOption", initkwargs={'allow_private': True}),
'mac': dict(opttype="MACOption"),
'cidr': dict(opttype="IPOption", initkwargs={'cidr': True}),
'network_cidr': dict(opttype="NetworkOption", initkwargs={'cidr': True}),
}
class TiramisuReflector:
def __init__(self,
xmlroot,
@ -344,6 +318,8 @@ class Variable(Common):
value = value.split(',')
if self.object_type == 'IntOption':
value = [int(v) for v in value]
elif self.object_type == 'FloatOption':
value = [float(v) for v in value]
self.informations[key] = value
else:
self.attrib[key] = value
@ -397,7 +373,7 @@ class Variable(Common):
function = child.name
if hasattr(child, 'param'):
for param in child.param:
value = self.populate_param(param)
value = self.populate_param(function, param)
if not hasattr(param, 'name'):
args.append(str(value))
else:
@ -411,6 +387,7 @@ class Variable(Common):
return ret + ')'
def populate_param(self,
function: str,
param,
):
if param.type == 'string':
@ -420,7 +397,7 @@ class Variable(Common):
elif param.type == 'variable':
value = {'option': param.text,
'notraisepropertyerror': param.notraisepropertyerror,
'todict': param.text in FUNC_TO_DICT,
'todict': function in FUNC_TO_DICT,
}
if hasattr(param, 'suffix'):
value['suffix'] = param.suffix
@ -443,7 +420,7 @@ class Variable(Common):
self.attrib['default'].append(value)
if not self.is_leader:
self.attrib['default_multi'] = value
elif isinstance(value, int):
elif isinstance(value, (int, float)):
self.attrib['default'].append(value)
else:
self.attrib['default'].append("'" + value + "'")

View File

@ -37,7 +37,7 @@ class XMLReflector(object):
# document = parse(BytesIO(xmlfile), XMLParser(remove_blank_text=True))
document = parse(xmlfile)
if not self.dtd.validate(document):
raise DictConsistencyError(_("not a valid xml file: {}").format(xmlfile))
raise DictConsistencyError(_(f'"{xmlfile}" not a valid xml file: {self.dtd.error_log.filter_from_errors()[0]}'))
return document.getroot()
def load_xml_from_folders(self, xmlfolders):

View File

@ -0,0 +1,16 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<variables>
<family name="general">
<variable name="float" type="float" description="Description">
<value>0.527</value>
</variable>
<variable name="float_multi" type="float" description="Description" multi="True">
<value>0.527</value>
</variable>
</family>
<separators/>
</variables>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1 @@
{"rougail.general.float": 0.527, "rougail.general.float_multi": [0.527]}

View File

@ -0,0 +1,15 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = FloatOption(properties=frozenset({'mandatory', 'normal'}), name='float', doc='Description', multi=False, default=0.527)
option_4 = FloatOption(properties=frozenset({'mandatory', 'normal'}), name='float_multi', doc='Description', multi=True, default=[0.527], default_multi=0.527)
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,12 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<variables>
<family name="general">
<variable name="general" type="oui/non" description="description">
<value>non</value>
</variable>
</family>
</variables>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1 @@
{"rougail.general.general": "non"}

View File

@ -0,0 +1,14 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='general', doc='description', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -10,7 +10,7 @@ except:
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = StrOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='b')
option_5 = IntOption(properties=frozenset({'normal'}), name='int2', doc='No change', multi=False)
option_4 = IntOption(properties=frozenset({'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False)], name='int', doc='No change', multi=False)
option_4 = IntOption(properties=frozenset({'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False)], name='int', doc='No change', multi=False)
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -9,7 +9,7 @@ except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non'))
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -11,7 +11,7 @@ from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non'))
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_5 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif2', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_6 = StrOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False), Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif3', doc='No change', multi=False, default='oui')
option_6 = StrOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False), Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif3', doc='No change', multi=False, default='oui')
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5, option_6])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -11,7 +11,7 @@ from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non'))
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_5 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif2', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_6 = StrOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False), Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif3', doc='No change', multi=False, default='oui')
option_6 = StrOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False), Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif3', doc='No change', multi=False, default='oui')
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5, option_6])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,29 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services/>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="oui/non" description="No change">
<value>oui</value>
</variable>
<variable name="adresse_ip_eth0" type="local_ip" description="Adresse IP de la carte" mandatory="True" mode="basic"/>
<variable name="adresse_netmask_eth0" type="netmask" description="Masque de sous réseau de la carte" mandatory="True" mode="basic"/>
<variable name="adresse_ip" type="local_ip" description="IP" mandatory="True" mode="basic"/>
</family>
<separators/>
</variables>
<constraints>
<check name="valid_in_network" target="adresse_ip" level="warning">
<param type="variable">adresse_ip_eth0</param>
<param type="variable">adresse_netmask_eth0</param>
</check>
</constraints>
<help/>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1 @@
{"rougail.general.mode_conteneur_actif": "oui", "rougail.general.adresse_ip_eth0": null, "rougail.general.adresse_netmask_eth0": null, "rougail.general.adresse_ip": null}

View File

@ -0,0 +1,17 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non'))
option_4 = IPOption(private_only=True, warnings_only=True, properties=frozenset({'basic', 'mandatory'}), name='adresse_ip_eth0', doc='Adresse IP de la carte', multi=False)
option_5 = NetmaskOption(properties=frozenset({'basic', 'mandatory'}), name='adresse_netmask_eth0', doc='Masque de sous réseau de la carte', multi=False)
option_6 = IPOption(private_only=True, warnings_only=True, properties=frozenset({'basic', 'mandatory'}), validators=[Calculation(func.valid_in_network, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=False), ParamOption(option_5, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=True)], name='adresse_ip', doc='IP', multi=False)
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'basic'}), children=[option_3, option_4, option_5, option_6])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,27 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services/>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="oui/non" description="No change">
<value>oui</value>
</variable>
<variable name="adresse_ip_eth0" type="cidr" description="Adresse IP de la carte" mandatory="True" mode="basic"/>
<variable name="adresse_ip" type="local_ip" description="IP" mandatory="True" mode="basic"/>
</family>
<separators/>
</variables>
<constraints>
<check name="valid_in_network" target="adresse_ip" level="warning">
<param type="variable">adresse_ip_eth0</param>
</check>
</constraints>
<help/>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1 @@
{"rougail.general.mode_conteneur_actif": "oui", "rougail.general.adresse_ip_eth0": null, "rougail.general.adresse_ip": null}

View File

@ -0,0 +1,16 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non'))
option_4 = IPOption(cidr=True, properties=frozenset({'basic', 'mandatory'}), name='adresse_ip_eth0', doc='Adresse IP de la carte', multi=False)
option_5 = IPOption(private_only=True, warnings_only=True, properties=frozenset({'basic', 'mandatory'}), validators=[Calculation(func.valid_in_network, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=True)], name='adresse_ip', doc='IP', multi=False)
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'basic'}), children=[option_3, option_4, option_5])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<rougail>
<variables>
<family name='general'>
<variable name='mode_conteneur_actif' type='oui/non' description="No change">
<value>non</value>
</variable>
</family>
<family name='general1'>
<variable name='leader' type='string' description="leader" multi="True"/>
<variable name='follower1' type='string' description="follower1"/>
<variable name='follower2' type='string' description="follower2"/>
</family>
</variables>
<constraints>
<fill name='calc_val' target='follower1'>
<param name='valeur'>valfill</param>
</fill>
<fill name='calc_val' target='follower2'>
<param type='variable'>follower1</param>
</fill>
<group leader='leader' name="other_name">
<follower>follower1</follower>
<follower>follower2</follower>
</group>
</constraints>
</rougail>

View File

@ -0,0 +1 @@
{"rougail.general.mode_conteneur_actif": "non", "rougail.general1.other_name.leader": [], "rougail.general1.other_name.follower1": [], "rougail.general1.other_name.follower2": []}

View File

@ -0,0 +1,19 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3])
option_6 = StrOption(name='leader', doc='leader', multi=True)
option_7 = StrOption(properties=frozenset({'normal'}), name='follower1', doc='follower1', multi=True, default=Calculation(func.calc_val, Params((), kwargs={'valeur': ParamValue("valfill")})))
option_8 = StrOption(properties=frozenset({'normal'}), name='follower2', doc='follower2', multi=True, default=Calculation(func.calc_val, Params((ParamOption(option_7, notraisepropertyerror=False, todict=False)), kwargs={})))
option_5 = Leadership(name='other_name', doc='leader', properties=frozenset({'normal'}), children=[option_6, option_7, option_8])
option_4 = OptionDescription(name='general1', doc='general1', properties=frozenset({'normal'}), children=[option_5])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2, option_4])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,25 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services/>
<variables>
<family name="extra">
<variable name="mode_conteneur_actif" type="oui/non" description="No change" hidden="True">
<value>non</value>
</variable>
<variable name="activer_ejabberd" type="oui/non" description="No change" hidden="True">
<value>non</value>
</variable>
</family>
<separators/>
</variables>
<constraints>
</constraints>
<help/>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<rougail>
<variables>
<family name='ejabberd'>
<variable name="description" type="string">
<value>Exportation de la base de ejabberd</value>
</variable>
<variable name="day" type="schedule"></variable>
<variable name="mode" type="schedulemod">
<value>pre</value>
</variable>
</family>
</variables>
<constraints>
<fill name='calc_multi_condition' target='extra.ejabberd.day'>
<param>non</param>
<param type='variable' name='condition_1' notraisepropertyerror='True'>activer_ejabberd</param>
<param name='match'>none</param>
<param name='mismatch'>daily</param>
</fill>
</constraints>
</rougail>

View File

@ -0,0 +1 @@
{"rougail.extra.mode_conteneur_actif": "non", "rougail.extra.activer_ejabberd": "non", "extra.ejabberd.description": "Exportation de la base de ejabberd", "extra.ejabberd.day": null, "extra.ejabberd.mode": "pre"}

View File

@ -0,0 +1,20 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_4 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='activer_ejabberd', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='extra', doc='extra', properties=frozenset({'normal'}), children=[option_3, option_4])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_7 = StrOption(properties=frozenset({'mandatory', 'normal'}), name='description', doc='description', multi=False, default='Exportation de la base de ejabberd')
option_8 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='day', doc='day', multi=False, default=Calculation(func.calc_multi_condition, Params((ParamValue("non")), kwargs={'condition_1': ParamOption(option_4, notraisepropertyerror=True, todict=False), 'match': ParamValue("none"), 'mismatch': ParamValue("daily")})), values=('none', 'daily', 'weekly', 'monthly'))
option_9 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode', doc='mode', multi=False, default='pre', values=('pre', 'post'))
option_6 = OptionDescription(name='ejabberd', doc='ejabberd', properties=frozenset({'normal'}), children=[option_7, option_8, option_9])
option_5 = OptionDescription(name='extra', doc='extra', children=[option_6])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1, option_5])

View File

@ -0,0 +1,27 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services/>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="string" description="No change">
<value>b</value>
</variable>
<variable name="int" type="number" description="No change"/>
</family>
<separators/>
</variables>
<constraints>
<check name="unknown" target="int">
<param name="mini">0</param>
<param name="maxi">100</param>
</check>
</constraints>
<help/>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1,26 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services/>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="string" description="No change">
<value>b</value>
</variable>
</family>
<separators/>
</variables>
<constraints>
<check name="valid_differ" target="mode_conteneur_actif">
<param type="variable">int3</param>
</check>
</constraints>
<help/>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="unknown" description="Description"/>
</family>
</variables>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -1,4 +1,4 @@
from tiramisu import valid_not_equal, valid_ip_netmask, calc_value
from tiramisu import valid_not_equal, valid_ip_netmask, calc_value, valid_in_network
def calc_val(*args, **kwargs):
if len(args) > 0: