Compare commits

..

No commits in common. "d5ed39c1f35c3a96abebe1ea891647beda11fd24" and "13b1e9bf546f420c93e09cdeaa569092b8a1e1c7" have entirely different histories.

35 changed files with 447 additions and 641 deletions

View File

@ -1,7 +1,5 @@
"""Annotate constraints from typing import List
"""
from importlib.machinery import SourceFileLoader from importlib.machinery import SourceFileLoader
from typing import List, Any
from .variable import CONVERT_OPTION from .variable import CONVERT_OPTION
@ -15,31 +13,7 @@ FREEZE_AUTOFREEZE_VARIABLE = 'module_instancie'
INTERNAL_FUNCTIONS = ['valid_enum', 'valid_in_network', 'valid_differ', 'valid_entier'] INTERNAL_FUNCTIONS = ['valid_enum', 'valid_in_network', 'valid_differ', 'valid_entier']
def get_actions_from_condition(condition_name: str) -> List[str]:
"""get action's name from a condition
"""
if condition_name.startswith('hidden_if_'):
return ['hidden', 'frozen', 'force_default_on_freeze']
if condition_name == 'auto_frozen_if_not_in':
return ['auto_frozen']
return [condition_name.split('_', 1)[0]]
def check_valid_enum_value(variable,
values,
) -> None:
"""check that values in valid_enum are valid
"""
for value in variable.value:
if value.name not in values:
msg = _(f'value "{value.name}" of variable "{variable.name}" is not in list '
f'of all expected values ({values})')
raise DictConsistencyError(msg, 15)
class ConstrainteAnnotator: class ConstrainteAnnotator:
"""Annotate constrainte
"""
def __init__(self, def __init__(self,
objectspace, objectspace,
eosfunc_file, eosfunc_file,
@ -50,16 +24,18 @@ class ConstrainteAnnotator:
eosfunc = SourceFileLoader('eosfunc', eosfunc_file).load_module() eosfunc = SourceFileLoader('eosfunc', eosfunc_file).load_module()
self.functions = dir(eosfunc) self.functions = dir(eosfunc)
self.functions.extend(INTERNAL_FUNCTIONS) self.functions.extend(INTERNAL_FUNCTIONS)
self.valid_enums = {}
self.convert_auto_freeze() self.convert_auto_freeze()
self.valid_enums = {}
if hasattr(self.objectspace.space.constraints, 'check'): if hasattr(self.objectspace.space.constraints, 'check'):
self.check_check() self.check_check()
self.check_replace_text()
self.check_valid_enum() self.check_valid_enum()
self.check_change_warning() self.check_change_warning()
self.convert_check() self.convert_check()
if hasattr(self.objectspace.space.constraints, 'condition'): if hasattr(self.objectspace.space.constraints, 'condition'):
self.convert_condition_target() self.check_params_target()
self.filter_targets()
self.convert_xxxlist_to_variable() self.convert_xxxlist_to_variable()
self.check_condition_fallback_optional() self.check_condition_fallback_optional()
self.check_choice_option_condition() self.check_choice_option_condition()
@ -67,20 +43,16 @@ class ConstrainteAnnotator:
self.convert_condition() self.convert_condition()
if hasattr(self.objectspace.space.constraints, 'fill'): if hasattr(self.objectspace.space.constraints, 'fill'):
self.convert_fill() self.convert_fill()
del self.objectspace.space.constraints self.remove_constraints()
def convert_auto_freeze(self): def convert_auto_freeze(self): # pylint: disable=C0111
"""convert auto_freeze
only if FREEZE_AUTOFREEZE_VARIABLE == 'oui' this variable is frozen
"""
def _convert_auto_freeze(variable, namespace): def _convert_auto_freeze(variable, namespace):
if variable.auto_freeze: if variable.auto_freeze:
if namespace != Config['variable_namespace']: if namespace != Config['variable_namespace']:
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
msg = _(f'auto_freeze is not allowed in extra "{namespace}" in {xmlfiles}') raise DictConsistencyError(_(f'auto_freeze is not allowed in extra "{namespace}" in {xmlfiles}'), 49)
raise DictConsistencyError(msg, 49)
new_condition = self.objectspace.condition(variable.xmlfiles) new_condition = self.objectspace.condition(variable.xmlfiles)
new_condition.name = 'auto_frozen_if_not_in' new_condition.name = 'auto_hidden_if_not_in'
new_condition.namespace = namespace new_condition.namespace = namespace
new_condition.source = FREEZE_AUTOFREEZE_VARIABLE new_condition.source = FREEZE_AUTOFREEZE_VARIABLE
new_param = self.objectspace.param(variable.xmlfiles) new_param = self.objectspace.param(variable.xmlfiles)
@ -94,176 +66,82 @@ class ConstrainteAnnotator:
self.objectspace.space.constraints.condition = [] self.objectspace.space.constraints.condition = []
self.objectspace.space.constraints.condition.append(new_condition) self.objectspace.space.constraints.condition.append(new_condition)
for variables in self.objectspace.space.variables.values(): for variables in self.objectspace.space.variables.values():
if not hasattr(variables, 'family'): if hasattr(variables, 'family'):
continue namespace = variables.name
for family in variables.family.values(): for family in variables.family.values():
if not hasattr(family, 'variable'): if hasattr(family, 'variable'):
continue for variable in family.variable.values():
for variable in family.variable.values(): if isinstance(variable, self.objectspace.leadership):
if isinstance(variable, self.objectspace.leadership): for follower in variable.variable:
for follower in variable.variable: _convert_auto_freeze(follower, namespace)
_convert_auto_freeze(follower, else:
variables.namespace, _convert_auto_freeze(variable, namespace)
)
else:
_convert_auto_freeze(variable,
variables.namespace,
)
def check_check(self): def check_check(self):
"""valid and manage <check>
"""
remove_indexes = [] remove_indexes = []
for check_idx, check in enumerate(self.objectspace.space.constraints.check): for check_idx, check in enumerate(self.objectspace.space.constraints.check):
if not check.name in self.functions: if not check.name in self.functions:
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
msg = _(f'cannot find check function "{check.name}" in {xmlfiles}') raise DictConsistencyError(_(f'cannot find check function "{check.name}" in {xmlfiles}'), 1)
raise DictConsistencyError(msg, 1) if hasattr(check, 'param'):
if not hasattr(check, 'param'): param_option_indexes = []
continue for idx, param in enumerate(check.param):
param_option_indexes = [] if param.type == 'variable' and not self.objectspace.paths.path_is_defined(param.text):
for idx, param in enumerate(check.param): if param.optional is True:
if param.type == 'variable': param_option_indexes.append(idx)
if not self.objectspace.paths.path_is_defined(param.text): else:
if not param.optional:
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
msg = _(f'cannot find check param "{param.text}" in {xmlfiles}') raise DictConsistencyError(_(f'cannot find check param "{param.text}" in {xmlfiles}'), 2)
raise DictConsistencyError(msg, 2) if param.type != 'variable':
param_option_indexes.append(idx) param.notraisepropertyerror = None
else: param_option_indexes = list(set(param_option_indexes))
# let's replace params by the path param_option_indexes.sort(reverse=True)
param.text = self.objectspace.paths.get_variable_path(param.text, for idx in param_option_indexes:
check.namespace, check.param.pop(idx)
) if check.param == []:
param_option_indexes.sort(reverse=True) remove_indexes.append(check_idx)
for idx in param_option_indexes:
check.param.pop(idx)
if check.param == []:
remove_indexes.append(check_idx)
continue
# let's replace the target by the path
check.target = self.objectspace.paths.get_variable_path(check.target,
check.namespace,
)
check.is_in_leadership = self.objectspace.paths.get_leader(check.target) is not None
remove_indexes.sort(reverse=True) remove_indexes.sort(reverse=True)
for idx in remove_indexes: for idx in remove_indexes:
del self.objectspace.space.constraints.check[idx] del self.objectspace.space.constraints.check[idx]
def check_replace_text(self):
for check_idx, check in enumerate(self.objectspace.space.constraints.check):
namespace = check.namespace
if hasattr(check, 'param'):
for idx, param in enumerate(check.param):
if param.type == 'variable':
param.text = self.objectspace.paths.get_variable_path(param.text, namespace)
check.is_in_leadership = self.objectspace.paths.get_leader(check.target) != None
# let's replace the target by the path
check.target = self.objectspace.paths.get_variable_path(check.target, namespace)
def check_valid_enum(self): def check_valid_enum(self):
"""verify valid_enum
"""
remove_indexes = [] remove_indexes = []
for idx, check in enumerate(self.objectspace.space.constraints.check): for idx, check in enumerate(self.objectspace.space.constraints.check):
if check.name == 'valid_enum': if check.name == 'valid_enum':
if check.target in self.valid_enums: if check.target in self.valid_enums:
check_xmlfiles = self.valid_enums[check.target]['xmlfiles'] old_xmlfiles = self.objectspace.display_xmlfiles(self.valid_enums[check.target]['xmlfiles'])
old_xmlfiles = self.objectspace.display_xmlfiles(check_xmlfiles)
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
msg = _(f'valid_enum define in {xmlfiles} but already set in {old_xmlfiles} ' raise DictConsistencyError(_(f'valid_enum define in {xmlfiles} but already set in {old_xmlfiles} for "{check.target}", did you forget remove_check?'), 3)
f'for "{check.target}", did you forget remove_check?')
raise DictConsistencyError(msg, 3)
if not hasattr(check, 'param'): if not hasattr(check, 'param'):
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
msg = _(f'param is mandatory for a valid_enum of variable "{check.target}" ' raise DictConsistencyError(_(f'param is mandatory for a valid_enum of variable "{check.target}" in {xmlfiles}'), 4)
f'in {xmlfiles}')
raise DictConsistencyError(msg, 4)
variable = self.objectspace.paths.get_variable_obj(check.target) variable = self.objectspace.paths.get_variable_obj(check.target)
variable_type = variable.type self._set_valid_enum(variable,
values = self._set_valid_enum(variable, check,
check, )
)
if values:
if hasattr(variable, 'value'):
# check value
check_valid_enum_value(variable, values)
else:
# no value, set the first choice has default value
new_value = self.objectspace.value(check.xmlfiles)
new_value.name = values[0]
new_value.type = variable_type
variable.value = [new_value]
remove_indexes.append(idx) remove_indexes.append(idx)
remove_indexes.sort(reverse=True) remove_indexes.sort(reverse=True)
for idx in remove_indexes: for idx in remove_indexes:
del self.objectspace.space.constraints.check[idx] del self.objectspace.space.constraints.check[idx]
def _set_valid_enum(self,
variable,
check,
) -> List[Any]:
# value for choice's variable is mandatory
variable.mandatory = True
# build choice
variable.choice = []
variable_type = variable.type
variable.type = 'choice'
has_variable = False
values = []
for param in check.param:
if has_variable:
xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
msg = _(f'only one "variable" parameter is allowed for valid_enum '
f'of variable "{variable.name}" in {xmlfiles}')
raise DictConsistencyError(msg, 5)
param_type = variable_type
if param.type == 'variable':
has_variable = True
if param.optional is True:
xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
msg = _(f'optional parameter in valid_enum for variable "{variable.name}" '
f'is not allowed in {xmlfiles}')
raise DictConsistencyError(msg, 14)
param_variable = self.objectspace.paths.get_variable_obj(param.text)
if not param_variable.multi:
xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
msg = _(f'only multi "variable" parameter is allowed for valid_enum '
f'of variable "{variable.name}" in {xmlfiles}')
raise DictConsistencyError(msg, 6)
param_type = 'calculation'
value = param.text
else:
if 'type' in vars(param) and variable_type != param.type:
xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
msg = _(f'parameter in valid_enum has incompatible type "{param.type}" '
f'with type of the variable "{variable.name}" ("{variable_type}") '
f'in {xmlfiles}')
raise DictConsistencyError(msg, 7)
if hasattr(param, 'text'):
try:
value = CONVERT_OPTION[variable_type].get('func', str)(param.text)
except ValueError as err:
msg = _(f'unable to change type of a valid_enum entry "{param.text}" '
f'is not a valid "{variable_type}" for "{variable.name}"')
raise DictConsistencyError(msg, 13) from err
else:
if param.type == 'number':
xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
msg = _('param type is number, so value is mandatory for valid_enum '
f'of variable "{variable.name}" in {xmlfiles}')
raise DictConsistencyError(msg, 8)
value = None
values.append(value)
choice = self.objectspace.choice(variable.xmlfiles)
choice.name = value
choice.type = param_type
variable.choice.append(choice)
if has_variable:
return None
self.valid_enums[check.target] = {'type': variable_type,
'values': values,
'xmlfiles': check.xmlfiles,
}
return values
def check_change_warning(self): def check_change_warning(self):
"""convert level to "warnings_only" #convert level to "warnings_only"
"""
for check in self.objectspace.space.constraints.check: for check in self.objectspace.space.constraints.check:
check.warnings_only = check.level == 'warning' if check.level == 'warning':
check.warnings_only = True
else:
check.warnings_only = False
check.level = None check.level = None
def _get_family_variables_from_target(self, def _get_family_variables_from_target(self,
@ -280,50 +158,40 @@ class ConstrainteAnnotator:
variable = self.objectspace.paths.get_family_obj(target.name) variable = self.objectspace.paths.get_family_obj(target.name)
return variable, list(variable.variable.values()) return variable, list(variable.variable.values())
def convert_condition_target(self): def check_params_target(self):
"""verify and manage target in condition
"""
for condition in self.objectspace.space.constraints.condition: for condition in self.objectspace.space.constraints.condition:
if not hasattr(condition, 'target'): if not hasattr(condition, 'target'):
xmlfiles = self.objectspace.display_xmlfiles(condition.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(condition.xmlfiles)
msg = _(f'target is mandatory in a condition for source "{condition.source}" ' raise DictConsistencyError(_(f'target is mandatory in a condition for source "{condition.source}" in {xmlfiles}'), 9)
f'in {xmlfiles}')
raise DictConsistencyError(msg, 9)
for target in condition.target: for target in condition.target:
if target.type.endswith('list') and condition.name not in ['disabled_if_in', 'disabled_if_not_in']:
xmlfiles = self.objectspace.display_xmlfiles(target.xmlfiles)
raise DictConsistencyError(_(f'target "{target.type}" not allow in condition "{condition.name}" in {xmlfiles}'), 10)
def filter_targets(self): # pylint: disable=C0111
for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition):
namespace = condition.namespace
for idx, target in enumerate(condition.target):
if target.type == 'variable': if target.type == 'variable':
if condition.source == target.name: if condition.source == target.name:
msg = f'target name and source name must be different: {condition.source}' raise DictConsistencyError(_('target name and source name must be different: {}').format(condition.source), 11)
raise DictConsistencyError(_(msg), 11)
target_names = '.'.join([normalize_family(name) \
for name in target.name.split('.')])
try: try:
target.name = self.objectspace.paths.get_variable_path(target_names, target_names = [normalize_family(name) for name in target.name.split('.')]
condition.namespace, target.name = self.objectspace.paths.get_variable_path('.'.join(target_names), namespace)
)
except DictConsistencyError as err: except DictConsistencyError as err:
# for optional variable # for optional variable
if not target.optional or err.errno != 42: if not target.optional or err.errno != 42:
raise err raise err
elif target.type == 'family': elif target.type == 'family':
target_names = '.'.join([normalize_family(name) \
for name in target.name.split('.')])
try: try:
target.name = self.objectspace.paths.get_family_path(target_names, target_names = [normalize_family(name) for name in target.name.split('.')]
condition.namespace, target.name = self.objectspace.paths.get_family_path('.'.join(target_names), namespace)
)
except KeyError: except KeyError:
raise DictConsistencyError(_(f'cannot found family {target.name}'), 12) raise DictConsistencyError(_('cannot found family {}').format(target.name), 12)
elif target.type.endswith('list') and \
condition.name not in ['disabled_if_in', 'disabled_if_not_in']:
xmlfiles = self.objectspace.display_xmlfiles(target.xmlfiles)
msg = _(f'target "{target.type}" not allow in condition "{condition.name}" '
f'in {xmlfiles}')
raise DictConsistencyError(msg, 10)
def convert_xxxlist_to_variable(self): def convert_xxxlist_to_variable(self): # pylint: disable=C0111
"""transform *list to variable or family # transform *list to variable or family
""" for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition):
for condition in self.objectspace.space.constraints.condition:
new_targets = [] new_targets = []
remove_targets = [] remove_targets = []
for target_idx, target in enumerate(condition.target): for target_idx, target in enumerate(condition.target):
@ -347,56 +215,55 @@ class ConstrainteAnnotator:
condition.target.extend(new_targets) condition.target.extend(new_targets)
def check_condition_fallback_optional(self): def check_condition_fallback_optional(self):
"""a condition with a fallback **and** the source variable doesn't exist # a condition with a fallback **and** the source variable doesn't exist
"""
remove_conditions = [] remove_conditions = []
for idx, condition in enumerate(self.objectspace.space.constraints.condition): for idx, condition in enumerate(self.objectspace.space.constraints.condition):
# fallback # fallback
if condition.fallback is True and \ if condition.fallback is True and not self.objectspace.paths.path_is_defined(condition.source):
not self.objectspace.paths.path_is_defined(condition.source):
apply_action = False apply_action = False
if condition.name in ['disabled_if_in', 'mandatory_if_in', 'hidden_if_in']: if condition.name in ['disabled_if_in', 'mandatory_if_in', 'hidden_if_in']:
apply_action = not condition.force_condition_on_fallback apply_action = not condition.force_condition_on_fallback
else: else:
apply_action = condition.force_inverse_condition_on_fallback apply_action = condition.force_inverse_condition_on_fallback
remove_conditions.append(idx)
if apply_action: if apply_action:
self.force_actions_to_variable(condition) actions = self._get_condition_actions(condition.name)
for target in condition.target:
leader_or_variable, variables = self._get_family_variables_from_target(target)
for action_idx, action in enumerate(actions):
if action_idx == 0:
setattr(leader_or_variable, action, True)
else:
for variable in variables:
setattr(variable, action, True)
remove_conditions.append(idx)
continue continue
remove_targets = [] remove_targets = []
# optional # optional
for index, target in enumerate(condition.target): for idx, target in enumerate(condition.target):
if target.optional is True and \ if target.optional is True and not self.objectspace.paths.path_is_defined(target.name):
not self.objectspace.paths.path_is_defined(target.name): remove_targets.append(idx)
remove_targets.append(index)
remove_targets = list(set(remove_targets)) remove_targets = list(set(remove_targets))
remove_targets.sort(reverse=True) remove_targets.sort(reverse=True)
for index in remove_targets: for idx in remove_targets:
condition.target.pop(index) condition.target.pop(idx)
remove_conditions = list(set(remove_conditions)) remove_conditions = list(set(remove_conditions))
remove_conditions.sort(reverse=True) remove_conditions.sort(reverse=True)
for idx in remove_conditions: for idx in remove_conditions:
self.objectspace.space.constraints.condition.pop(idx) self.objectspace.space.constraints.condition.pop(idx)
def force_actions_to_variable(self, def _get_condition_actions(self, condition_name):
condition: 'self.objectspace.condition', if condition_name.startswith('disabled_if_'):
) -> None: return ['disabled']
"""force property to a variable elif condition_name.startswith('hidden_if_'):
for example disabled_if_not_in => variable.disabled = True return ['hidden', 'frozen', 'force_default_on_freeze']
""" elif condition_name.startswith('mandatory_if_'):
actions = get_actions_from_condition(condition.name) return ['mandatory']
for target in condition.target: elif condition_name == 'auto_hidden_if_not_in':
leader_or_var, variables = self._get_family_variables_from_target(target) return ['auto_frozen']
main_action = actions[0]
setattr(leader_or_var, main_action, True)
for action in actions[1:]:
for variable in variables:
setattr(variable, action, True)
def check_choice_option_condition(self): def check_choice_option_condition(self):
"""remove condition for ChoiceOption that don't have param # remove condition for ChoiceOption that don't have param
"""
remove_conditions = [] remove_conditions = []
for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition): for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition):
namespace = condition.namespace namespace = condition.namespace
@ -407,200 +274,257 @@ class ConstrainteAnnotator:
) )
if suffix: if suffix:
xmlfiles = self.objectspace.display_xmlfiles(condition.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(condition.xmlfiles)
msg = _(f'the source "{condition.source}" in condition cannot be a dynamic ' raise DictConsistencyError(_(f'the source "{condition.source}" in condition cannot be a dynamic variable in {xmlfiles}'), 20)
f'variable in {xmlfiles}') src_variable = self.objectspace.paths.get_variable_obj(condition.source)
raise DictConsistencyError(msg, 20) valid_enum = None
# FIXME only string? # FIXME only string?
if condition.source in self.valid_enums and \ if condition.source in self.valid_enums and self.valid_enums[condition.source]['type'] == 'string':
self.valid_enums[condition.source]['type'] == 'string':
valid_enum = self.valid_enums[condition.source]['values'] valid_enum = self.valid_enums[condition.source]['values']
remove_param = [param_idx for param_idx, param in enumerate(condition.param) \ if valid_enum is not None:
if param.text not in valid_enum] remove_param = []
for param_idx, param in enumerate(condition.param):
if param.text not in valid_enum:
remove_param.append(param_idx)
remove_param.sort(reverse=True) remove_param.sort(reverse=True)
for idx in remove_param: for idx in remove_param:
del condition.param[idx] del condition.param[idx]
if not condition.param and condition.name.endswith('_if_not_in'): if condition.param == []:
self.force_actions_to_variable(condition) for target in condition.target:
leader_or_variable, variables = self._get_family_variables_from_target(target)
if condition.name == 'disabled_if_not_in':
leader_or_variable.disabled = True
elif condition.name == 'hidden_if_not_in':
leader_or_variable.hidden = True
for variable in variables:
variable.frozen = True
variable.force_default_on_freeze = True
elif condition.name == 'mandatory_if_not_in':
leader_or_variable.mandatory = True
remove_conditions.append(condition_idx) remove_conditions.append(condition_idx)
remove_conditions = list(set(remove_conditions))
remove_conditions.sort(reverse=True) remove_conditions.sort(reverse=True)
for idx in remove_conditions: for idx in remove_conditions:
self.objectspace.space.constraints.condition.pop(idx) self.objectspace.space.constraints.condition.pop(idx)
def remove_condition_with_empty_target(self): def remove_condition_with_empty_target(self):
"""remove condition with empty target
"""
# optional target are remove, condition could be empty # optional target are remove, condition could be empty
remove_conditions = [condition_idx for condition_idx, condition in \ remove_conditions = [condition_idx for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition) if not condition.target]
enumerate(self.objectspace.space.constraints.condition) \
if not condition.target]
remove_conditions.sort(reverse=True) remove_conditions.sort(reverse=True)
for idx in remove_conditions: for idx in remove_conditions:
self.objectspace.space.constraints.condition.pop(idx) self.objectspace.space.constraints.condition.pop(idx)
def convert_condition(self): def convert_condition(self):
"""valid and manage <condition>
"""
for condition in self.objectspace.space.constraints.condition: for condition in self.objectspace.space.constraints.condition:
actions = get_actions_from_condition(condition.name) inverse = condition.name.endswith('_if_not_in')
actions = self._get_condition_actions(condition.name)
for param in condition.param: for param in condition.param:
text = getattr(param, 'text', None) text = getattr(param, 'text', None)
for target in condition.target: for target in condition.target:
leader_or_variable, variables = self._get_family_variables_from_target(target) leader_or_variable, variables = self._get_family_variables_from_target(target)
# if option is already disable, do not apply disable_if_in # if option is already disable, do not apply disable_if_in
# check only the first action (example of multiple actions: # check only the first action (example of multiple actions: 'hidden', 'frozen', 'force_default_on_freeze')
# 'hidden', 'frozen', 'force_default_on_freeze')
main_action = actions[0] main_action = actions[0]
if getattr(leader_or_variable, main_action, False) is True: if getattr(leader_or_variable, main_action, False) is True:
continue continue
self.build_property(leader_or_variable,
text,
condition,
main_action,
)
if isinstance(leader_or_variable, self.objectspace.variable) and \ if isinstance(leader_or_variable, self.objectspace.variable) and \
(leader_or_variable.auto_save or leader_or_variable.auto_freeze) and \ (leader_or_variable.auto_save or leader_or_variable.auto_freeze) and \
'force_default_on_freeze' in actions: 'force_default_on_freeze' in actions:
continue xmlfiles = self.objectspace.display_xmlfiles(leader_or_variable.xmlfiles)
for action in actions[1:]: raise DictConsistencyError(_(f'cannot have auto_freeze or auto_store with the hidden_if_in or hidden_if_not_in variable "{leader_or_variable.name}" in {xmlfiles}'), 51)
# other actions are set to the variable or children of family for idx, action in enumerate(actions):
for variable in variables: prop = self.objectspace.property_(leader_or_variable.xmlfiles)
self.build_property(variable, prop.type = 'calculation'
text, prop.inverse = inverse
condition, prop.source = condition.source
action, prop.expected = text
) prop.name = action
if idx == 0:
# main action is for the variable or family
if not hasattr(leader_or_variable, 'property'):
leader_or_variable.property = []
leader_or_variable.property.append(prop)
else:
# other actions are set to the variable or children of family
for variable in variables:
if not hasattr(variable, 'property'):
variable.property = []
variable.property.append(prop)
del self.objectspace.space.constraints.condition
def build_property(self, def _set_valid_enum(self,
obj, variable,
text: Any, check,
condition: 'self.objectspace.condition', ):
action: str, type_ = variable.type
) -> 'self.objectspace.property_': target = check.target
"""build property_ for a condition # value for choice's variable is mandatory
""" variable.mandatory = True
prop = self.objectspace.property_(obj.xmlfiles) # build choice
prop.type = 'calculation' variable.choice = []
prop.inverse = condition.name.endswith('_if_not_in') variable.type = 'choice'
prop.source = condition.source
prop.expected = text
prop.name = action
if not hasattr(obj, 'property'):
obj.property = []
obj.property.append(prop)
def convert_check(self) -> None: has_variable = False
"""valid and manage <check> values = []
""" for param in check.param:
if has_variable:
xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
raise DictConsistencyError(_(f'only one "variable" parameter is allowed for valid_enum of variable "{variable.name}" in {xmlfiles}'), 5)
param_type = type_
if param.type == 'variable':
has_variable = True
param_variable = self.objectspace.paths.get_variable_obj(param.text)
if param.optional is True:
xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
raise DictConsistencyError(_(f'optional parameter in valid_enum for variable "{variable.name}" is not allowed in {xmlfiles}'), 14)
if not param_variable.multi:
xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
raise DictConsistencyError(_(f'only multi "variable" parameter is allowed for valid_enum of variable "{variable.name}" in {xmlfiles}'), 6)
param_type = 'calculation'
value = param.text
else:
if 'type' in vars(param) and type_ != param.type:
xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
raise DictConsistencyError(_(f'parameter in valid_enum has incompatible type "{param.type}" with type of the variable "{variable.name}" ("{type_}") in {xmlfiles}'), 7)
if hasattr(param, 'text'):
try:
value = CONVERT_OPTION[type_].get('func', str)(param.text)
except:
raise DictConsistencyError(_(f'unable to change type of a valid_enum entry "{param.text}" is not a valid "{type_}" for "{variable.name}"'), 13)
else:
if param.type == 'number':
xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
raise DictConsistencyError(_(f'param type is number, so value is mandatory for valid_enum of variable "{variable.name}" in {xmlfiles}'), 8)
value = None
values.append(value)
choice = self.objectspace.choice(variable.xmlfiles)
choice.name = value
choice.type = param_type
variable.choice.append(choice)
if has_variable:
return
# FIXME really?
if param_type != 'calculation':
self.valid_enums[target] = {'type': type_,
'values': values,
'xmlfiles': check.xmlfiles,
}
# check value or set first choice value has default value
if hasattr(variable, 'value'):
for value in variable.value:
if value.name not in values:
raise DictConsistencyError(_(f'value "{value.name}" of variable "{variable.name}" is not in list of all expected values ({values})'), 15)
else:
new_value = self.objectspace.value(check.xmlfiles)
new_value.name = values[0]
new_value.type = type_
variable.value = [new_value]
def convert_check(self):
for check in self.objectspace.space.constraints.check: for check in self.objectspace.space.constraints.check:
variable = self.objectspace.paths.get_variable_obj(check.target) variable = self.objectspace.paths.get_variable_obj(check.target)
if check.name == 'valid_entier': name = check.name
if name == 'valid_entier':
if not hasattr(check, 'param'): if not hasattr(check, 'param'):
msg = _(f'{check.name} must have, at least, 1 param') raise DictConsistencyError(_('{} must have, at least, 1 param').format(name), 17)
raise DictConsistencyError(msg, 17)
for param in check.param: for param in check.param:
if param.type != 'number': if param.type != 'number':
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
msg = _(f'param in "valid_entier" must be an "integer", not "{param.type}"' raise DictConsistencyError(_(f'param in "valid_entier" must be an "integer", not "{param.type}" in {xmlfiles}'), 18)
f' in {xmlfiles}')
raise DictConsistencyError(msg, 18)
if param.name == 'mini': if param.name == 'mini':
variable.min_number = int(param.text) variable.min_number = int(param.text)
elif param.name == 'maxi': elif param.name == 'maxi':
variable.max_number = int(param.text) variable.max_number = int(param.text)
else: else:
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
msg = _(f'unknown parameter "{param.name}" in check "valid_entier" ' raise DictConsistencyError(_(f'unknown parameter "{param.name}" in check "valid_entier" for variable "{check.target}" in {xmlfiles}'), 19)
f'for variable "{check.target}" in {xmlfiles}')
raise DictConsistencyError(msg, 19)
else: else:
check_ = self.objectspace.check(variable.xmlfiles)
check_.name = name
check_.warnings_only = check.warnings_only
if hasattr(check, 'param'):
check_.param = check.param
if not hasattr(variable, 'check'): if not hasattr(variable, 'check'):
variable.check = [] variable.check = []
variable.check.append(check) variable.check.append(check_)
del self.objectspace.space.constraints.check
def convert_fill(self) -> None: def convert_fill(self): # pylint: disable=C0111,R0912
"""valid and manage <fill> # sort fill/auto by index
""" fills = {fill.index: fill for idx, fill in enumerate(self.objectspace.space.constraints.fill)}
indexes = list(fills.keys())
indexes.sort()
targets = [] targets = []
for fill in self.objectspace.space.constraints.fill: for idx in indexes:
fill = fills[idx]
# test if it's redefined calculation # test if it's redefined calculation
if fill.target in targets: if fill.target in targets:
xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
msg = _(f'A fill already exists for the target of "{fill.target}" created ' raise DictConsistencyError(_(f'A fill already exists for the target of "{fill.target}" created in {xmlfiles}'), 24)
f'in {xmlfiles}')
raise DictConsistencyError(msg, 24)
targets.append(fill.target) targets.append(fill.target)
#
# test if the function exists
if fill.name not in self.functions: if fill.name not in self.functions:
xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
msg = _(f'cannot find fill function "{fill.name}" in {xmlfiles}') raise DictConsistencyError(_(f'cannot find fill function "{fill.name}" in {xmlfiles}'), 25)
raise DictConsistencyError(msg, 25)
namespace = fill.namespace
# let's replace the target by the path # let's replace the target by the path
fill.target, suffix = self.objectspace.paths.get_variable_path(fill.target, fill.target, suffix = self.objectspace.paths.get_variable_path(fill.target,
fill.namespace, namespace,
with_suffix=True, with_suffix=True,
) )
if suffix is not None: if suffix is not None:
xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
msg = _(f'Cannot add fill function to "{fill.target}" only ' raise DictConsistencyError(_(f'Cannot add fill function to "{fill.target}" only for the suffix "{suffix}" in {xmlfiles}'), 26)
f'for the suffix "{suffix}" in {xmlfiles}')
raise DictConsistencyError(msg, 26)
# get the target variable
variable = self.objectspace.paths.get_variable_obj(fill.target) variable = self.objectspace.paths.get_variable_obj(fill.target)
value = self.objectspace.value(variable.xmlfiles)
# create an object value
value = self.objectspace.value(fill.xmlfiles)
value.type = 'calculation' value.type = 'calculation'
value.name = fill.name value.name = fill.name
variable.value = [value] if hasattr(fill, 'param'):
param_to_delete = []
# manage params for fill_idx, param in enumerate(fill.param):
if not hasattr(fill, 'param'): if param.type not in ['suffix', 'string'] and not hasattr(param, 'text'):
continue xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
self.convert_fill_param(fill) raise DictConsistencyError(_(f"All '{param.type}' variables must have a value in order to calculate {fill.target} in {xmlfiles}"), 27)
if fill.param: if param.type == 'suffix':
if hasattr(param, 'text'):
xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
raise DictConsistencyError(_(f'"{param.type}" variables must not have a value in order to calculate "{fill.target}" in {xmlfiles}'), 28)
if not self.objectspace.paths.variable_is_dynamic(fill.target):
xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
raise DictConsistencyError(_(f'Cannot set suffix target to the none dynamic variable "{fill.target}" in {xmlfiles}'), 53)
if param.type == 'string':
if not hasattr(param, 'text'):
param.text = None
if param.type == 'variable':
try:
param.text, suffix = self.objectspace.paths.get_variable_path(param.text,
namespace,
with_suffix=True,
)
if suffix:
param.suffix = suffix
except DictConsistencyError as err:
if err.errno != 42:
raise err
if param.optional is False:
raise err
param_to_delete.append(fill_idx)
continue
else:
param.notraisepropertyerror = None
param_to_delete.sort(reverse=True)
for param_idx in param_to_delete:
fill.param.pop(param_idx)
value.param = fill.param value.param = fill.param
variable.value = [value]
del self.objectspace.space.constraints.fill
def convert_fill_param(self, def remove_constraints(self):
fill: "self.objectspace.fill", if hasattr(self.objectspace.space.constraints, 'index'):
) -> None: del self.objectspace.space.constraints.index
""" valid and convert fill's param del self.objectspace.space.constraints.namespace
""" del self.objectspace.space.constraints.xmlfiles
param_to_delete = [] if vars(self.objectspace.space.constraints): # pragma: no cover
for param_idx, param in enumerate(fill.param): raise Exception('constraints again?')
if param.type == 'string' and not hasattr(param, 'text'): del self.objectspace.space.constraints
param.text = None
if param.type == 'suffix':
if hasattr(param, 'text'):
xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
msg = _(f'"{param.type}" variables must not have a value in order '
f'to calculate "{fill.target}" in {xmlfiles}')
raise DictConsistencyError(msg, 28)
if not self.objectspace.paths.variable_is_dynamic(fill.target):
xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
msg = _('Cannot set suffix target to the none dynamic variable '
f'"{fill.target}" in {xmlfiles}')
raise DictConsistencyError(msg, 53)
elif not hasattr(param, 'text'):
xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
msg = _(f'All "{param.type}" variables must have a value in order '
f'to calculate "{fill.target}" in {xmlfiles}')
raise DictConsistencyError(msg, 27)
if param.type == 'variable':
try:
text, suffix = self.objectspace.paths.get_variable_path(param.text,
fill.namespace,
with_suffix=True,
)
param.text = text
if suffix:
param.suffix = suffix
except DictConsistencyError as err:
if err.errno != 42 or not param.optional:
raise err
param_to_delete.append(param_idx)
param_to_delete.sort(reverse=True)
for param_idx in param_to_delete:
fill.param.pop(param_idx)

