Compare commits

..

5 Commits

Author SHA1 Message Date
Emmanuel Garette d5ed39c1f3 support auto_freeze with hidden_if_in 2021-01-06 22:33:55 +01:00
Emmanuel Garette 1a77416e6d support auto_freeze with auto 2021-01-06 22:20:33 +01:00
Emmanuel Garette 8a07892276 pylint 2021-01-06 21:50:53 +01:00
Emmanuel Garette 1e0cb96b34 pylint annotator/constrainte.py 2021-01-02 21:23:18 +01:00
Emmanuel Garette a6bafd89bd pylint 2020-12-26 17:06:56 +01:00
35 changed files with 642 additions and 448 deletions

View File

@ -1,5 +1,7 @@
from typing import List """Annotate constraints
"""
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
@ -13,7 +15,31 @@ 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,
@ -24,18 +50,16 @@ 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.check_params_target() self.convert_condition_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()
@ -43,16 +67,20 @@ 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()
self.remove_constraints() del self.objectspace.space.constraints
def convert_auto_freeze(self): # pylint: disable=C0111 def convert_auto_freeze(self):
"""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)
raise DictConsistencyError(_(f'auto_freeze is not allowed in extra "{namespace}" in {xmlfiles}'), 49) msg = _(f'auto_freeze is not allowed in extra "{namespace}" in {xmlfiles}')
raise DictConsistencyError(msg, 49)
new_condition = self.objectspace.condition(variable.xmlfiles) new_condition = self.objectspace.condition(variable.xmlfiles)
new_condition.name = 'auto_hidden_if_not_in' new_condition.name = 'auto_frozen_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)
@ -66,82 +94,176 @@ 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 hasattr(variables, 'family'): if not hasattr(variables, 'family'):
namespace = variables.name continue
for family in variables.family.values(): for family in variables.family.values():
if hasattr(family, 'variable'): if not hasattr(family, 'variable'):
for variable in family.variable.values(): continue
if isinstance(variable, self.objectspace.leadership): for variable in family.variable.values():
for follower in variable.variable: if isinstance(variable, self.objectspace.leadership):
_convert_auto_freeze(follower, namespace) for follower in variable.variable:
else: _convert_auto_freeze(follower,
_convert_auto_freeze(variable, namespace) variables.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)
raise DictConsistencyError(_(f'cannot find check function "{check.name}" in {xmlfiles}'), 1) msg = _(f'cannot find check function "{check.name}" in {xmlfiles}')
if hasattr(check, 'param'): raise DictConsistencyError(msg, 1)
param_option_indexes = [] if not hasattr(check, 'param'):
for idx, param in enumerate(check.param): continue
if param.type == 'variable' and not self.objectspace.paths.path_is_defined(param.text): param_option_indexes = []
if param.optional is True: for idx, param in enumerate(check.param):
param_option_indexes.append(idx) if param.type == 'variable':
else: if not self.objectspace.paths.path_is_defined(param.text):
if not param.optional:
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'cannot find check param "{param.text}" in {xmlfiles}'), 2) msg = _(f'cannot find check param "{param.text}" in {xmlfiles}')
if param.type != 'variable': raise DictConsistencyError(msg, 2)
param.notraisepropertyerror = None param_option_indexes.append(idx)
param_option_indexes = list(set(param_option_indexes)) else:
param_option_indexes.sort(reverse=True) # let's replace params by the path
for idx in param_option_indexes: param.text = self.objectspace.paths.get_variable_path(param.text,
check.param.pop(idx) check.namespace,
if check.param == []: )
remove_indexes.append(check_idx) 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
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:
old_xmlfiles = self.objectspace.display_xmlfiles(self.valid_enums[check.target]['xmlfiles']) check_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)
raise DictConsistencyError(_(f'valid_enum define in {xmlfiles} but already set in {old_xmlfiles} for "{check.target}", did you forget remove_check?'), 3) 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)
if not hasattr(check, 'param'): if not hasattr(check, 'param'):
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'param is mandatory for a valid_enum of variable "{check.target}" in {xmlfiles}'), 4) msg = _(f'param is mandatory for a valid_enum of variable "{check.target}" '
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)
self._set_valid_enum(variable, variable_type = variable.type
check, 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]
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 check_change_warning(self): def _set_valid_enum(self,
#convert level to "warnings_only" variable,
for check in self.objectspace.space.constraints.check: check,
if check.level == 'warning': ) -> List[Any]:
check.warnings_only = True # 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: else:
check.warnings_only = False 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"
"""
for check in self.objectspace.space.constraints.check:
check.warnings_only = check.level == 'warning'
check.level = None check.level = None
def _get_family_variables_from_target(self, def _get_family_variables_from_target(self,
@ -158,40 +280,50 @@ 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 check_params_target(self): def convert_condition_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)
raise DictConsistencyError(_(f'target is mandatory in a condition for source "{condition.source}" in {xmlfiles}'), 9) msg = _(f'target is mandatory in a condition for source "{condition.source}" '
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:
raise DictConsistencyError(_('target name and source name must be different: {}').format(condition.source), 11) 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('.')])
try: try:
target_names = [normalize_family(name) for name in target.name.split('.')] target.name = self.objectspace.paths.get_variable_path(target_names,
target.name = self.objectspace.paths.get_variable_path('.'.join(target_names), namespace) condition.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_names = [normalize_family(name) for name in target.name.split('.')] target.name = self.objectspace.paths.get_family_path(target_names,
target.name = self.objectspace.paths.get_family_path('.'.join(target_names), namespace) condition.namespace,
)
except KeyError: except KeyError:
raise DictConsistencyError(_('cannot found family {}').format(target.name), 12) 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)
def convert_xxxlist_to_variable(self): # pylint: disable=C0111 def convert_xxxlist_to_variable(self):
# 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):
@ -215,55 +347,56 @@ 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 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 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
if apply_action:
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) remove_conditions.append(idx)
if apply_action:
self.force_actions_to_variable(condition)
continue continue
remove_targets = [] remove_targets = []
# optional # optional
for idx, target in enumerate(condition.target): for index, target in enumerate(condition.target):
if target.optional is True and not self.objectspace.paths.path_is_defined(target.name): if target.optional is True and \
remove_targets.append(idx) not self.objectspace.paths.path_is_defined(target.name):
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 idx in remove_targets: for index in remove_targets:
condition.target.pop(idx) condition.target.pop(index)
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 _get_condition_actions(self, condition_name): def force_actions_to_variable(self,
if condition_name.startswith('disabled_if_'): condition: 'self.objectspace.condition',
return ['disabled'] ) -> None:
elif condition_name.startswith('hidden_if_'): """force property to a variable
return ['hidden', 'frozen', 'force_default_on_freeze'] for example disabled_if_not_in => variable.disabled = True
elif condition_name.startswith('mandatory_if_'): """
return ['mandatory'] actions = get_actions_from_condition(condition.name)
elif condition_name == 'auto_hidden_if_not_in': for target in condition.target:
return ['auto_frozen'] 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 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
@ -274,257 +407,200 @@ class ConstrainteAnnotator:
) )
if suffix: if suffix:
xmlfiles = self.objectspace.display_xmlfiles(condition.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(condition.xmlfiles)
raise DictConsistencyError(_(f'the source "{condition.source}" in condition cannot be a dynamic variable in {xmlfiles}'), 20) msg = _(f'the source "{condition.source}" in condition cannot be a dynamic '
src_variable = self.objectspace.paths.get_variable_obj(condition.source) f'variable in {xmlfiles}')
valid_enum = None raise DictConsistencyError(msg, 20)
# FIXME only string? # 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'] valid_enum = self.valid_enums[condition.source]['values']
if valid_enum is not None: remove_param = [param_idx for param_idx, param in enumerate(condition.param) \
remove_param = [] if param.text not in valid_enum]
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 condition.param == []: if not condition.param and condition.name.endswith('_if_not_in'):
for target in condition.target: self.force_actions_to_variable(condition)
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 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) 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:
inverse = condition.name.endswith('_if_not_in') actions = get_actions_from_condition(condition.name)
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: '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] 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:
xmlfiles = self.objectspace.display_xmlfiles(leader_or_variable.xmlfiles) continue
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 action in actions[1:]:
for idx, action in enumerate(actions): # other actions are set to the variable or children of family
prop = self.objectspace.property_(leader_or_variable.xmlfiles) for variable in variables:
prop.type = 'calculation' self.build_property(variable,
prop.inverse = inverse text,
prop.source = condition.source condition,
prop.expected = text action,
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 _set_valid_enum(self, def build_property(self,
variable, obj,
check, text: Any,
): condition: 'self.objectspace.condition',
type_ = variable.type action: str,
target = check.target ) -> 'self.objectspace.property_':
# value for choice's variable is mandatory """build property_ for a condition
variable.mandatory = True """
# build choice prop = self.objectspace.property_(obj.xmlfiles)
variable.choice = [] prop.type = 'calculation'
variable.type = 'choice' 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)
has_variable = False def convert_check(self) -> None:
values = [] """valid and manage <check>
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)
name = check.name if check.name == 'valid_entier':
if name == 'valid_entier':
if not hasattr(check, 'param'): if not hasattr(check, 'param'):
raise DictConsistencyError(_('{} must have, at least, 1 param').format(name), 17) msg = _(f'{check.name} must have, at least, 1 param')
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)
raise DictConsistencyError(_(f'param in "valid_entier" must be an "integer", not "{param.type}" in {xmlfiles}'), 18) msg = _(f'param in "valid_entier" must be an "integer", not "{param.type}"'
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)
raise DictConsistencyError(_(f'unknown parameter "{param.name}" in check "valid_entier" for variable "{check.target}" in {xmlfiles}'), 19) msg = _(f'unknown parameter "{param.name}" in check "valid_entier" '
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): # pylint: disable=C0111,R0912 def convert_fill(self) -> None:
# sort fill/auto by index """valid and manage <fill>
fills = {fill.index: fill for idx, fill in enumerate(self.objectspace.space.constraints.fill)} """
indexes = list(fills.keys())
indexes.sort()
targets = [] targets = []
for idx in indexes: for fill in self.objectspace.space.constraints.fill:
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)
raise DictConsistencyError(_(f'A fill already exists for the target of "{fill.target}" created in {xmlfiles}'), 24) msg = _(f'A fill already exists for the target of "{fill.target}" created '
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)
raise DictConsistencyError(_(f'cannot find fill function "{fill.name}" in {xmlfiles}'), 25) msg = _(f'cannot find fill function "{fill.name}" in {xmlfiles}')
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,
namespace, fill.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)
raise DictConsistencyError(_(f'Cannot add fill function to "{fill.target}" only for the suffix "{suffix}" in {xmlfiles}'), 26) 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
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
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] variable.value = [value]
del self.objectspace.space.constraints.fill
def remove_constraints(self): # manage params
if hasattr(self.objectspace.space.constraints, 'index'): if not hasattr(fill, 'param'):
del self.objectspace.space.constraints.index continue
del self.objectspace.space.constraints.namespace self.convert_fill_param(fill)
del self.objectspace.space.constraints.xmlfiles if fill.param:
if vars(self.objectspace.space.constraints): # pragma: no cover value.param = fill.param
raise Exception('constraints again?')
del self.objectspace.space.constraints 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)

View File

@ -6,7 +6,7 @@ from ..error import DictConsistencyError
modes_level = ('basic', 'normal', 'expert') modes_level = ('basic', 'normal', 'expert')
class Mode(object): class Mode:
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, family in space.items(): for family_name, sfamily in space.items():
if not hasattr(family, 'variable') or len(family.variable) == 0: if not hasattr(sfamily, 'variable') or len(sfamily.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 family in family.family.values(): for vfamily in family.family.values():
mode = modes_level[-1] mode = modes_level[-1]
for variable in family.variable.values(): for variable in vfamily.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,24 +62,28 @@ 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
family.mode = mode vfamily.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 family in family.family.values(): for vfamily in family.family.values():
if 'dynamic' in vars(family): if 'dynamic' in vars(vfamily):
namespace = self.objectspace.paths.get_variable_namespace(family.dynamic) namespace = self.objectspace.paths.get_variable_namespace(vfamily.dynamic)
varpath = self.objectspace.paths.get_variable_path(family.dynamic, namespace) varpath = self.objectspace.paths.get_variable_path(vfamily.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(family.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(vfamily.xmlfiles)
raise DictConsistencyError(_(f'dynamic family "{family.name}" must be linked to multi variable in {xmlfiles}'), 16) raise DictConsistencyError(_(f'dynamic family "{vfamily.name}" must be linked to multi variable in {xmlfiles}'), 16)
family.dynamic = varpath vfamily.dynamic = varpath
def annotate_variable(self, variable, family_mode, path, is_follower=False): def annotate_variable(self,
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':
@ -92,32 +96,28 @@ 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 != None and modes[variable.mode] < modes[family_mode] and (not is_follower or 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]):
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 'force_default_on_freeze' not in vars(variable): if not variable.auto_save is True and \
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,7 +125,6 @@ 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)
@ -134,8 +133,10 @@ 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
path = '{}.{}.{}'.format(family.path, variable.name, follower.name) self.annotate_variable(follower,
self.annotate_variable(follower, family_mode, path, is_follower) family_mode,
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
@ -147,6 +148,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]
path = '{}.{}'.format(family.path, variable.name) self.annotate_variable(variable,
self.annotate_variable(variable, family_mode, path) family_mode,
)

View File

@ -1,3 +1,5 @@
"""Annotate group
"""
from typing import List from typing import List
from ..i18n import _ from ..i18n import _
@ -5,15 +7,20 @@ 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 not hasattr(self.objectspace.space.constraints, 'group'): if not hasattr(self.objectspace.space, 'constraints') or \
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)
@ -23,18 +30,20 @@ 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
ori_leader_family = self.objectspace.paths.get_family_obj(leader_fullname.rsplit('.', 1)[0]) leader_family = 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(namespace, self.manage_follower(leader_family_name,
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
@ -56,7 +65,6 @@ 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,
@ -65,7 +73,9 @@ 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)
raise DictConsistencyError(_(f'when parsing leadership, we espect to find those followers "{joined}" in {xmlfiles}'), 31) msg = _(f'when parsing leadership, we espect to find those followers "{joined}" '
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,
@ -73,15 +83,16 @@ 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)
raise DictConsistencyError(_(f'the variable "{variable.name}" in a group must be multi in {xmlfiles}'), 32) msg = _(f'the variable "{variable.name}" in a group must be multi in {xmlfiles}')
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
@ -98,6 +109,7 @@ 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,
@ -115,25 +127,21 @@ 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:
if variable.name != follower_names[0]: """manage follower
"""
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)
raise DictConsistencyError(_(f'when parsing leadership, we espect to find the follower "{follower_names[0]}" but we found "{variable.name}" in {xmlfiles}'), 33) msg = _('when parsing leadership, we espect to find the follower '
follower_names.remove(variable.name) f'"{follower_name}" but we found "{variable.name}" in {xmlfiles}')
if leader_is_hidden: raise DictConsistencyError(msg, 33)
variable.frozen = True self.objectspace.paths.set_leader(variable.namespace,
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,24 +1,35 @@
"""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'], 'auto_freeze': ['force_store_value', 'auto_freeze']} CONVERT_PROPERTIES = {'auto_save': ['force_store_value'],
'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
self.convert_annotator() if hasattr(self.objectspace.space, 'services'):
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) == True: if getattr(variable, prop) is 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)
@ -27,35 +38,46 @@ 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)
raise DictConsistencyError(_(f'cannot have auto_freeze or auto_store with the hidden variable "{variable.name}" in {xmlfiles}'), 50) msg = _('cannot have auto_freeze or auto_store with the hidden '
f'variable "{variable.name}" in {xmlfiles}')
raise DictConsistencyError(msg, 50)
if properties: if properties:
variable.properties = frozenset(properties) variable.properties = frozenset(properties)
def convert_annotator(self): # pylint: disable=C0111 def convert_services(self) -> None:
if hasattr(self.objectspace.space, 'services'): """convert services
self.convert_property(self.objectspace.space.services) """
for services in self.objectspace.space.services.service.values(): self.convert_property(self.objectspace.space.services)
self.convert_property(services) for services in self.objectspace.space.services.service.values():
for service in vars(services).values(): self.convert_property(services)
if isinstance(service, self.objectspace.family): for service in vars(services).values():
self.convert_property(service) if not isinstance(service, self.objectspace.family):
if hasattr(service, 'family'): continue
self.convert_property(service) self.convert_property(service)
for family in service.family: if not hasattr(service, 'family'):
self.convert_property(family) continue
if hasattr(family, 'variable'): self.convert_property(service)
for variable in family.variable: for family in service.family:
self.convert_property(variable) self.convert_property(family)
if hasattr(self.objectspace.space, 'variables'): if not hasattr(family, 'variable'):
for variables in self.objectspace.space.variables.values(): continue
if hasattr(variables, 'family'): for variable in family.variable:
for family in variables.family.values(): self.convert_property(variable)
self.convert_property(family)
if hasattr(family, 'variable'): def convert_variables(self) -> None:
for variable in family.variable.values(): """convert variables
if isinstance(variable, self.objectspace.leadership): """
self.convert_property(variable) for variables in self.objectspace.space.variables.values():
for follower in variable.variable: if not hasattr(variables, 'family'):
self.convert_property(follower) continue
else: for family in variables.family.values():
self.convert_property(variable) 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)

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 idx, service_name in enumerate(self.objectspace.space.services.service.keys()): for service_name in 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 idx, separator in enumerate(family.separators.separator): for separator in 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,4 +151,3 @@ 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,17 +6,15 @@ 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|auto_hidden_if_not_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|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,7 +11,6 @@ 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,6 +1,3 @@
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
@ -111,7 +108,6 @@ 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,
@ -165,8 +161,7 @@ class RougailObjSpace:
self.remove(child, self.remove(child,
variableobj, variableobj,
) )
self.set_path(space, self.set_path(child,
child,
namespace, namespace,
document, document,
variableobj, variableobj,
@ -200,7 +195,7 @@ class RougailObjSpace:
child, child,
namespace, namespace,
) )
elif Atom in obj.__mro__: if 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
@ -368,7 +363,6 @@ 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,
@ -382,7 +376,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') != None, document.attrib.get('dynamic') is not None,
variableobj, variableobj,
) )
if child.attrib.get('redefine', 'False') == 'True': if child.attrib.get('redefine', 'False') == 'True':

