Compare commits
No commits in common. "d5ed39c1f35c3a96abebe1ea891647beda11fd24" and "13b1e9bf546f420c93e09cdeaa569092b8a1e1c7" have entirely different histories.
d5ed39c1f3
...
13b1e9bf54
|
@ -1,7 +1,5 @@
|
|||
"""Annotate constraints
|
||||
"""
|
||||
from typing import List
|
||||
from importlib.machinery import SourceFileLoader
|
||||
from typing import List, Any
|
||||
|
||||
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']
|
||||
|
||||
|
||||
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:
|
||||
"""Annotate constrainte
|
||||
"""
|
||||
def __init__(self,
|
||||
objectspace,
|
||||
eosfunc_file,
|
||||
|
@ -50,16 +24,18 @@ class ConstrainteAnnotator:
|
|||
eosfunc = SourceFileLoader('eosfunc', eosfunc_file).load_module()
|
||||
self.functions = dir(eosfunc)
|
||||
self.functions.extend(INTERNAL_FUNCTIONS)
|
||||
self.valid_enums = {}
|
||||
|
||||
self.convert_auto_freeze()
|
||||
self.valid_enums = {}
|
||||
if hasattr(self.objectspace.space.constraints, 'check'):
|
||||
self.check_check()
|
||||
self.check_replace_text()
|
||||
self.check_valid_enum()
|
||||
self.check_change_warning()
|
||||
self.convert_check()
|
||||
if hasattr(self.objectspace.space.constraints, 'condition'):
|
||||
self.convert_condition_target()
|
||||
self.check_params_target()
|
||||
self.filter_targets()
|
||||
self.convert_xxxlist_to_variable()
|
||||
self.check_condition_fallback_optional()
|
||||
self.check_choice_option_condition()
|
||||
|
@ -67,20 +43,16 @@ class ConstrainteAnnotator:
|
|||
self.convert_condition()
|
||||
if hasattr(self.objectspace.space.constraints, 'fill'):
|
||||
self.convert_fill()
|
||||
del self.objectspace.space.constraints
|
||||
self.remove_constraints()
|
||||
|
||||
def convert_auto_freeze(self):
|
||||
"""convert auto_freeze
|
||||
only if FREEZE_AUTOFREEZE_VARIABLE == 'oui' this variable is frozen
|
||||
"""
|
||||
def convert_auto_freeze(self): # pylint: disable=C0111
|
||||
def _convert_auto_freeze(variable, namespace):
|
||||
if variable.auto_freeze:
|
||||
if namespace != Config['variable_namespace']:
|
||||
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
|
||||
msg = _(f'auto_freeze is not allowed in extra "{namespace}" in {xmlfiles}')
|
||||
raise DictConsistencyError(msg, 49)
|
||||
raise DictConsistencyError(_(f'auto_freeze is not allowed in extra "{namespace}" in {xmlfiles}'), 49)
|
||||
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.source = FREEZE_AUTOFREEZE_VARIABLE
|
||||
new_param = self.objectspace.param(variable.xmlfiles)
|
||||
|
@ -94,176 +66,82 @@ class ConstrainteAnnotator:
|
|||
self.objectspace.space.constraints.condition = []
|
||||
self.objectspace.space.constraints.condition.append(new_condition)
|
||||
for variables in self.objectspace.space.variables.values():
|
||||
if not hasattr(variables, 'family'):
|
||||
continue
|
||||
for family in variables.family.values():
|
||||
if not hasattr(family, 'variable'):
|
||||
continue
|
||||
for variable in family.variable.values():
|
||||
if isinstance(variable, self.objectspace.leadership):
|
||||
for follower in variable.variable:
|
||||
_convert_auto_freeze(follower,
|
||||
variables.namespace,
|
||||
)
|
||||
else:
|
||||
_convert_auto_freeze(variable,
|
||||
variables.namespace,
|
||||
)
|
||||
if hasattr(variables, 'family'):
|
||||
namespace = variables.name
|
||||
for family in variables.family.values():
|
||||
if hasattr(family, 'variable'):
|
||||
for variable in family.variable.values():
|
||||
if isinstance(variable, self.objectspace.leadership):
|
||||
for follower in variable.variable:
|
||||
_convert_auto_freeze(follower, namespace)
|
||||
else:
|
||||
_convert_auto_freeze(variable, namespace)
|
||||
|
||||
def check_check(self):
|
||||
"""valid and manage <check>
|
||||
"""
|
||||
remove_indexes = []
|
||||
for check_idx, check in enumerate(self.objectspace.space.constraints.check):
|
||||
if not check.name in self.functions:
|
||||
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
|
||||
msg = _(f'cannot find check function "{check.name}" in {xmlfiles}')
|
||||
raise DictConsistencyError(msg, 1)
|
||||
if not hasattr(check, 'param'):
|
||||
continue
|
||||
param_option_indexes = []
|
||||
for idx, param in enumerate(check.param):
|
||||
if param.type == 'variable':
|
||||
if not self.objectspace.paths.path_is_defined(param.text):
|
||||
if not param.optional:
|
||||
raise DictConsistencyError(_(f'cannot find check function "{check.name}" in {xmlfiles}'), 1)
|
||||
if hasattr(check, 'param'):
|
||||
param_option_indexes = []
|
||||
for idx, param in enumerate(check.param):
|
||||
if param.type == 'variable' and not self.objectspace.paths.path_is_defined(param.text):
|
||||
if param.optional is True:
|
||||
param_option_indexes.append(idx)
|
||||
else:
|
||||
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
|
||||
msg = _(f'cannot find check param "{param.text}" in {xmlfiles}')
|
||||
raise DictConsistencyError(msg, 2)
|
||||
param_option_indexes.append(idx)
|
||||
else:
|
||||
# let's replace params by the path
|
||||
param.text = self.objectspace.paths.get_variable_path(param.text,
|
||||
check.namespace,
|
||||
)
|
||||
param_option_indexes.sort(reverse=True)
|
||||
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
|
||||
raise DictConsistencyError(_(f'cannot find check param "{param.text}" in {xmlfiles}'), 2)
|
||||
if param.type != 'variable':
|
||||
param.notraisepropertyerror = None
|
||||
param_option_indexes = list(set(param_option_indexes))
|
||||
param_option_indexes.sort(reverse=True)
|
||||
for idx in param_option_indexes:
|
||||
check.param.pop(idx)
|
||||
if check.param == []:
|
||||
remove_indexes.append(check_idx)
|
||||
remove_indexes.sort(reverse=True)
|
||||
for idx in remove_indexes:
|
||||
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):
|
||||
"""verify valid_enum
|
||||
"""
|
||||
remove_indexes = []
|
||||
for idx, check in enumerate(self.objectspace.space.constraints.check):
|
||||
if check.name == 'valid_enum':
|
||||
if check.target in self.valid_enums:
|
||||
check_xmlfiles = self.valid_enums[check.target]['xmlfiles']
|
||||
old_xmlfiles = self.objectspace.display_xmlfiles(check_xmlfiles)
|
||||
old_xmlfiles = self.objectspace.display_xmlfiles(self.valid_enums[check.target]['xmlfiles'])
|
||||
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
|
||||
msg = _(f'valid_enum define in {xmlfiles} but already set in {old_xmlfiles} '
|
||||
f'for "{check.target}", did you forget remove_check?')
|
||||
raise DictConsistencyError(msg, 3)
|
||||
raise DictConsistencyError(_(f'valid_enum define in {xmlfiles} but already set in {old_xmlfiles} for "{check.target}", did you forget remove_check?'), 3)
|
||||
if not hasattr(check, 'param'):
|
||||
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
|
||||
msg = _(f'param is mandatory for a valid_enum of variable "{check.target}" '
|
||||
f'in {xmlfiles}')
|
||||
raise DictConsistencyError(msg, 4)
|
||||
raise DictConsistencyError(_(f'param is mandatory for a valid_enum of variable "{check.target}" in {xmlfiles}'), 4)
|
||||
variable = self.objectspace.paths.get_variable_obj(check.target)
|
||||
variable_type = variable.type
|
||||
values = self._set_valid_enum(variable,
|
||||
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]
|
||||
self._set_valid_enum(variable,
|
||||
check,
|
||||
)
|
||||
remove_indexes.append(idx)
|
||||
remove_indexes.sort(reverse=True)
|
||||
for idx in remove_indexes:
|
||||
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):
|
||||
"""convert level to "warnings_only"
|
||||
"""
|
||||
#convert level to "warnings_only"
|
||||
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
|
||||
|
||||
def _get_family_variables_from_target(self,
|
||||
|
@ -280,50 +158,40 @@ class ConstrainteAnnotator:
|
|||
variable = self.objectspace.paths.get_family_obj(target.name)
|
||||
return variable, list(variable.variable.values())
|
||||
|
||||
def convert_condition_target(self):
|
||||
"""verify and manage target in condition
|
||||
"""
|
||||
def check_params_target(self):
|
||||
for condition in self.objectspace.space.constraints.condition:
|
||||
if not hasattr(condition, 'target'):
|
||||
xmlfiles = self.objectspace.display_xmlfiles(condition.xmlfiles)
|
||||
msg = _(f'target is mandatory in a condition for source "{condition.source}" '
|
||||
f'in {xmlfiles}')
|
||||
raise DictConsistencyError(msg, 9)
|
||||
raise DictConsistencyError(_(f'target is mandatory in a condition for source "{condition.source}" in {xmlfiles}'), 9)
|
||||
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 condition.source == target.name:
|
||||
msg = f'target name and source name must be different: {condition.source}'
|
||||
raise DictConsistencyError(_(msg), 11)
|
||||
target_names = '.'.join([normalize_family(name) \
|
||||
for name in target.name.split('.')])
|
||||
raise DictConsistencyError(_('target name and source name must be different: {}').format(condition.source), 11)
|
||||
try:
|
||||
target.name = self.objectspace.paths.get_variable_path(target_names,
|
||||
condition.namespace,
|
||||
)
|
||||
target_names = [normalize_family(name) for name in target.name.split('.')]
|
||||
target.name = self.objectspace.paths.get_variable_path('.'.join(target_names), namespace)
|
||||
except DictConsistencyError as err:
|
||||
# for optional variable
|
||||
if not target.optional or err.errno != 42:
|
||||
raise err
|
||||
elif target.type == 'family':
|
||||
target_names = '.'.join([normalize_family(name) \
|
||||
for name in target.name.split('.')])
|
||||
try:
|
||||
target.name = self.objectspace.paths.get_family_path(target_names,
|
||||
condition.namespace,
|
||||
)
|
||||
target_names = [normalize_family(name) for name in target.name.split('.')]
|
||||
target.name = self.objectspace.paths.get_family_path('.'.join(target_names), namespace)
|
||||
except KeyError:
|
||||
raise DictConsistencyError(_(f'cannot found family {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)
|
||||
raise DictConsistencyError(_('cannot found family {}').format(target.name), 12)
|
||||
|
||||
def convert_xxxlist_to_variable(self):
|
||||
"""transform *list to variable or family
|
||||
"""
|
||||
for condition in self.objectspace.space.constraints.condition:
|
||||
def convert_xxxlist_to_variable(self): # pylint: disable=C0111
|
||||
# transform *list to variable or family
|
||||
for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition):
|
||||
new_targets = []
|
||||
remove_targets = []
|
||||
for target_idx, target in enumerate(condition.target):
|
||||
|
@ -347,56 +215,55 @@ class ConstrainteAnnotator:
|
|||
condition.target.extend(new_targets)
|
||||
|
||||
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 = []
|
||||
for idx, condition in enumerate(self.objectspace.space.constraints.condition):
|
||||
# fallback
|
||||
if condition.fallback is True and \
|
||||
not self.objectspace.paths.path_is_defined(condition.source):
|
||||
if condition.fallback is True and not self.objectspace.paths.path_is_defined(condition.source):
|
||||
apply_action = False
|
||||
if condition.name in ['disabled_if_in', 'mandatory_if_in', 'hidden_if_in']:
|
||||
apply_action = not condition.force_condition_on_fallback
|
||||
else:
|
||||
apply_action = condition.force_inverse_condition_on_fallback
|
||||
remove_conditions.append(idx)
|
||||
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
|
||||
|
||||
remove_targets = []
|
||||
# optional
|
||||
for index, target in enumerate(condition.target):
|
||||
if target.optional is True and \
|
||||
not self.objectspace.paths.path_is_defined(target.name):
|
||||
remove_targets.append(index)
|
||||
for idx, target in enumerate(condition.target):
|
||||
if target.optional is True and not self.objectspace.paths.path_is_defined(target.name):
|
||||
remove_targets.append(idx)
|
||||
remove_targets = list(set(remove_targets))
|
||||
remove_targets.sort(reverse=True)
|
||||
for index in remove_targets:
|
||||
condition.target.pop(index)
|
||||
for idx in remove_targets:
|
||||
condition.target.pop(idx)
|
||||
remove_conditions = list(set(remove_conditions))
|
||||
remove_conditions.sort(reverse=True)
|
||||
for idx in remove_conditions:
|
||||
self.objectspace.space.constraints.condition.pop(idx)
|
||||
|
||||
def force_actions_to_variable(self,
|
||||
condition: 'self.objectspace.condition',
|
||||
) -> None:
|
||||
"""force property to a variable
|
||||
for example disabled_if_not_in => variable.disabled = True
|
||||
"""
|
||||
actions = get_actions_from_condition(condition.name)
|
||||
for target in condition.target:
|
||||
leader_or_var, variables = self._get_family_variables_from_target(target)
|
||||
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 _get_condition_actions(self, condition_name):
|
||||
if condition_name.startswith('disabled_if_'):
|
||||
return ['disabled']
|
||||
elif condition_name.startswith('hidden_if_'):
|
||||
return ['hidden', 'frozen', 'force_default_on_freeze']
|
||||
elif condition_name.startswith('mandatory_if_'):
|
||||
return ['mandatory']
|
||||
elif condition_name == 'auto_hidden_if_not_in':
|
||||
return ['auto_frozen']
|
||||
|
||||
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 = []
|
||||
for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition):
|
||||
namespace = condition.namespace
|
||||
|
@ -407,200 +274,257 @@ class ConstrainteAnnotator:
|
|||
)
|
||||
if suffix:
|
||||
xmlfiles = self.objectspace.display_xmlfiles(condition.xmlfiles)
|
||||
msg = _(f'the source "{condition.source}" in condition cannot be a dynamic '
|
||||
f'variable in {xmlfiles}')
|
||||
raise DictConsistencyError(msg, 20)
|
||||
raise DictConsistencyError(_(f'the source "{condition.source}" in condition cannot be a dynamic variable in {xmlfiles}'), 20)
|
||||
src_variable = self.objectspace.paths.get_variable_obj(condition.source)
|
||||
valid_enum = None
|
||||
# FIXME only string?
|
||||
if condition.source in self.valid_enums and \
|
||||
self.valid_enums[condition.source]['type'] == 'string':
|
||||
if condition.source in self.valid_enums and self.valid_enums[condition.source]['type'] == 'string':
|
||||
valid_enum = self.valid_enums[condition.source]['values']
|
||||
remove_param = [param_idx for param_idx, param in enumerate(condition.param) \
|
||||
if param.text not in valid_enum]
|
||||
if valid_enum is not None:
|
||||
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)
|
||||
for idx in remove_param:
|
||||
del condition.param[idx]
|
||||
if not condition.param and condition.name.endswith('_if_not_in'):
|
||||
self.force_actions_to_variable(condition)
|
||||
if condition.param == []:
|
||||
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 = list(set(remove_conditions))
|
||||
remove_conditions.sort(reverse=True)
|
||||
for idx in remove_conditions:
|
||||
self.objectspace.space.constraints.condition.pop(idx)
|
||||
|
||||
def remove_condition_with_empty_target(self):
|
||||
"""remove condition with empty target
|
||||
"""
|
||||
# optional target are remove, condition could be empty
|
||||
remove_conditions = [condition_idx for condition_idx, condition in \
|
||||
enumerate(self.objectspace.space.constraints.condition) \
|
||||
if not condition.target]
|
||||
remove_conditions = [condition_idx for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition) if not condition.target]
|
||||
remove_conditions.sort(reverse=True)
|
||||
for idx in remove_conditions:
|
||||
self.objectspace.space.constraints.condition.pop(idx)
|
||||
|
||||
def convert_condition(self):
|
||||
"""valid and manage <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:
|
||||
text = getattr(param, 'text', None)
|
||||
for target in condition.target:
|
||||
leader_or_variable, variables = self._get_family_variables_from_target(target)
|
||||
# if option is already disable, do not apply disable_if_in
|
||||
# check only the first action (example of multiple actions:
|
||||
# 'hidden', 'frozen', 'force_default_on_freeze')
|
||||
# check only the first action (example of multiple actions: 'hidden', 'frozen', 'force_default_on_freeze')
|
||||
main_action = actions[0]
|
||||
if getattr(leader_or_variable, main_action, False) is True:
|
||||
continue
|
||||
self.build_property(leader_or_variable,
|
||||
text,
|
||||
condition,
|
||||
main_action,
|
||||
)
|
||||
if isinstance(leader_or_variable, self.objectspace.variable) and \
|
||||
(leader_or_variable.auto_save or leader_or_variable.auto_freeze) and \
|
||||
'force_default_on_freeze' in actions:
|
||||
continue
|
||||
for action in actions[1:]:
|
||||
# other actions are set to the variable or children of family
|
||||
for variable in variables:
|
||||
self.build_property(variable,
|
||||
text,
|
||||
condition,
|
||||
action,
|
||||
)
|
||||
xmlfiles = self.objectspace.display_xmlfiles(leader_or_variable.xmlfiles)
|
||||
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)
|
||||
for idx, action in enumerate(actions):
|
||||
prop = self.objectspace.property_(leader_or_variable.xmlfiles)
|
||||
prop.type = 'calculation'
|
||||
prop.inverse = inverse
|
||||
prop.source = condition.source
|
||||
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,
|
||||
obj,
|
||||
text: Any,
|
||||
condition: 'self.objectspace.condition',
|
||||
action: str,
|
||||
) -> 'self.objectspace.property_':
|
||||
"""build property_ for a condition
|
||||
"""
|
||||
prop = self.objectspace.property_(obj.xmlfiles)
|
||||
prop.type = 'calculation'
|
||||
prop.inverse = condition.name.endswith('_if_not_in')
|
||||
prop.source = condition.source
|
||||
prop.expected = text
|
||||
prop.name = action
|
||||
if not hasattr(obj, 'property'):
|
||||
obj.property = []
|
||||
obj.property.append(prop)
|
||||
def _set_valid_enum(self,
|
||||
variable,
|
||||
check,
|
||||
):
|
||||
type_ = variable.type
|
||||
target = check.target
|
||||
# value for choice's variable is mandatory
|
||||
variable.mandatory = True
|
||||
# build choice
|
||||
variable.choice = []
|
||||
variable.type = 'choice'
|
||||
|
||||
def convert_check(self) -> None:
|
||||
"""valid and manage <check>
|
||||
"""
|
||||
has_variable = False
|
||||
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:
|
||||
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'):
|
||||
msg = _(f'{check.name} must have, at least, 1 param')
|
||||
raise DictConsistencyError(msg, 17)
|
||||
raise DictConsistencyError(_('{} must have, at least, 1 param').format(name), 17)
|
||||
for param in check.param:
|
||||
if param.type != 'number':
|
||||
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
|
||||
msg = _(f'param in "valid_entier" must be an "integer", not "{param.type}"'
|
||||
f' in {xmlfiles}')
|
||||
raise DictConsistencyError(msg, 18)
|
||||
raise DictConsistencyError(_(f'param in "valid_entier" must be an "integer", not "{param.type}" in {xmlfiles}'), 18)
|
||||
if param.name == 'mini':
|
||||
variable.min_number = int(param.text)
|
||||
elif param.name == 'maxi':
|
||||
variable.max_number = int(param.text)
|
||||
else:
|
||||
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
|
||||
msg = _(f'unknown parameter "{param.name}" in check "valid_entier" '
|
||||
f'for variable "{check.target}" in {xmlfiles}')
|
||||
raise DictConsistencyError(msg, 19)
|
||||
raise DictConsistencyError(_(f'unknown parameter "{param.name}" in check "valid_entier" for variable "{check.target}" in {xmlfiles}'), 19)
|
||||
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'):
|
||||
variable.check = []
|
||||
variable.check.append(check)
|
||||
variable.check.append(check_)
|
||||
del self.objectspace.space.constraints.check
|
||||
|
||||
def convert_fill(self) -> None:
|
||||
"""valid and manage <fill>
|
||||
"""
|
||||
def convert_fill(self): # pylint: disable=C0111,R0912
|
||||
# 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 = []
|
||||
for fill in self.objectspace.space.constraints.fill:
|
||||
for idx in indexes:
|
||||
fill = fills[idx]
|
||||
# test if it's redefined calculation
|
||||
if fill.target in targets:
|
||||
xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
|
||||
msg = _(f'A fill already exists for the target of "{fill.target}" created '
|
||||
f'in {xmlfiles}')
|
||||
raise DictConsistencyError(msg, 24)
|
||||
raise DictConsistencyError(_(f'A fill already exists for the target of "{fill.target}" created in {xmlfiles}'), 24)
|
||||
targets.append(fill.target)
|
||||
|
||||
# test if the function exists
|
||||
#
|
||||
if fill.name not in self.functions:
|
||||
xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
|
||||
msg = _(f'cannot find fill function "{fill.name}" in {xmlfiles}')
|
||||
raise DictConsistencyError(msg, 25)
|
||||
raise DictConsistencyError(_(f'cannot find fill function "{fill.name}" in {xmlfiles}'), 25)
|
||||
|
||||
namespace = fill.namespace
|
||||
# let's replace the target by the path
|
||||
fill.target, suffix = self.objectspace.paths.get_variable_path(fill.target,
|
||||
fill.namespace,
|
||||
namespace,
|
||||
with_suffix=True,
|
||||
)
|
||||
if suffix is not None:
|
||||
xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
|
||||
msg = _(f'Cannot add fill function to "{fill.target}" only '
|
||||
f'for the suffix "{suffix}" in {xmlfiles}')
|
||||
raise DictConsistencyError(msg, 26)
|
||||
|
||||
# get the target variable
|
||||
raise DictConsistencyError(_(f'Cannot add fill function to "{fill.target}" only for the suffix "{suffix}" in {xmlfiles}'), 26)
|
||||
variable = self.objectspace.paths.get_variable_obj(fill.target)
|
||||
|
||||
# create an object value
|
||||
value = self.objectspace.value(fill.xmlfiles)
|
||||
value = self.objectspace.value(variable.xmlfiles)
|
||||
value.type = 'calculation'
|
||||
value.name = fill.name
|
||||
variable.value = [value]
|
||||
|
||||
# manage params
|
||||
if not hasattr(fill, 'param'):
|
||||
continue
|
||||
self.convert_fill_param(fill)
|
||||
if fill.param:
|
||||
if hasattr(fill, 'param'):
|
||||
param_to_delete = []
|
||||
for fill_idx, param in enumerate(fill.param):
|
||||
if param.type not in ['suffix', 'string'] and not hasattr(param, 'text'):
|
||||
xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
|
||||
raise DictConsistencyError(_(f"All '{param.type}' variables must have a value in order to calculate {fill.target} in {xmlfiles}"), 27)
|
||||
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
|
||||
variable.value = [value]
|
||||
del self.objectspace.space.constraints.fill
|
||||
|
||||
def convert_fill_param(self,
|
||||
fill: "self.objectspace.fill",
|
||||
) -> None:
|
||||
""" valid and convert fill's param
|
||||
"""
|
||||
param_to_delete = []
|
||||
for param_idx, param in enumerate(fill.param):
|
||||
if param.type == 'string' and not hasattr(param, 'text'):
|
||||
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)
|
||||
def remove_constraints(self):
|
||||
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): # pragma: no cover
|
||||
raise Exception('constraints again?')
|
||||
del self.objectspace.space.constraints
|
||||
|
|
|
@ -6,7 +6,7 @@ from ..error import DictConsistencyError
|
|||
modes_level = ('basic', 'normal', 'expert')
|
||||
|
||||
|
||||
class Mode:
|
||||
class Mode(object):
|
||||
def __init__(self, name, level):
|
||||
self.name = name
|
||||
self.level = level
|
||||
|
@ -40,8 +40,8 @@ class FamilyAnnotator:
|
|||
if hasattr(family, 'family'):
|
||||
space = family.family
|
||||
removed_families = []
|
||||
for family_name, sfamily in space.items():
|
||||
if not hasattr(sfamily, 'variable') or len(sfamily.variable) == 0:
|
||||
for family_name, family in space.items():
|
||||
if not hasattr(family, 'variable') or len(family.variable) == 0:
|
||||
removed_families.append(family_name)
|
||||
for family_name in removed_families:
|
||||
del space[family_name]
|
||||
|
@ -51,9 +51,9 @@ class FamilyAnnotator:
|
|||
return
|
||||
for family in self.objectspace.space.variables.values():
|
||||
if hasattr(family, 'family'):
|
||||
for vfamily in family.family.values():
|
||||
for family in family.family.values():
|
||||
mode = modes_level[-1]
|
||||
for variable in vfamily.variable.values():
|
||||
for variable in family.variable.values():
|
||||
if isinstance(variable, self.objectspace.leadership):
|
||||
variable_mode = variable.variable[0].mode
|
||||
variable.variable[0].mode = None
|
||||
|
@ -62,28 +62,24 @@ class FamilyAnnotator:
|
|||
variable_mode = variable.mode
|
||||
if variable_mode is not None and modes[mode] > modes[variable_mode]:
|
||||
mode = variable_mode
|
||||
vfamily.mode = mode
|
||||
family.mode = mode
|
||||
|
||||
def dynamic_families(self): # pylint: disable=C0111
|
||||
if not hasattr(self.objectspace.space, 'variables'):
|
||||
return
|
||||
for family in self.objectspace.space.variables.values():
|
||||
if hasattr(family, 'family'):
|
||||
for vfamily in family.family.values():
|
||||
if 'dynamic' in vars(vfamily):
|
||||
namespace = self.objectspace.paths.get_variable_namespace(vfamily.dynamic)
|
||||
varpath = self.objectspace.paths.get_variable_path(vfamily.dynamic, namespace)
|
||||
for family in family.family.values():
|
||||
if 'dynamic' in vars(family):
|
||||
namespace = self.objectspace.paths.get_variable_namespace(family.dynamic)
|
||||
varpath = self.objectspace.paths.get_variable_path(family.dynamic, namespace)
|
||||
obj = self.objectspace.paths.get_variable_obj(varpath)
|
||||
if not obj.multi:
|
||||
xmlfiles = self.objectspace.display_xmlfiles(vfamily.xmlfiles)
|
||||
raise DictConsistencyError(_(f'dynamic family "{vfamily.name}" must be linked to multi variable in {xmlfiles}'), 16)
|
||||
vfamily.dynamic = varpath
|
||||
xmlfiles = self.objectspace.display_xmlfiles(family.xmlfiles)
|
||||
raise DictConsistencyError(_(f'dynamic family "{family.name}" must be linked to multi variable in {xmlfiles}'), 16)
|
||||
family.dynamic = varpath
|
||||
|
||||
def annotate_variable(self,
|
||||
variable,
|
||||
family_mode: str,
|
||||
is_follower=False,
|
||||
) -> None:
|
||||
def annotate_variable(self, variable, family_mode, path, is_follower=False):
|
||||
# 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':
|
||||
|
@ -96,28 +92,32 @@ class FamilyAnnotator:
|
|||
for value in variable.value:
|
||||
if value.type == 'calculation':
|
||||
has_value = False
|
||||
has_variable = False
|
||||
if hasattr(value, 'param'):
|
||||
for param in value.param:
|
||||
if param.type == 'variable':
|
||||
has_variable = True
|
||||
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 but without any calculation
|
||||
variable.mandatory = True
|
||||
if variable.mandatory is True and (not hasattr(variable, 'value') or is_follower):
|
||||
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
|
||||
if variable.hidden is True:
|
||||
variable.frozen = True
|
||||
if not variable.auto_save is True and \
|
||||
not variable.auto_freeze and \
|
||||
'force_default_on_freeze' not in vars(variable):
|
||||
if not variable.auto_save is True and 'force_default_on_freeze' not in vars(variable):
|
||||
variable.force_default_on_freeze = True
|
||||
|
||||
def change_variable_mode(self): # pylint: disable=C0111
|
||||
if not hasattr(self.objectspace.space, 'variables'):
|
||||
return
|
||||
for variables in self.objectspace.space.variables.values():
|
||||
namespace = variables.name
|
||||
if hasattr(variables, 'family'):
|
||||
for family in variables.family.values():
|
||||
family_mode = family.mode
|
||||
|
@ -125,6 +125,7 @@ class FamilyAnnotator:
|
|||
for variable in family.variable.values():
|
||||
|
||||
if isinstance(variable, self.objectspace.leadership):
|
||||
mode = modes_level[-1]
|
||||
for idx, follower in enumerate(variable.variable):
|
||||
if follower.auto_save is True:
|
||||
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
|
||||
|
@ -133,10 +134,8 @@ class FamilyAnnotator:
|
|||
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
|
||||
raise DictConsistencyError(_(f'leader/followers "{follower.name}" could not be auto_freeze in {xmlfiles}'), 30)
|
||||
is_follower = idx != 0
|
||||
self.annotate_variable(follower,
|
||||
family_mode,
|
||||
is_follower,
|
||||
)
|
||||
path = '{}.{}.{}'.format(family.path, variable.name, follower.name)
|
||||
self.annotate_variable(follower, family_mode, path, is_follower)
|
||||
# leader's mode is minimum level
|
||||
if modes[variable.variable[0].mode] > modes[follower.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'
|
||||
if variable.auto_freeze is True and variable.mode != modes_level[-1]:
|
||||
variable.mode = modes_level[0]
|
||||
self.annotate_variable(variable,
|
||||
family_mode,
|
||||
)
|
||||
path = '{}.{}'.format(family.path, variable.name)
|
||||
self.annotate_variable(variable, family_mode, path)
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
"""Annotate group
|
||||
"""
|
||||
from typing import List
|
||||
|
||||
from ..i18n import _
|
||||
|
@ -7,20 +5,15 @@ from ..error import DictConsistencyError
|
|||
|
||||
|
||||
class GroupAnnotator:
|
||||
"""Annotate group
|
||||
"""
|
||||
def __init__(self,
|
||||
objectspace,
|
||||
):
|
||||
self.objectspace = objectspace
|
||||
if not hasattr(self.objectspace.space, 'constraints') or \
|
||||
not hasattr(self.objectspace.space.constraints, 'group'):
|
||||
if not hasattr(self.objectspace.space, 'constraints') or not hasattr(self.objectspace.space.constraints, 'group'):
|
||||
return
|
||||
self.convert_groups()
|
||||
|
||||
def convert_groups(self): # pylint: disable=C0111
|
||||
"""convert groups
|
||||
"""
|
||||
for group in self.objectspace.space.constraints.group:
|
||||
leader_fullname = group.leader
|
||||
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])
|
||||
follower_names = list(group.follower.keys())
|
||||
has_a_leader = False
|
||||
leader_family = leader_fullname.rsplit('.', 1)[0]
|
||||
ori_leader_family = self.objectspace.paths.get_family_obj(leader_family)
|
||||
ori_leader_family = self.objectspace.paths.get_family_obj(leader_fullname.rsplit('.', 1)[0])
|
||||
for variable in list(ori_leader_family.variable.values()):
|
||||
if has_a_leader:
|
||||
# it's a follower
|
||||
self.manage_follower(leader_family_name,
|
||||
self.manage_follower(namespace,
|
||||
leader_family_name,
|
||||
variable,
|
||||
leadership_name,
|
||||
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)
|
||||
if follower_names == []:
|
||||
# no more follower
|
||||
|
@ -65,6 +56,7 @@ class GroupAnnotator:
|
|||
leader_family_name,
|
||||
leadership_name,
|
||||
leader_name,
|
||||
namespace,
|
||||
variable,
|
||||
group,
|
||||
leader_fullname,
|
||||
|
@ -73,9 +65,7 @@ class GroupAnnotator:
|
|||
else:
|
||||
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
|
||||
joined = '", "'.join(follower_names)
|
||||
msg = _(f'when parsing leadership, we espect to find those followers "{joined}" '
|
||||
f'in {xmlfiles}')
|
||||
raise DictConsistencyError(msg, 31)
|
||||
raise DictConsistencyError(_(f'when parsing leadership, we espect to find those followers "{joined}" in {xmlfiles}'), 31)
|
||||
del self.objectspace.space.constraints.group
|
||||
|
||||
def manage_leader(self,
|
||||
|
@ -83,16 +73,15 @@ class GroupAnnotator:
|
|||
leader_family_name: str,
|
||||
leadership_name: str,
|
||||
leader_name: str,
|
||||
namespace: str,
|
||||
variable: 'Variable',
|
||||
group: 'Group',
|
||||
leader_fullname: str,
|
||||
) -> None:
|
||||
"""manage leader's variable
|
||||
"""
|
||||
# manage leader's variable
|
||||
if variable.multi is not True:
|
||||
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
|
||||
msg = _(f'the variable "{variable.name}" in a group must be multi in {xmlfiles}')
|
||||
raise DictConsistencyError(msg, 32)
|
||||
raise DictConsistencyError(_(f'the variable "{variable.name}" in a group must be multi in {xmlfiles}'), 32)
|
||||
leader_space.variable = []
|
||||
leader_space.name = leadership_name
|
||||
leader_space.hidden = variable.hidden
|
||||
|
@ -109,7 +98,6 @@ class GroupAnnotator:
|
|||
leader_space.doc = variable.description
|
||||
else:
|
||||
leader_space.doc = variable.name
|
||||
namespace = variable.namespace
|
||||
leadership_path = namespace + '.' + leader_family_name + '.' + leadership_name
|
||||
self.objectspace.paths.add_family(namespace,
|
||||
leadership_path,
|
||||
|
@ -127,21 +115,25 @@ class GroupAnnotator:
|
|||
return leader_is_hidden
|
||||
|
||||
def manage_follower(self,
|
||||
namespace: str,
|
||||
leader_family_name: str,
|
||||
variable: 'Variable',
|
||||
leader_name: str,
|
||||
follower_names: List[str],
|
||||
leader_space: 'Leadership',
|
||||
leader_is_hidden: bool,
|
||||
) -> None:
|
||||
"""manage follower
|
||||
"""
|
||||
follower_name = follower_names.pop(0)
|
||||
if variable.name != follower_name:
|
||||
if variable.name != follower_names[0]:
|
||||
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
|
||||
msg = _('when parsing leadership, we espect to find the follower '
|
||||
f'"{follower_name}" but we found "{variable.name}" in {xmlfiles}')
|
||||
raise DictConsistencyError(msg, 33)
|
||||
self.objectspace.paths.set_leader(variable.namespace,
|
||||
raise DictConsistencyError(_(f'when parsing leadership, we espect to find the follower "{follower_names[0]}" but we found "{variable.name}" in {xmlfiles}'), 33)
|
||||
follower_names.remove(variable.name)
|
||||
if leader_is_hidden:
|
||||
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,
|
||||
variable.name,
|
||||
leader_name,
|
||||
)
|
||||
|
||||
|
|
|
@ -1,35 +1,24 @@
|
|||
"""Annotate properties
|
||||
"""
|
||||
from ..i18n import _
|
||||
from ..error import DictConsistencyError
|
||||
|
||||
|
||||
PROPERTIES = ('hidden', 'frozen', 'auto_freeze', 'auto_save', 'force_default_on_freeze',
|
||||
'force_store_value', 'disabled', 'mandatory')
|
||||
CONVERT_PROPERTIES = {'auto_save': ['force_store_value'],
|
||||
'auto_freeze': ['force_store_value', 'auto_freeze'],
|
||||
}
|
||||
CONVERT_PROPERTIES = {'auto_save': ['force_store_value'], 'auto_freeze': ['force_store_value', 'auto_freeze']}
|
||||
|
||||
|
||||
class PropertyAnnotator:
|
||||
"""Annotate properties
|
||||
"""
|
||||
def __init__(self, objectspace):
|
||||
self.objectspace = objectspace
|
||||
if hasattr(self.objectspace.space, 'services'):
|
||||
self.convert_services()
|
||||
if hasattr(self.objectspace.space, 'variables'):
|
||||
self.convert_variables()
|
||||
self.convert_annotator()
|
||||
|
||||
def convert_property(self,
|
||||
variable,
|
||||
) -> None:
|
||||
"""convert properties
|
||||
"""
|
||||
):
|
||||
properties = []
|
||||
for prop in PROPERTIES:
|
||||
if hasattr(variable, prop):
|
||||
if getattr(variable, prop) is True:
|
||||
if getattr(variable, prop) == True:
|
||||
for subprop in CONVERT_PROPERTIES.get(prop, [prop]):
|
||||
properties.append(subprop)
|
||||
setattr(variable, prop, None)
|
||||
|
@ -38,46 +27,35 @@ class PropertyAnnotator:
|
|||
variable.mode = None
|
||||
if 'force_store_value' in properties and 'force_default_on_freeze' in properties:
|
||||
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
|
||||
msg = _('cannot have auto_freeze or auto_store with the hidden '
|
||||
f'variable "{variable.name}" in {xmlfiles}')
|
||||
raise DictConsistencyError(msg, 50)
|
||||
raise DictConsistencyError(_(f'cannot have auto_freeze or auto_store with the hidden variable "{variable.name}" in {xmlfiles}'), 50)
|
||||
if properties:
|
||||
variable.properties = frozenset(properties)
|
||||
|
||||
def convert_services(self) -> None:
|
||||
"""convert services
|
||||
"""
|
||||
self.convert_property(self.objectspace.space.services)
|
||||
for services in self.objectspace.space.services.service.values():
|
||||
self.convert_property(services)
|
||||
for service in vars(services).values():
|
||||
if not isinstance(service, self.objectspace.family):
|
||||
continue
|
||||
self.convert_property(service)
|
||||
if not hasattr(service, 'family'):
|
||||
continue
|
||||
self.convert_property(service)
|
||||
for family in service.family:
|
||||
self.convert_property(family)
|
||||
if not hasattr(family, 'variable'):
|
||||
continue
|
||||
for variable in family.variable:
|
||||
self.convert_property(variable)
|
||||
|
||||
def convert_variables(self) -> None:
|
||||
"""convert variables
|
||||
"""
|
||||
for variables in self.objectspace.space.variables.values():
|
||||
if not hasattr(variables, 'family'):
|
||||
continue
|
||||
for family in variables.family.values():
|
||||
self.convert_property(family)
|
||||
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)
|
||||
def convert_annotator(self): # pylint: disable=C0111
|
||||
if hasattr(self.objectspace.space, 'services'):
|
||||
self.convert_property(self.objectspace.space.services)
|
||||
for services in self.objectspace.space.services.service.values():
|
||||
self.convert_property(services)
|
||||
for service in vars(services).values():
|
||||
if isinstance(service, self.objectspace.family):
|
||||
self.convert_property(service)
|
||||
if hasattr(service, 'family'):
|
||||
self.convert_property(service)
|
||||
for family in service.family:
|
||||
self.convert_property(family)
|
||||
if hasattr(family, 'variable'):
|
||||
for variable in family.variable:
|
||||
self.convert_property(variable)
|
||||
if hasattr(self.objectspace.space, 'variables'):
|
||||
for variables in self.objectspace.space.variables.values():
|
||||
if hasattr(variables, 'family'):
|
||||
for family in variables.family.values():
|
||||
self.convert_property(family)
|
||||
if hasattr(family, 'variable'):
|
||||
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)
|
||||
|
|
|
@ -45,7 +45,7 @@ class ServiceAnnotator:
|
|||
self.objectspace.space.services.name = 'services'
|
||||
self.objectspace.space.services.doc = 'services'
|
||||
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]
|
||||
new_service = self.objectspace.service(service.xmlfiles)
|
||||
for elttype, values in vars(service).items():
|
||||
|
|
|
@ -141,7 +141,7 @@ class VariableAnnotator:
|
|||
if not hasattr(family, 'separators'):
|
||||
continue
|
||||
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)
|
||||
if hasattr(option, 'separator'):
|
||||
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)
|
||||
option.separator = separator.text
|
||||
del family.separators
|
||||
|
||||
|
|
|
@ -6,15 +6,17 @@ fichier de configuration pour rougail
|
|||
from os.path import join, abspath, dirname
|
||||
|
||||
|
||||
ROUGAILROOT = '/var/rougail'
|
||||
DTDDIR = join(dirname(abspath(__file__)), 'data')
|
||||
rougailroot = '/var/rougail'
|
||||
dtddir = join(dirname(abspath(__file__)), 'data')
|
||||
|
||||
|
||||
Config = {'rougailroot': ROUGAILROOT,
|
||||
'patch_dir': join(ROUGAILROOT, 'patches'),
|
||||
'manifests_dir': join(ROUGAILROOT, 'manifests'),
|
||||
'templates_dir': join(ROUGAILROOT, 'templates'),
|
||||
'dtdfilename': join(DTDDIR, 'rougail.dtd'),
|
||||
'dtddir': DTDDIR,
|
||||
Config = {'rougailroot': rougailroot,
|
||||
'patch_dir': join(rougailroot, 'patches'),
|
||||
'manifests_dir': join(rougailroot, 'manifests'),
|
||||
'templates_dir': join(rougailroot, 'templates'),
|
||||
'dtdfilename': join(dtddir, 'rougail.dtd'),
|
||||
'dtddir': dtddir,
|
||||
# chemin du répertoire source des fichiers templates
|
||||
'patch_dir': '/srv/rougail/patch',
|
||||
'variable_namespace': 'rougail',
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@
|
|||
<!ATTLIST check level (error|warning) "error">
|
||||
|
||||
<!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 fallback (True|False) "False">
|
||||
<!ATTLIST condition force_condition_on_fallback (True|False) "False">
|
||||
|
|
|
@ -11,6 +11,7 @@ class TemplateError(ConfigError):
|
|||
class TemplateDisabled(TemplateError):
|
||||
"""Template is disabled.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class OperationError(Exception):
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
|
||||
from typing import List
|
||||
|
||||
from .i18n import _
|
||||
from .xmlreflector import XMLReflector
|
||||
from .utils import normalize_family
|
||||
|
@ -108,6 +111,7 @@ class RougailObjSpace:
|
|||
if name.endswith('_'):
|
||||
name = name[:-1]
|
||||
setattr(self, elt, type(name, (RootRougailObject,), dict()))
|
||||
self.Leadership = self.leadership
|
||||
|
||||
def display_xmlfiles(self,
|
||||
xmlfiles: list,
|
||||
|
@ -161,7 +165,8 @@ class RougailObjSpace:
|
|||
self.remove(child,
|
||||
variableobj,
|
||||
)
|
||||
self.set_path(child,
|
||||
self.set_path(space,
|
||||
child,
|
||||
namespace,
|
||||
document,
|
||||
variableobj,
|
||||
|
@ -195,7 +200,7 @@ class RougailObjSpace:
|
|||
child,
|
||||
namespace,
|
||||
)
|
||||
if Atom in obj.__mro__:
|
||||
elif Atom in obj.__mro__:
|
||||
if child.tag in vars(space):
|
||||
# Atom instance has to be a singleton here
|
||||
# we do not re-create it, we reuse it
|
||||
|
@ -363,6 +368,7 @@ class RougailObjSpace:
|
|||
self.space.constraints.fill.pop(idx)
|
||||
|
||||
def set_path(self,
|
||||
space,
|
||||
child,
|
||||
namespace,
|
||||
document,
|
||||
|
@ -376,7 +382,7 @@ class RougailObjSpace:
|
|||
self.paths.add_variable(namespace,
|
||||
child.attrib['name'],
|
||||
family_name,
|
||||
document.attrib.get('dynamic') is not None,
|
||||
document.attrib.get('dynamic') != None,
|
||||
variableobj,
|
||||
)
|
||||
if child.attrib.get('redefine', 'False') == 'True':
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from .i18n import _
|
||||
from .utils import normalize_family
|
||||
from .error import OperationError, DictConsistencyError
|
||||
from .config import Config
|
||||
|
||||
|
@ -141,7 +142,7 @@ class Path:
|
|||
else:
|
||||
dico = self._get_variable(name)
|
||||
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']]
|
||||
if dico['leader'] is not None:
|
||||
list_path.append(dico['leader'])
|
||||
|
|
|
@ -18,7 +18,7 @@ from Cheetah.NameMapper import NotFound as CheetahNotFound
|
|||
try:
|
||||
from tiramisu3 import Config
|
||||
from tiramisu3.error import PropertiesOptionError # pragma: no cover
|
||||
except ModuleNotFoundError: # pragma: no cover
|
||||
except: # pragma: no cover
|
||||
from tiramisu import Config
|
||||
from tiramisu.error import PropertiesOptionError
|
||||
|
||||
|
@ -89,7 +89,12 @@ class CheetahTemplate(ChtTemplate):
|
|||
return None
|
||||
|
||||
|
||||
class CreoleLeaderIndex:
|
||||
class CreoleValue:
|
||||
def __str__(self):
|
||||
return str(self._value)
|
||||
|
||||
|
||||
class CreoleLeaderIndex(CreoleValue):
|
||||
def __init__(self,
|
||||
value,
|
||||
follower,
|
||||
|
@ -107,9 +112,6 @@ class CreoleLeaderIndex:
|
|||
raise AttributeError()
|
||||
return value
|
||||
|
||||
def __str__(self):
|
||||
return str(self._value)
|
||||
|
||||
def __lt__(self, value):
|
||||
return self._value.__lt__(value)
|
||||
|
||||
|
@ -135,7 +137,7 @@ class CreoleLeaderIndex:
|
|||
return value + self._value
|
||||
|
||||
|
||||
class CreoleLeader:
|
||||
class CreoleLeader(CreoleValue):
|
||||
def __init__(self,
|
||||
value,
|
||||
) -> None:
|
||||
|
@ -185,8 +187,7 @@ class CreoleExtra:
|
|||
self.suboption = suboption
|
||||
|
||||
def __getattr__(self,
|
||||
key: str,
|
||||
) -> Any:
|
||||
key: str) -> Any:
|
||||
return self.suboption[key]
|
||||
|
||||
def __iter__(self):
|
||||
|
@ -211,8 +212,8 @@ class CreoleTemplateEngine:
|
|||
if eosfunc_file is not None:
|
||||
eosfunc = SourceFileLoader('eosfunc', eosfunc_file).load_module()
|
||||
for func in dir(eosfunc):
|
||||
if not func.startswith('_'):
|
||||
eos[func] = getattr(eosfunc, func)
|
||||
if not func.startswith('_'):
|
||||
eos[func] = getattr(eosfunc, func)
|
||||
self.eosfunc = eos
|
||||
self.rougail_variables_dict = {}
|
||||
|
||||
|
@ -237,8 +238,8 @@ class CreoleTemplateEngine:
|
|||
self.rougail_variables_dict[await option.option.name()] = await option.value.get()
|
||||
|
||||
async def load_eole_variables(self,
|
||||
optiondescription,
|
||||
):
|
||||
namespace,
|
||||
optiondescription):
|
||||
families = {}
|
||||
for family in await optiondescription.list('all'):
|
||||
variables = {}
|
||||
|
@ -256,7 +257,9 @@ class CreoleTemplateEngine:
|
|||
)
|
||||
variables[leader_name] = leader
|
||||
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
|
||||
else:
|
||||
variables[await variable.option.name()] = await variable.value.get()
|
||||
|
@ -298,6 +301,7 @@ class CreoleTemplateEngine:
|
|||
source: str,
|
||||
true_destfilename: str,
|
||||
destfilename: str,
|
||||
filevar: Dict,
|
||||
variable: Any,
|
||||
):
|
||||
"""Process a cheetah template
|
||||
|
@ -323,6 +327,7 @@ class CreoleTemplateEngine:
|
|||
|
||||
def instance_file(self,
|
||||
filevar: Dict,
|
||||
service_name: str,
|
||||
tmp_dir: str,
|
||||
dest_dir: str,
|
||||
) -> None:
|
||||
|
@ -350,8 +355,8 @@ class CreoleTemplateEngine:
|
|||
self.process(source,
|
||||
filename,
|
||||
destfilename,
|
||||
var,
|
||||
)
|
||||
filevar,
|
||||
var)
|
||||
else:
|
||||
copy(source, destfilename)
|
||||
|
||||
|
@ -368,11 +373,13 @@ class CreoleTemplateEngine:
|
|||
if namespace == Config['variable_namespace']:
|
||||
await self.load_eole_variables_rougail(option)
|
||||
else:
|
||||
families = await self.load_eole_variables(option)
|
||||
families = await self.load_eole_variables(namespace,
|
||||
option)
|
||||
self.rougail_variables_dict[namespace] = families
|
||||
for template in listdir('.'):
|
||||
self.prepare_template(template, tmp_dir, patch_dir)
|
||||
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'):
|
||||
if await fills.option.name() in ['files', 'overrides']:
|
||||
for fill_obj in await fills.list('all'):
|
||||
|
@ -382,6 +389,7 @@ class CreoleTemplateEngine:
|
|||
raise FileNotFound(_(f"File {filename} does not exist."))
|
||||
if fill.get('activate', False):
|
||||
self.instance_file(fill,
|
||||
service_name,
|
||||
tmp_dir,
|
||||
dest_dir,
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
try:
|
||||
from tiramisu3 import DynOptionDescription
|
||||
except ModuleNotFoundError:
|
||||
except:
|
||||
from tiramisu import DynOptionDescription
|
||||
from .utils import normalize_family
|
||||
|
||||
|
|
|
@ -181,6 +181,7 @@ class ElementStorage:
|
|||
|
||||
class Common:
|
||||
def __init__(self,
|
||||
elt,
|
||||
storage,
|
||||
is_leader,
|
||||
path,
|
||||
|
@ -205,7 +206,7 @@ class Common:
|
|||
self.attrib['properties'] += ', '
|
||||
self.attrib['properties'] += prop
|
||||
|
||||
def get_attrib(self):
|
||||
def get_attrib(self, attrib):
|
||||
ret_list = []
|
||||
for key, value in self.attrib.items():
|
||||
if value is None:
|
||||
|
@ -260,7 +261,8 @@ class Variable(Common):
|
|||
is_leader,
|
||||
path,
|
||||
):
|
||||
super().__init__(storage,
|
||||
super().__init__(elt,
|
||||
storage,
|
||||
is_leader,
|
||||
path,
|
||||
)
|
||||
|
@ -281,7 +283,7 @@ class Variable(Common):
|
|||
self.attrib['opt'] = self.storage.get(self.attrib['opt']).get()
|
||||
else:
|
||||
self.parse_children()
|
||||
attrib = self.get_attrib()
|
||||
attrib = self.get_attrib(self.attrib)
|
||||
self.option_name = self.storage.get_name(self.path)
|
||||
self.storage.text.append(f'{self.option_name} = {self.object_type}({attrib})')
|
||||
self.populate_informations()
|
||||
|
@ -302,7 +304,7 @@ class Variable(Common):
|
|||
self.attrib[key] = value
|
||||
|
||||
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'] = []
|
||||
if self.attrib['multi'] == 'submulti' and self.is_follower:
|
||||
self.attrib['default_multi'] = []
|
||||
|
@ -365,9 +367,9 @@ class Variable(Common):
|
|||
):
|
||||
if param.type == 'string':
|
||||
return f'ParamValue("{param.text}")'
|
||||
if param.type == 'number':
|
||||
elif param.type == 'number':
|
||||
return f'ParamValue({param.text})'
|
||||
if param.type == 'variable':
|
||||
elif param.type == 'variable':
|
||||
value = {'option': param.text,
|
||||
'notraisepropertyerror': param.notraisepropertyerror,
|
||||
'todict': function in FUNC_TO_DICT,
|
||||
|
@ -375,10 +377,10 @@ class Variable(Common):
|
|||
if hasattr(param, 'suffix'):
|
||||
value['suffix'] = param.suffix
|
||||
return self.build_param(value)
|
||||
if param.type == 'information':
|
||||
elif param.type == 'information':
|
||||
return f'ParamInformation("{param.text}", None)'
|
||||
if param.type == 'suffix':
|
||||
return 'ParamSuffix()'
|
||||
elif param.type == 'suffix':
|
||||
return f'ParamSuffix()'
|
||||
raise LoaderError(_('unknown param type {}').format(param.type)) # pragma: no cover
|
||||
|
||||
def populate_value(self,
|
||||
|
@ -416,7 +418,8 @@ class Family(Common):
|
|||
is_leader,
|
||||
path,
|
||||
):
|
||||
super().__init__(storage,
|
||||
super().__init__(elt,
|
||||
storage,
|
||||
is_leader,
|
||||
path,
|
||||
)
|
||||
|
@ -432,7 +435,7 @@ class Family(Common):
|
|||
self.parse_children()
|
||||
self.option_name = self.storage.get_name(self.path)
|
||||
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.populate_informations()
|
||||
return self.option_name
|
||||
|
@ -458,6 +461,6 @@ class Family(Common):
|
|||
def get_object_name(self):
|
||||
if 'suffixes' in self.attrib:
|
||||
return 'ConvertDynOptionDescription'
|
||||
if not self.is_leader:
|
||||
elif not self.is_leader:
|
||||
return 'OptionDescription'
|
||||
return 'Leadership'
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
utilitaires créole
|
||||
"""
|
||||
from unicodedata import normalize, combining
|
||||
from .i18n import _
|
||||
|
||||
|
||||
def normalize_family(family_name: str) -> str:
|
||||
|
|
|
@ -3,13 +3,13 @@ from typing import List
|
|||
from os.path import join, isfile
|
||||
from os import listdir
|
||||
|
||||
from lxml.etree import DTD, parse, XMLSyntaxError
|
||||
from lxml.etree import DTD, parse, tostring, XMLSyntaxError
|
||||
|
||||
from .i18n import _
|
||||
from .error import DictConsistencyError
|
||||
|
||||
|
||||
class XMLReflector:
|
||||
class XMLReflector(object):
|
||||
"""Helper class for loading the Creole XML file,
|
||||
parsing it, validating against the Creole DTD,
|
||||
writing the xml result on the disk
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
{"rougail.general.module_instancie": "non", "rougail.general.mode_conteneur_actif": "oui"}
|
|
@ -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])
|
|
@ -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
|
||||
-->
|
|
@ -1 +0,0 @@
|
|||
{"rougail.general.mode_conteneur_actif": null, "rougail.general.mode_conteneur_actif1": "non"}
|
|
@ -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])
|
|
@ -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
|
||||
-->
|
|
@ -1 +0,0 @@
|
|||
{"rougail.general.module_instancie": "non", "rougail.general.mode_conteneur_actif": "oui"}
|
|
@ -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])
|
|
@ -1 +0,0 @@
|
|||
{"rougail.general.mode_conteneur_actif": "non", "rougail.general.autosavevar": "oui"}
|
|
@ -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])
|
|
@ -28,9 +28,9 @@ excludes = set([])
|
|||
#excludes = set(['01base_file_utfchar'])
|
||||
test_ok -= excludes
|
||||
test_raise -= excludes
|
||||
#test_ok = ['01auto_autofreeze']
|
||||
#test_ok = ['10valid_enum_eosfunc']
|
||||
#test_ok = []
|
||||
#test_raise = ['80auto_autofreeze']
|
||||
#test_raise = ['80redefine_double_error']
|
||||
#test_raise = []
|
||||
|
||||
ORI_DIR = getcwd()
|
||||
|
|
Loading…
Reference in New Issue