View File

@ -6,7 +6,7 @@ from ..error import DictConsistencyError
modes_level = ('basic', 'normal', 'expert') modes_level = ('basic', 'normal', 'expert')
class Mode: class Mode(object):
def __init__(self, name, level): def __init__(self, name, level):
self.name = name self.name = name
self.level = level self.level = level
@ -40,8 +40,8 @@ class FamilyAnnotator:
if hasattr(family, 'family'): if hasattr(family, 'family'):
space = family.family space = family.family
removed_families = [] removed_families = []
for family_name, sfamily in space.items(): for family_name, family in space.items():
if not hasattr(sfamily, 'variable') or len(sfamily.variable) == 0: if not hasattr(family, 'variable') or len(family.variable) == 0:
removed_families.append(family_name) removed_families.append(family_name)
for family_name in removed_families: for family_name in removed_families:
del space[family_name] del space[family_name]
@ -51,9 +51,9 @@ class FamilyAnnotator:
return return
for family in self.objectspace.space.variables.values(): for family in self.objectspace.space.variables.values():
if hasattr(family, 'family'): if hasattr(family, 'family'):
for vfamily in family.family.values(): for family in family.family.values():
mode = modes_level[-1] mode = modes_level[-1]
for variable in vfamily.variable.values(): for variable in family.variable.values():
if isinstance(variable, self.objectspace.leadership): if isinstance(variable, self.objectspace.leadership):
variable_mode = variable.variable[0].mode variable_mode = variable.variable[0].mode
variable.variable[0].mode = None variable.variable[0].mode = None
@ -62,28 +62,24 @@ class FamilyAnnotator:
variable_mode = variable.mode variable_mode = variable.mode
if variable_mode is not None and modes[mode] > modes[variable_mode]: if variable_mode is not None and modes[mode] > modes[variable_mode]:
mode = variable_mode mode = variable_mode
vfamily.mode = mode family.mode = mode
def dynamic_families(self): # pylint: disable=C0111 def dynamic_families(self): # pylint: disable=C0111
if not hasattr(self.objectspace.space, 'variables'): if not hasattr(self.objectspace.space, 'variables'):
return return
for family in self.objectspace.space.variables.values(): for family in self.objectspace.space.variables.values():
if hasattr(family, 'family'): if hasattr(family, 'family'):
for vfamily in family.family.values(): for family in family.family.values():
if 'dynamic' in vars(vfamily): if 'dynamic' in vars(family):
namespace = self.objectspace.paths.get_variable_namespace(vfamily.dynamic) namespace = self.objectspace.paths.get_variable_namespace(family.dynamic)
varpath = self.objectspace.paths.get_variable_path(vfamily.dynamic, namespace) varpath = self.objectspace.paths.get_variable_path(family.dynamic, namespace)
obj = self.objectspace.paths.get_variable_obj(varpath) obj = self.objectspace.paths.get_variable_obj(varpath)
if not obj.multi: if not obj.multi:
xmlfiles = self.objectspace.display_xmlfiles(vfamily.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(family.xmlfiles)
raise DictConsistencyError(_(f'dynamic family "{vfamily.name}" must be linked to multi variable in {xmlfiles}'), 16) raise DictConsistencyError(_(f'dynamic family "{family.name}" must be linked to multi variable in {xmlfiles}'), 16)
vfamily.dynamic = varpath family.dynamic = varpath
def annotate_variable(self, def annotate_variable(self, variable, family_mode, path, is_follower=False):
variable,
family_mode: str,
is_follower=False,
) -> None:
# if the variable is mandatory and doesn't have any value # if the variable is mandatory and doesn't have any value
# then the variable's mode is set to 'basic' # then the variable's mode is set to 'basic'
if not hasattr(variable, 'value') and variable.type == 'boolean': if not hasattr(variable, 'value') and variable.type == 'boolean':
@ -96,28 +92,32 @@ class FamilyAnnotator:
for value in variable.value: for value in variable.value:
if value.type == 'calculation': if value.type == 'calculation':
has_value = False has_value = False
has_variable = False
if hasattr(value, 'param'): if hasattr(value, 'param'):
for param in value.param: for param in value.param:
if param.type == 'variable': if param.type == 'variable':
has_variable = True
break break
#if not has_variable:
# # if one parameter is a variable, let variable choice if it's mandatory
# variable.mandatory = True
if has_value: if has_value:
# if has value but without any calculation # if has value but without any calculation
variable.mandatory = True variable.mandatory = True
if variable.mandatory is True and (not hasattr(variable, 'value') or is_follower): if variable.mandatory is True and (not hasattr(variable, 'value') or is_follower):
variable.mode = modes_level[0] variable.mode = modes_level[0]
if variable.mode is not None and modes[variable.mode] < modes[family_mode] and (not is_follower or variable.mode != modes_level[0]): if variable.mode != None and modes[variable.mode] < modes[family_mode] and (not is_follower or variable.mode != modes_level[0]):
variable.mode = family_mode variable.mode = family_mode
if variable.hidden is True: if variable.hidden is True:
variable.frozen = True variable.frozen = True
if not variable.auto_save is True and \ if not variable.auto_save is True and 'force_default_on_freeze' not in vars(variable):
not variable.auto_freeze and \
'force_default_on_freeze' not in vars(variable):
variable.force_default_on_freeze = True variable.force_default_on_freeze = True
def change_variable_mode(self): # pylint: disable=C0111 def change_variable_mode(self): # pylint: disable=C0111
if not hasattr(self.objectspace.space, 'variables'): if not hasattr(self.objectspace.space, 'variables'):
return return
for variables in self.objectspace.space.variables.values(): for variables in self.objectspace.space.variables.values():
namespace = variables.name
if hasattr(variables, 'family'): if hasattr(variables, 'family'):
for family in variables.family.values(): for family in variables.family.values():
family_mode = family.mode family_mode = family.mode
@ -125,6 +125,7 @@ class FamilyAnnotator:
for variable in family.variable.values(): for variable in family.variable.values():
if isinstance(variable, self.objectspace.leadership): if isinstance(variable, self.objectspace.leadership):
mode = modes_level[-1]
for idx, follower in enumerate(variable.variable): for idx, follower in enumerate(variable.variable):
if follower.auto_save is True: if follower.auto_save is True:
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
@ -133,10 +134,8 @@ class FamilyAnnotator:
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
raise DictConsistencyError(_(f'leader/followers "{follower.name}" could not be auto_freeze in {xmlfiles}'), 30) raise DictConsistencyError(_(f'leader/followers "{follower.name}" could not be auto_freeze in {xmlfiles}'), 30)
is_follower = idx != 0 is_follower = idx != 0
self.annotate_variable(follower, path = '{}.{}.{}'.format(family.path, variable.name, follower.name)
family_mode, self.annotate_variable(follower, family_mode, path, is_follower)
is_follower,
)
# leader's mode is minimum level # leader's mode is minimum level
if modes[variable.variable[0].mode] > modes[follower.mode]: if modes[variable.variable[0].mode] > modes[follower.mode]:
follower.mode = variable.variable[0].mode follower.mode = variable.variable[0].mode
@ -148,6 +147,6 @@ class FamilyAnnotator:
# auto_freeze's variable is set in 'basic' mode if its mode is 'normal' # auto_freeze's variable is set in 'basic' mode if its mode is 'normal'
if variable.auto_freeze is True and variable.mode != modes_level[-1]: if variable.auto_freeze is True and variable.mode != modes_level[-1]:
variable.mode = modes_level[0] variable.mode = modes_level[0]
self.annotate_variable(variable, path = '{}.{}'.format(family.path, variable.name)
family_mode, self.annotate_variable(variable, family_mode, path)
)

View File

@ -1,5 +1,3 @@
"""Annotate group
"""
from typing import List from typing import List
from ..i18n import _ from ..i18n import _
@ -7,20 +5,15 @@ from ..error import DictConsistencyError
class GroupAnnotator: class GroupAnnotator:
"""Annotate group
"""
def __init__(self, def __init__(self,
objectspace, objectspace,
): ):
self.objectspace = objectspace self.objectspace = objectspace
if not hasattr(self.objectspace.space, 'constraints') or \ if not hasattr(self.objectspace.space, 'constraints') or not hasattr(self.objectspace.space.constraints, 'group'):
not hasattr(self.objectspace.space.constraints, 'group'):
return return
self.convert_groups() self.convert_groups()
def convert_groups(self): # pylint: disable=C0111 def convert_groups(self): # pylint: disable=C0111
"""convert groups
"""
for group in self.objectspace.space.constraints.group: for group in self.objectspace.space.constraints.group:
leader_fullname = group.leader leader_fullname = group.leader
leader_family_name = self.objectspace.paths.get_variable_family_name(leader_fullname) leader_family_name = self.objectspace.paths.get_variable_family_name(leader_fullname)
@ -30,20 +23,18 @@ class GroupAnnotator:
leader_fullname = '.'.join([namespace, leader_family_name, leader_fullname]) leader_fullname = '.'.join([namespace, leader_family_name, leader_fullname])
follower_names = list(group.follower.keys()) follower_names = list(group.follower.keys())
has_a_leader = False has_a_leader = False
leader_family = leader_fullname.rsplit('.', 1)[0] ori_leader_family = self.objectspace.paths.get_family_obj(leader_fullname.rsplit('.', 1)[0])
ori_leader_family = self.objectspace.paths.get_family_obj(leader_family)
for variable in list(ori_leader_family.variable.values()): for variable in list(ori_leader_family.variable.values()):
if has_a_leader: if has_a_leader:
# it's a follower # it's a follower
self.manage_follower(leader_family_name, self.manage_follower(namespace,
leader_family_name,
variable, variable,
leadership_name, leadership_name,
follower_names, follower_names,
leader_space,
leader_is_hidden,
) )
if leader_is_hidden:
variable.frozen = True
variable.force_default_on_freeze = True
leader_space.variable.append(variable)
ori_leader_family.variable.pop(variable.name) ori_leader_family.variable.pop(variable.name)
if follower_names == []: if follower_names == []:
# no more follower # no more follower
@ -65,6 +56,7 @@ class GroupAnnotator:
leader_family_name, leader_family_name,
leadership_name, leadership_name,
leader_name, leader_name,
namespace,
variable, variable,
group, group,
leader_fullname, leader_fullname,
@ -73,9 +65,7 @@ class GroupAnnotator:
else: else:
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
joined = '", "'.join(follower_names) joined = '", "'.join(follower_names)
msg = _(f'when parsing leadership, we espect to find those followers "{joined}" ' raise DictConsistencyError(_(f'when parsing leadership, we espect to find those followers "{joined}" in {xmlfiles}'), 31)
f'in {xmlfiles}')
raise DictConsistencyError(msg, 31)
del self.objectspace.space.constraints.group del self.objectspace.space.constraints.group
def manage_leader(self, def manage_leader(self,
@ -83,16 +73,15 @@ class GroupAnnotator:
leader_family_name: str, leader_family_name: str,
leadership_name: str, leadership_name: str,
leader_name: str, leader_name: str,
namespace: str,
variable: 'Variable', variable: 'Variable',
group: 'Group', group: 'Group',
leader_fullname: str, leader_fullname: str,
) -> None: ) -> None:
"""manage leader's variable # manage leader's variable
"""
if variable.multi is not True: if variable.multi is not True:
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
msg = _(f'the variable "{variable.name}" in a group must be multi in {xmlfiles}') raise DictConsistencyError(_(f'the variable "{variable.name}" in a group must be multi in {xmlfiles}'), 32)
raise DictConsistencyError(msg, 32)
leader_space.variable = [] leader_space.variable = []
leader_space.name = leadership_name leader_space.name = leadership_name
leader_space.hidden = variable.hidden leader_space.hidden = variable.hidden
@ -109,7 +98,6 @@ class GroupAnnotator:
leader_space.doc = variable.description leader_space.doc = variable.description
else: else:
leader_space.doc = variable.name leader_space.doc = variable.name
namespace = variable.namespace
leadership_path = namespace + '.' + leader_family_name + '.' + leadership_name leadership_path = namespace + '.' + leader_family_name + '.' + leadership_name
self.objectspace.paths.add_family(namespace, self.objectspace.paths.add_family(namespace,
leadership_path, leadership_path,
@ -127,21 +115,25 @@ class GroupAnnotator:
return leader_is_hidden return leader_is_hidden
def manage_follower(self, def manage_follower(self,
namespace: str,
leader_family_name: str, leader_family_name: str,
variable: 'Variable', variable: 'Variable',
leader_name: str, leader_name: str,
follower_names: List[str], follower_names: List[str],
leader_space: 'Leadership',
leader_is_hidden: bool,
) -> None: ) -> None:
"""manage follower if variable.name != follower_names[0]:
"""
follower_name = follower_names.pop(0)
if variable.name != follower_name:
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
msg = _('when parsing leadership, we espect to find the follower ' raise DictConsistencyError(_(f'when parsing leadership, we espect to find the follower "{follower_names[0]}" but we found "{variable.name}" in {xmlfiles}'), 33)
f'"{follower_name}" but we found "{variable.name}" in {xmlfiles}') follower_names.remove(variable.name)
raise DictConsistencyError(msg, 33) if leader_is_hidden:
self.objectspace.paths.set_leader(variable.namespace, variable.frozen = True
variable.force_default_on_freeze = True
leader_space.variable.append(variable) # pylint: disable=E1101
self.objectspace.paths.set_leader(namespace,
leader_family_name, leader_family_name,
variable.name, variable.name,
leader_name, leader_name,
) )

View File

@ -1,35 +1,24 @@
"""Annotate properties
"""
from ..i18n import _ from ..i18n import _
from ..error import DictConsistencyError from ..error import DictConsistencyError
PROPERTIES = ('hidden', 'frozen', 'auto_freeze', 'auto_save', 'force_default_on_freeze', PROPERTIES = ('hidden', 'frozen', 'auto_freeze', 'auto_save', 'force_default_on_freeze',
'force_store_value', 'disabled', 'mandatory') 'force_store_value', 'disabled', 'mandatory')
CONVERT_PROPERTIES = {'auto_save': ['force_store_value'], CONVERT_PROPERTIES = {'auto_save': ['force_store_value'], 'auto_freeze': ['force_store_value', 'auto_freeze']}
'auto_freeze': ['force_store_value', 'auto_freeze'],
}
class PropertyAnnotator: class PropertyAnnotator:
"""Annotate properties
"""
def __init__(self, objectspace): def __init__(self, objectspace):
self.objectspace = objectspace self.objectspace = objectspace
if hasattr(self.objectspace.space, 'services'): self.convert_annotator()
self.convert_services()
if hasattr(self.objectspace.space, 'variables'):
self.convert_variables()
def convert_property(self, def convert_property(self,
variable, variable,
) -> None: ):
"""convert properties
"""
properties = [] properties = []
for prop in PROPERTIES: for prop in PROPERTIES:
if hasattr(variable, prop): if hasattr(variable, prop):
if getattr(variable, prop) is True: if getattr(variable, prop) == True:
for subprop in CONVERT_PROPERTIES.get(prop, [prop]): for subprop in CONVERT_PROPERTIES.get(prop, [prop]):
properties.append(subprop) properties.append(subprop)
setattr(variable, prop, None) setattr(variable, prop, None)
@ -38,46 +27,35 @@ class PropertyAnnotator:
variable.mode = None variable.mode = None
if 'force_store_value' in properties and 'force_default_on_freeze' in properties: if 'force_store_value' in properties and 'force_default_on_freeze' in properties:
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
msg = _('cannot have auto_freeze or auto_store with the hidden ' raise DictConsistencyError(_(f'cannot have auto_freeze or auto_store with the hidden variable "{variable.name}" in {xmlfiles}'), 50)
f'variable "{variable.name}" in {xmlfiles}')
raise DictConsistencyError(msg, 50)
if properties: if properties:
variable.properties = frozenset(properties) variable.properties = frozenset(properties)
def convert_services(self) -> None: def convert_annotator(self): # pylint: disable=C0111
"""convert services if hasattr(self.objectspace.space, 'services'):
""" self.convert_property(self.objectspace.space.services)
self.convert_property(self.objectspace.space.services) for services in self.objectspace.space.services.service.values():
for services in self.objectspace.space.services.service.values(): self.convert_property(services)
self.convert_property(services) for service in vars(services).values():
for service in vars(services).values(): if isinstance(service, self.objectspace.family):
if not isinstance(service, self.objectspace.family): self.convert_property(service)
continue if hasattr(service, 'family'):
self.convert_property(service) self.convert_property(service)
if not hasattr(service, 'family'): for family in service.family:
continue self.convert_property(family)
self.convert_property(service) if hasattr(family, 'variable'):
for family in service.family: for variable in family.variable:
self.convert_property(family) self.convert_property(variable)
if not hasattr(family, 'variable'): if hasattr(self.objectspace.space, 'variables'):
continue for variables in self.objectspace.space.variables.values():
for variable in family.variable: if hasattr(variables, 'family'):
self.convert_property(variable) for family in variables.family.values():
self.convert_property(family)
def convert_variables(self) -> None: if hasattr(family, 'variable'):
"""convert variables for variable in family.variable.values():
""" if isinstance(variable, self.objectspace.leadership):
for variables in self.objectspace.space.variables.values(): self.convert_property(variable)
if not hasattr(variables, 'family'): for follower in variable.variable:
continue self.convert_property(follower)
for family in variables.family.values(): else:
self.convert_property(family) self.convert_property(variable)
if not hasattr(family, 'variable'):
continue
for variable in family.variable.values():
if isinstance(variable, self.objectspace.leadership):
self.convert_property(variable)
for follower in variable.variable:
self.convert_property(follower)
else:
self.convert_property(variable)

View File

@ -45,7 +45,7 @@ class ServiceAnnotator:
self.objectspace.space.services.name = 'services' self.objectspace.space.services.name = 'services'
self.objectspace.space.services.doc = 'services' self.objectspace.space.services.doc = 'services'
families = {} families = {}
for service_name in self.objectspace.space.services.service.keys(): for idx, service_name in enumerate(self.objectspace.space.services.service.keys()):
service = self.objectspace.space.services.service[service_name] service = self.objectspace.space.services.service[service_name]
new_service = self.objectspace.service(service.xmlfiles) new_service = self.objectspace.service(service.xmlfiles)
for elttype, values in vars(service).items(): for elttype, values in vars(service).items():

View File

@ -141,7 +141,7 @@ class VariableAnnotator:
if not hasattr(family, 'separators'): if not hasattr(family, 'separators'):
continue continue
if hasattr(family.separators, 'separator'): if hasattr(family.separators, 'separator'):
for separator in family.separators.separator: for idx, separator in enumerate(family.separators.separator):
option = self.objectspace.paths.get_variable_obj(separator.name) option = self.objectspace.paths.get_variable_obj(separator.name)
if hasattr(option, 'separator'): if hasattr(option, 'separator'):
subpath = self.objectspace.paths.get_variable_path(separator.name, subpath = self.objectspace.paths.get_variable_path(separator.name,
@ -151,3 +151,4 @@ class VariableAnnotator:
raise DictConsistencyError(_(f'{subpath} already has a separator in {xmlfiles}'), 35) raise DictConsistencyError(_(f'{subpath} already has a separator in {xmlfiles}'), 35)
option.separator = separator.text option.separator = separator.text
del family.separators del family.separators

View File

@ -6,15 +6,17 @@ fichier de configuration pour rougail
from os.path import join, abspath, dirname from os.path import join, abspath, dirname
ROUGAILROOT = '/var/rougail' rougailroot = '/var/rougail'
DTDDIR = join(dirname(abspath(__file__)), 'data') dtddir = join(dirname(abspath(__file__)), 'data')
Config = {'rougailroot': ROUGAILROOT, Config = {'rougailroot': rougailroot,
'patch_dir': join(ROUGAILROOT, 'patches'), 'patch_dir': join(rougailroot, 'patches'),
'manifests_dir': join(ROUGAILROOT, 'manifests'), 'manifests_dir': join(rougailroot, 'manifests'),
'templates_dir': join(ROUGAILROOT, 'templates'), 'templates_dir': join(rougailroot, 'templates'),
'dtdfilename': join(DTDDIR, 'rougail.dtd'), 'dtdfilename': join(dtddir, 'rougail.dtd'),
'dtddir': DTDDIR, 'dtddir': dtddir,
# chemin du répertoire source des fichiers templates
'patch_dir': '/srv/rougail/patch',
'variable_namespace': 'rougail', 'variable_namespace': 'rougail',
} }

View File

@ -125,7 +125,7 @@
<!ATTLIST check level (error|warning) "error"> <!ATTLIST check level (error|warning) "error">
<!ELEMENT condition ((target | param)+ )> <!ELEMENT condition ((target | param)+ )>
<!ATTLIST condition name (disabled_if_in|disabled_if_not_in|hidden_if_in|hidden_if_not_in|mandatory_if_in|mandatory_if_not_in) #REQUIRED> <!ATTLIST condition name (disabled_if_in|disabled_if_not_in|hidden_if_in|auto_hidden_if_not_in|hidden_if_not_in|mandatory_if_in|mandatory_if_not_in) #REQUIRED>
<!ATTLIST condition source CDATA #REQUIRED> <!ATTLIST condition source CDATA #REQUIRED>
<!ATTLIST condition fallback (True|False) "False"> <!ATTLIST condition fallback (True|False) "False">
<!ATTLIST condition force_condition_on_fallback (True|False) "False"> <!ATTLIST condition force_condition_on_fallback (True|False) "False">

View File

@ -11,6 +11,7 @@ class TemplateError(ConfigError):
class TemplateDisabled(TemplateError): class TemplateDisabled(TemplateError):
"""Template is disabled. """Template is disabled.
""" """
pass
class OperationError(Exception): class OperationError(Exception):

View File

@ -1,3 +1,6 @@
from typing import List
from .i18n import _ from .i18n import _
from .xmlreflector import XMLReflector from .xmlreflector import XMLReflector
from .utils import normalize_family from .utils import normalize_family
@ -108,6 +111,7 @@ class RougailObjSpace:
if name.endswith('_'): if name.endswith('_'):
name = name[:-1] name = name[:-1]
setattr(self, elt, type(name, (RootRougailObject,), dict())) setattr(self, elt, type(name, (RootRougailObject,), dict()))
self.Leadership = self.leadership
def display_xmlfiles(self, def display_xmlfiles(self,
xmlfiles: list, xmlfiles: list,
@ -161,7 +165,8 @@ class RougailObjSpace:
self.remove(child, self.remove(child,
variableobj, variableobj,
) )
self.set_path(child, self.set_path(space,
child,
namespace, namespace,
document, document,
variableobj, variableobj,
@ -195,7 +200,7 @@ class RougailObjSpace:
child, child,
namespace, namespace,
) )
if Atom in obj.__mro__: elif Atom in obj.__mro__:
if child.tag in vars(space): if child.tag in vars(space):
# Atom instance has to be a singleton here # Atom instance has to be a singleton here
# we do not re-create it, we reuse it # we do not re-create it, we reuse it
@ -363,6 +368,7 @@ class RougailObjSpace:
self.space.constraints.fill.pop(idx) self.space.constraints.fill.pop(idx)
def set_path(self, def set_path(self,
space,
child, child,
namespace, namespace,
document, document,
@ -376,7 +382,7 @@ class RougailObjSpace:
self.paths.add_variable(namespace, self.paths.add_variable(namespace,
child.attrib['name'], child.attrib['name'],
family_name, family_name,
document.attrib.get('dynamic') is not None, document.attrib.get('dynamic') != None,
variableobj, variableobj,
) )
if child.attrib.get('redefine', 'False') == 'True': if child.attrib.get('redefine', 'False') == 'True':

View File

@ -1,4 +1,5 @@
from .i18n import _ from .i18n import _
from .utils import normalize_family
from .error import OperationError, DictConsistencyError from .error import OperationError, DictConsistencyError
from .config import Config from .config import Config
@ -141,7 +142,7 @@ class Path:
else: else:
dico = self._get_variable(name) dico = self._get_variable(name)
if not allow_source and dico['namespace'] not in [Config['variable_namespace'], 'services'] and current_namespace != dico['namespace']: if not allow_source and dico['namespace'] not in [Config['variable_namespace'], 'services'] and current_namespace != dico['namespace']:
raise DictConsistencyError(_(f'A variable located in the "{dico["namespace"]}" namespace shall not be used in the "{current_namespace}" namespace'), 41) raise DictConsistencyError(_(f'A variable located in the "{dico["namespace"]}" namespace shall not be used in the "{current_namespace}" namespace'), 41)
list_path = [dico['namespace'], dico['family']] list_path = [dico['namespace'], dico['family']]
if dico['leader'] is not None: if dico['leader'] is not None:
list_path.append(dico['leader']) list_path.append(dico['leader'])

View File

@ -18,7 +18,7 @@ from Cheetah.NameMapper import NotFound as CheetahNotFound
try: try:
from tiramisu3 import Config from tiramisu3 import Config
from tiramisu3.error import PropertiesOptionError # pragma: no cover from tiramisu3.error import PropertiesOptionError # pragma: no cover
except ModuleNotFoundError: # pragma: no cover except: # pragma: no cover
from tiramisu import Config from tiramisu import Config
from tiramisu.error import PropertiesOptionError from tiramisu.error import PropertiesOptionError
@ -89,7 +89,12 @@ class CheetahTemplate(ChtTemplate):
return None return None
class CreoleLeaderIndex: class CreoleValue:
def __str__(self):
return str(self._value)
class CreoleLeaderIndex(CreoleValue):
def __init__(self, def __init__(self,
value, value,
follower, follower,
@ -107,9 +112,6 @@ class CreoleLeaderIndex:
raise AttributeError() raise AttributeError()
return value return value
def __str__(self):
return str(self._value)
def __lt__(self, value): def __lt__(self, value):
return self._value.__lt__(value) return self._value.__lt__(value)
@ -135,7 +137,7 @@ class CreoleLeaderIndex:
return value + self._value return value + self._value
class CreoleLeader: class CreoleLeader(CreoleValue):
def __init__(self, def __init__(self,
value, value,
) -> None: ) -> None:
@ -185,8 +187,7 @@ class CreoleExtra:
self.suboption = suboption self.suboption = suboption
def __getattr__(self, def __getattr__(self,
key: str, key: str) -> Any:
) -> Any:
return self.suboption[key] return self.suboption[key]
def __iter__(self): def __iter__(self):
@ -211,8 +212,8 @@ class CreoleTemplateEngine:
if eosfunc_file is not None: if eosfunc_file is not None:
eosfunc = SourceFileLoader('eosfunc', eosfunc_file).load_module() eosfunc = SourceFileLoader('eosfunc', eosfunc_file).load_module()
for func in dir(eosfunc): for func in dir(eosfunc):
if not func.startswith('_'): if not func.startswith('_'):
eos[func] = getattr(eosfunc, func) eos[func] = getattr(eosfunc, func)
self.eosfunc = eos self.eosfunc = eos
self.rougail_variables_dict = {} self.rougail_variables_dict = {}
@ -237,8 +238,8 @@ class CreoleTemplateEngine:
self.rougail_variables_dict[await option.option.name()] = await option.value.get() self.rougail_variables_dict[await option.option.name()] = await option.value.get()
async def load_eole_variables(self, async def load_eole_variables(self,
optiondescription, namespace,
): optiondescription):
families = {} families = {}
for family in await optiondescription.list('all'): for family in await optiondescription.list('all'):
variables = {} variables = {}
@ -256,7 +257,9 @@ class CreoleTemplateEngine:
) )
variables[leader_name] = leader variables[leader_name] = leader
else: else:
subfamilies = await self.load_eole_variables(variable) subfamilies = await self.load_eole_variables(await variable.option.name(),
variable,
)
variables[await variable.option.name()] = subfamilies variables[await variable.option.name()] = subfamilies
else: else:
variables[await variable.option.name()] = await variable.value.get() variables[await variable.option.name()] = await variable.value.get()
@ -298,6 +301,7 @@ class CreoleTemplateEngine:
source: str, source: str,
true_destfilename: str, true_destfilename: str,
destfilename: str, destfilename: str,
filevar: Dict,
variable: Any, variable: Any,
): ):
"""Process a cheetah template """Process a cheetah template
@ -323,6 +327,7 @@ class CreoleTemplateEngine:
def instance_file(self, def instance_file(self,
filevar: Dict, filevar: Dict,
service_name: str,
tmp_dir: str, tmp_dir: str,
dest_dir: str, dest_dir: str,
) -> None: ) -> None:
@ -350,8 +355,8 @@ class CreoleTemplateEngine:
self.process(source, self.process(source,
filename, filename,
destfilename, destfilename,
var, filevar,
) var)
else: else:
copy(source, destfilename) copy(source, destfilename)
@ -368,11 +373,13 @@ class CreoleTemplateEngine:
if namespace == Config['variable_namespace']: if namespace == Config['variable_namespace']:
await self.load_eole_variables_rougail(option) await self.load_eole_variables_rougail(option)
else: else:
families = await self.load_eole_variables(option) families = await self.load_eole_variables(namespace,
option)
self.rougail_variables_dict[namespace] = families self.rougail_variables_dict[namespace] = families
for template in listdir('.'): for template in listdir('.'):
self.prepare_template(template, tmp_dir, patch_dir) self.prepare_template(template, tmp_dir, patch_dir)
for service_obj in await self.config.option('services').list('all'): for service_obj in await self.config.option('services').list('all'):
service_name = await service_obj.option.doc()
for fills in await service_obj.list('all'): for fills in await service_obj.list('all'):
if await fills.option.name() in ['files', 'overrides']: if await fills.option.name() in ['files', 'overrides']:
for fill_obj in await fills.list('all'): for fill_obj in await fills.list('all'):
@ -382,6 +389,7 @@ class CreoleTemplateEngine:
raise FileNotFound(_(f"File {filename} does not exist.")) raise FileNotFound(_(f"File {filename} does not exist."))
if fill.get('activate', False): if fill.get('activate', False):
self.instance_file(fill, self.instance_file(fill,
service_name,
tmp_dir, tmp_dir,
dest_dir, dest_dir,
) )

View File

@ -1,6 +1,6 @@
try: try:
from tiramisu3 import DynOptionDescription from tiramisu3 import DynOptionDescription
except ModuleNotFoundError: except:
from tiramisu import DynOptionDescription from tiramisu import DynOptionDescription
from .utils import normalize_family from .utils import normalize_family

View File

@ -181,6 +181,7 @@ class ElementStorage:
class Common: class Common:
def __init__(self, def __init__(self,
elt,
storage, storage,
is_leader, is_leader,
path, path,
@ -205,7 +206,7 @@ class Common:
self.attrib['properties'] += ', ' self.attrib['properties'] += ', '
self.attrib['properties'] += prop self.attrib['properties'] += prop
def get_attrib(self): def get_attrib(self, attrib):
ret_list = [] ret_list = []
for key, value in self.attrib.items(): for key, value in self.attrib.items():
if value is None: if value is None:
@ -260,7 +261,8 @@ class Variable(Common):
is_leader, is_leader,
path, path,
): ):
super().__init__(storage, super().__init__(elt,
storage,
is_leader, is_leader,
path, path,
) )
@ -281,7 +283,7 @@ class Variable(Common):
self.attrib['opt'] = self.storage.get(self.attrib['opt']).get() self.attrib['opt'] = self.storage.get(self.attrib['opt']).get()
else: else:
self.parse_children() self.parse_children()
attrib = self.get_attrib() attrib = self.get_attrib(self.attrib)
self.option_name = self.storage.get_name(self.path) self.option_name = self.storage.get_name(self.path)
self.storage.text.append(f'{self.option_name} = {self.object_type}({attrib})') self.storage.text.append(f'{self.option_name} = {self.object_type}({attrib})')
self.populate_informations() self.populate_informations()
@ -302,7 +304,7 @@ class Variable(Common):
self.attrib[key] = value self.attrib[key] = value
def parse_children(self): def parse_children(self):
if 'default' not in self.attrib or self.attrib['multi']: if not 'default' in self.attrib or self.attrib['multi']:
self.attrib['default'] = [] self.attrib['default'] = []
if self.attrib['multi'] == 'submulti' and self.is_follower: if self.attrib['multi'] == 'submulti' and self.is_follower:
self.attrib['default_multi'] = [] self.attrib['default_multi'] = []
@ -365,9 +367,9 @@ class Variable(Common):
): ):
if param.type == 'string': if param.type == 'string':
return f'ParamValue("{param.text}")' return f'ParamValue("{param.text}")'
if param.type == 'number': elif param.type == 'number':
return f'ParamValue({param.text})' return f'ParamValue({param.text})'
if param.type == 'variable': elif param.type == 'variable':
value = {'option': param.text, value = {'option': param.text,
'notraisepropertyerror': param.notraisepropertyerror, 'notraisepropertyerror': param.notraisepropertyerror,
'todict': function in FUNC_TO_DICT, 'todict': function in FUNC_TO_DICT,
@ -375,10 +377,10 @@ class Variable(Common):
if hasattr(param, 'suffix'): if hasattr(param, 'suffix'):
value['suffix'] = param.suffix value['suffix'] = param.suffix
return self.build_param(value) return self.build_param(value)
if param.type == 'information': elif param.type == 'information':
return f'ParamInformation("{param.text}", None)' return f'ParamInformation("{param.text}", None)'
if param.type == 'suffix': elif param.type == 'suffix':
return 'ParamSuffix()' return f'ParamSuffix()'
raise LoaderError(_('unknown param type {}').format(param.type)) # pragma: no cover raise LoaderError(_('unknown param type {}').format(param.type)) # pragma: no cover
def populate_value(self, def populate_value(self,
@ -416,7 +418,8 @@ class Family(Common):
is_leader, is_leader,
path, path,
): ):
super().__init__(storage, super().__init__(elt,
storage,
is_leader, is_leader,
path, path,
) )
@ -432,7 +435,7 @@ class Family(Common):
self.parse_children() self.parse_children()
self.option_name = self.storage.get_name(self.path) self.option_name = self.storage.get_name(self.path)
object_name = self.get_object_name() object_name = self.get_object_name()
attrib = self.get_attrib() + ', children=[' + ', '.join([child.get() for child in self.children]) + ']' attrib = self.get_attrib(self.attrib) + ', children=[' + ', '.join([child.get() for child in self.children]) + ']'
self.storage.text.append(f'{self.option_name} = {object_name}({attrib})') self.storage.text.append(f'{self.option_name} = {object_name}({attrib})')
self.populate_informations() self.populate_informations()
return self.option_name return self.option_name
@ -458,6 +461,6 @@ class Family(Common):
def get_object_name(self): def get_object_name(self):
if 'suffixes' in self.attrib: if 'suffixes' in self.attrib:
return 'ConvertDynOptionDescription' return 'ConvertDynOptionDescription'
if not self.is_leader: elif not self.is_leader:
return 'OptionDescription' return 'OptionDescription'
return 'Leadership' return 'Leadership'

View File

@ -2,6 +2,7 @@
utilitaires créole utilitaires créole
""" """
from unicodedata import normalize, combining from unicodedata import normalize, combining
from .i18n import _
def normalize_family(family_name: str) -> str: def normalize_family(family_name: str) -> str:

View File

@ -3,13 +3,13 @@ from typing import List
from os.path import join, isfile from os.path import join, isfile
from os import listdir from os import listdir
from lxml.etree import DTD, parse, XMLSyntaxError from lxml.etree import DTD, parse, tostring, XMLSyntaxError
from .i18n import _ from .i18n import _
from .error import DictConsistencyError from .error import DictConsistencyError
class XMLReflector: class XMLReflector(object):
"""Helper class for loading the Creole XML file, """Helper class for loading the Creole XML file,
parsing it, validating against the Creole DTD, parsing it, validating against the Creole DTD,
writing the xml result on the disk writing the xml result on the disk

View File

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

View File

@ -1,15 +0,0 @@
from importlib.machinery import SourceFileLoader
func = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py').load_module()
for key, value in dict(locals()).items():
if key != ['SourceFileLoader', '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='module_instancie', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_4 = ChoiceOption(properties=frozenset({'auto_freeze', 'basic', 'force_store_value', 'frozen', 'hidden', 'mandatory', Calculation(calc_value, Params(ParamValue('auto_frozen'), kwargs={'condition': ParamOption(option_3, todict=True), 'expected': ParamValue('oui'), 'reverse_condition': ParamValue(True)}))}), name='mode_conteneur_actif', doc='No change', multi=False, default=Calculation(func.calc_val, Params((ParamValue("oui")), kwargs={})), values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'basic'}), 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

@ -1,21 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="oui/non" description="No change" hidden="True">
<value>non</value>
</variable>
<variable name="mode_conteneur_actif1" type="oui/non" description="No change">
<value>non</value>
</variable>
</family>
</variables>
<constraints>
<fill name="calc_val" target="mode_conteneur_actif">
<param type="variable" optional="True">mode_conteneur_actif4</param>
</fill>
</constraints>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

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

View File

@ -1,15 +0,0 @@
from importlib.machinery import SourceFileLoader
func = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py').load_module()
for key, value in dict(locals()).items():
if key != ['SourceFileLoader', '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=Calculation(func.calc_val, Params((), kwargs={})), 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_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

@ -1,25 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<variables>
<family name="general">
<variable name="module_instancie" type="oui/non" description="No change">
<value>non</value>
</variable>
<variable name="mode_conteneur_actif" type="oui/non" description="No change" auto_freeze="True">
<value>non</value>
</variable>
</family>
<separators/>
</variables>
<constraints>
<fill name="calc_val" target="mode_conteneur_actif">
<param>oui</param>
</fill>
<condition name="hidden_if_in" source="module_instancie">
<param>oui</param>
<target type="variable">mode_conteneur_actif</target>
</condition>
</constraints>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

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

View File

@ -1,15 +0,0 @@
from importlib.machinery import SourceFileLoader
func = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py').load_module()
for key, value in dict(locals()).items():
if key != ['SourceFileLoader', '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='module_instancie', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_4 = ChoiceOption(properties=frozenset({'auto_freeze', 'basic', 'force_store_value', 'mandatory', Calculation(calc_value, Params(ParamValue('hidden'), kwargs={'condition': ParamOption(option_3, todict=True), 'expected': ParamValue('oui')})), Calculation(calc_value, Params(ParamValue('auto_frozen'), kwargs={'condition': ParamOption(option_3, todict=True), 'expected': ParamValue('oui'), 'reverse_condition': ParamValue(True)}))}), name='mode_conteneur_actif', doc='No change', multi=False, default=Calculation(func.calc_val, Params((ParamValue("oui")), kwargs={})), values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'basic'}), 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

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

View File

@ -1,15 +0,0 @@
from importlib.machinery import SourceFileLoader
func = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py').load_module()
for key, value in dict(locals()).items():
if key != ['SourceFileLoader', '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 = StrOption(properties=frozenset({'basic', 'force_store_value', Calculation(calc_value, Params(ParamValue('hidden'), kwargs={'condition': ParamOption(option_3, todict=True), 'expected': ParamValue('oui')}))}), name='autosavevar', doc='autosave variable', multi=False, default=Calculation(func.calc_val, Params((ParamValue("oui")), kwargs={})))
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'basic'}), 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

@ -28,9 +28,9 @@ excludes = set([])
#excludes = set(['01base_file_utfchar']) #excludes = set(['01base_file_utfchar'])
test_ok -= excludes test_ok -= excludes
test_raise -= excludes test_raise -= excludes
#test_ok = ['01auto_autofreeze'] #test_ok = ['10valid_enum_eosfunc']
#test_ok = [] #test_ok = []
#test_raise = ['80auto_autofreeze'] #test_raise = ['80redefine_double_error']
#test_raise = [] #test_raise = []
ORI_DIR = getcwd() ORI_DIR = getcwd()