View File

@ -1,5 +1,4 @@
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
@ -142,7 +141,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: # pragma: no cover except ModuleNotFoundError: # pragma: no cover
from tiramisu import Config from tiramisu import Config
from tiramisu.error import PropertiesOptionError from tiramisu.error import PropertiesOptionError
@ -89,12 +89,7 @@ class CheetahTemplate(ChtTemplate):
return None return None
class CreoleValue: class CreoleLeaderIndex:
def __str__(self):
return str(self._value)
class CreoleLeaderIndex(CreoleValue):
def __init__(self, def __init__(self,
value, value,
follower, follower,
@ -112,6 +107,9 @@ class CreoleLeaderIndex(CreoleValue):
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)
@ -137,7 +135,7 @@ class CreoleLeaderIndex(CreoleValue):
return value + self._value return value + self._value
class CreoleLeader(CreoleValue): class CreoleLeader:
def __init__(self, def __init__(self,
value, value,
) -> None: ) -> None:
@ -187,7 +185,8 @@ class CreoleExtra:
self.suboption = suboption self.suboption = suboption
def __getattr__(self, def __getattr__(self,
key: str) -> Any: key: str,
) -> Any:
return self.suboption[key] return self.suboption[key]
def __iter__(self): def __iter__(self):
@ -212,8 +211,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 = {}
@ -238,8 +237,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,
namespace, optiondescription,
optiondescription): ):
families = {} families = {}
for family in await optiondescription.list('all'): for family in await optiondescription.list('all'):
variables = {} variables = {}
@ -257,9 +256,7 @@ class CreoleTemplateEngine:
) )
variables[leader_name] = leader variables[leader_name] = leader
else: else:
subfamilies = await self.load_eole_variables(await variable.option.name(), subfamilies = await self.load_eole_variables(variable)
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()
@ -301,7 +298,6 @@ 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
@ -327,7 +323,6 @@ 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:
@ -355,8 +350,8 @@ class CreoleTemplateEngine:
self.process(source, self.process(source,
filename, filename,
destfilename, destfilename,
filevar, var,
var) )
else: else:
copy(source, destfilename) copy(source, destfilename)
@ -373,13 +368,11 @@ 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(namespace, families = await self.load_eole_variables(option)
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'):
@ -389,7 +382,6 @@ 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: except ModuleNotFoundError:
from tiramisu import DynOptionDescription from tiramisu import DynOptionDescription
from .utils import normalize_family from .utils import normalize_family

View File

@ -181,7 +181,6 @@ class ElementStorage:
class Common: class Common:
def __init__(self, def __init__(self,
elt,
storage, storage,
is_leader, is_leader,
path, path,
@ -206,7 +205,7 @@ class Common:
self.attrib['properties'] += ', ' self.attrib['properties'] += ', '
self.attrib['properties'] += prop self.attrib['properties'] += prop
def get_attrib(self, attrib): def get_attrib(self):
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:
@ -261,8 +260,7 @@ class Variable(Common):
is_leader, is_leader,
path, path,
): ):
super().__init__(elt, super().__init__(storage,
storage,
is_leader, is_leader,
path, path,
) )
@ -283,7 +281,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(self.attrib) attrib = self.get_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()
@ -304,7 +302,7 @@ class Variable(Common):
self.attrib[key] = value self.attrib[key] = value
def parse_children(self): def parse_children(self):
if not 'default' in self.attrib or self.attrib['multi']: if 'default' not 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'] = []
@ -367,9 +365,9 @@ class Variable(Common):
): ):
if param.type == 'string': if param.type == 'string':
return f'ParamValue("{param.text}")' return f'ParamValue("{param.text}")'
elif param.type == 'number': if param.type == 'number':
return f'ParamValue({param.text})' return f'ParamValue({param.text})'
elif param.type == 'variable': if 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,
@ -377,10 +375,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)
elif param.type == 'information': if param.type == 'information':
return f'ParamInformation("{param.text}", None)' return f'ParamInformation("{param.text}", None)'
elif param.type == 'suffix': if param.type == 'suffix':
return f'ParamSuffix()' return '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,
@ -418,8 +416,7 @@ class Family(Common):
is_leader, is_leader,
path, path,
): ):
super().__init__(elt, super().__init__(storage,
storage,
is_leader, is_leader,
path, path,
) )
@ -435,7 +432,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(self.attrib) + ', children=[' + ', '.join([child.get() for child in self.children]) + ']' attrib = self.get_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
@ -461,6 +458,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'
elif not self.is_leader: if not self.is_leader:
return 'OptionDescription' return 'OptionDescription'
return 'Leadership' return 'Leadership'

View File

@ -2,7 +2,6 @@
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, tostring, XMLSyntaxError from lxml.etree import DTD, parse, XMLSyntaxError
from .i18n import _ from .i18n import _
from .error import DictConsistencyError from .error import DictConsistencyError
class XMLReflector(object): class XMLReflector:
"""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

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

View File

@ -0,0 +1,15 @@
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

@ -0,0 +1,21 @@
<?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

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

View File

@ -0,0 +1,15 @@
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

@ -0,0 +1,25 @@
<?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

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

View File

@ -0,0 +1,15 @@
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

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

View File

@ -0,0 +1,15 @@
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 = ['10valid_enum_eosfunc'] #test_ok = ['01auto_autofreeze']
#test_ok = [] #test_ok = []
#test_raise = ['80redefine_double_error'] #test_raise = ['80auto_autofreeze']
#test_raise = [] #test_raise = []
ORI_DIR = getcwd() ORI_DIR = getcwd()