This commit is contained in:
Emmanuel Garette 2021-01-10 22:07:29 +01:00
parent f918792419
commit 9a19198bde
3 changed files with 159 additions and 127 deletions

View File

@ -1,3 +1,5 @@
"""Annotate dictionaries
"""
from .group import GroupAnnotator from .group import GroupAnnotator
from .service import ServiceAnnotator, ERASED_ATTRIBUTES from .service import ServiceAnnotator, ERASED_ATTRIBUTES
from .variable import VariableAnnotator, CONVERT_OPTION from .variable import VariableAnnotator, CONVERT_OPTION

View File

@ -74,27 +74,28 @@ class ConstrainteAnnotator:
only if FREEZE_AUTOFREEZE_VARIABLE == 'oui' this variable is frozen only if FREEZE_AUTOFREEZE_VARIABLE == 'oui' this variable is frozen
""" """
def _convert_auto_freeze(variable): def _convert_auto_freeze(variable):
if variable.auto_freeze: if not variable.auto_freeze:
if variable.namespace != Config['variable_namespace']: return
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) if variable.namespace != Config['variable_namespace']:
msg = _(f'auto_freeze is not allowed in extra "{variable.namespace}" in {xmlfiles}') xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
raise DictConsistencyError(msg, 49) msg = _(f'auto_freeze is not allowed in extra "{variable.namespace}" in {xmlfiles}')
new_condition = self.objectspace.condition(variable.xmlfiles) raise DictConsistencyError(msg, 49)
new_condition.name = 'auto_frozen_if_not_in' new_condition = self.objectspace.condition(variable.xmlfiles)
new_condition.namespace = variable.namespace new_condition.name = 'auto_frozen_if_not_in'
new_condition.source = FREEZE_AUTOFREEZE_VARIABLE new_condition.namespace = variable.namespace
new_param = self.objectspace.param(variable.xmlfiles) new_condition.source = FREEZE_AUTOFREEZE_VARIABLE
new_param.text = 'oui' new_param = self.objectspace.param(variable.xmlfiles)
new_condition.param = [new_param] new_param.text = 'oui'
new_target = self.objectspace.target(variable.xmlfiles) new_condition.param = [new_param]
new_target.type = 'variable' new_target = self.objectspace.target(variable.xmlfiles)
new_target.name = variable.name new_target.type = 'variable'
new_condition.target = [new_target] new_target.name = variable.name
if not hasattr(self.objectspace.space, 'constraints'): new_condition.target = [new_target]
self.objectspace.space.constraints = self.objectspace.constraints(variable.xmlfiles) if not hasattr(self.objectspace.space, 'constraints'):
if not hasattr(self.objectspace.space.constraints, 'condition'): self.objectspace.space.constraints = self.objectspace.constraints(variable.xmlfiles)
self.objectspace.space.constraints.condition = [] if not hasattr(self.objectspace.space.constraints, 'condition'):
self.objectspace.space.constraints.condition.append(new_condition) self.objectspace.space.constraints.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():
for family in variables.family.values(): for family in variables.family.values():
if not hasattr(family, 'variable'): if not hasattr(family, 'variable'):

View File

@ -1,3 +1,5 @@
"""Annotate family
"""
from ..i18n import _ from ..i18n import _
from ..error import DictConsistencyError from ..error import DictConsistencyError
@ -7,147 +9,174 @@ modes_level = ('basic', 'normal', 'expert')
class Mode: class Mode:
def __init__(self, name, level): """Class to manage mode level
"""
def __init__(self,
name: str,
level: int,
) -> None:
self.name = name self.name = name
self.level = level self.level = level
def __gt__(self, other):
def __gt__(self,
other: int,
) -> bool:
return other.level < self.level return other.level < self.level
def mode_factory(): modes = {name: Mode(name, idx) for idx, name in enumerate(modes_level)}
mode_obj = {}
for idx in range(len(modes_level)):
name = modes_level[idx]
mode_obj[name] = Mode(name, idx)
return mode_obj
modes = mode_factory()
class FamilyAnnotator: class FamilyAnnotator:
"""Annotate family
"""
def __init__(self, def __init__(self,
objectspace, objectspace,
): ):
self.objectspace = objectspace self.objectspace = objectspace
self.remove_empty_families()
self.change_variable_mode()
self.change_family_mode()
self.dynamic_families()
def remove_empty_families(self): # pylint: disable=C0111,R0201
if hasattr(self.objectspace.space, 'variables'): if hasattr(self.objectspace.space, 'variables'):
for family in self.objectspace.space.variables.values(): self.remove_empty_families()
if hasattr(family, 'family'): self.change_variable_mode()
space = family.family self.change_family_mode()
removed_families = [] self.dynamic_families()
for family_name, sfamily in space.items():
if not hasattr(sfamily, 'variable') or len(sfamily.variable) == 0:
removed_families.append(family_name)
for family_name in removed_families:
del space[family_name]
def change_family_mode(self): # pylint: disable=C0111 def remove_empty_families(self):
if not hasattr(self.objectspace.space, 'variables'): """Remove all families without any variable
return """
for family in self.objectspace.space.variables.values(): for families in self.objectspace.space.variables.values():
if hasattr(family, 'family'): removed_families = []
for vfamily in family.family.values(): for family_name, family in families.family.items():
mode = modes_level[-1] if not hasattr(family, 'variable') or len(family.variable) == 0:
for variable in vfamily.variable.values(): removed_families.append(family_name)
if isinstance(variable, self.objectspace.leadership): for family_name in removed_families:
variable_mode = variable.variable[0].mode del families.family[family_name]
variable.variable[0].mode = None
variable.mode = variable_mode
else:
variable_mode = variable.mode
if variable_mode is not None and modes[mode] > modes[variable_mode]:
mode = variable_mode
vfamily.mode = mode
def dynamic_families(self): # pylint: disable=C0111 def change_variable_mode(self):
if not hasattr(self.objectspace.space, 'variables'): """change the mode of variables
return """
for family in self.objectspace.space.variables.values(): for variables in self.objectspace.space.variables.values():
if hasattr(family, 'family'): for family in variables.family.values():
for vfamily in family.family.values(): family_mode = family.mode
if 'dynamic' in vars(vfamily): for variable in family.variable.values():
namespace = self.objectspace.paths.get_variable_namespace(vfamily.dynamic) if not isinstance(variable, self.objectspace.leadership):
varpath = self.objectspace.paths.get_variable_path(vfamily.dynamic, namespace) func = self._change_variabe_mode
obj = self.objectspace.paths.get_variable_obj(varpath) else:
if not obj.multi: func = self._change_variable_mode_leader
xmlfiles = self.objectspace.display_xmlfiles(vfamily.xmlfiles) func(variable,
raise DictConsistencyError(_(f'dynamic family "{vfamily.name}" must be linked to multi variable in {xmlfiles}'), 16) family_mode,
vfamily.dynamic = varpath )
def annotate_variable(self, def _change_variabe_mode(self,
variable, variable,
family_mode: str, family_mode: str,
is_follower=False, ) -> None:
) -> None: # auto_save or auto_freeze variable is set to 'basic' mode
# if the variable is mandatory and doesn't have any value # if its mode is not defined by the user
# then the variable's mode is set to 'basic' if 'mode' not in vars(variable) and \
(variable.auto_save is True or variable.auto_freeze is True):
variable.mode = modes_level[0]
self._annotate_variable(variable,
family_mode,
)
def _change_variable_mode_leader(self,
leadership,
family_mode: str,
) -> None:
is_follower = False
leader_mode = None
for follower in leadership.variable:
if follower.auto_save is True:
xmlfiles = self.objectspace.display_xmlfiles(leadership.xmlfiles)
msg = _(f'leader/followers "{follower.name}" could not be auto_save in {xmlfiles}')
raise DictConsistencyError(msg, 29)
if follower.auto_freeze is True:
xmlfiles = self.objectspace.display_xmlfiles(leadership.xmlfiles)
msg = f'leader/followers "{follower.name}" could not be auto_freeze in {xmlfiles}'
raise DictConsistencyError(_(msg), 30)
self._annotate_variable(follower,
family_mode,
is_follower,
)
if leader_mode is None:
leader_mode = leadership.variable[0].mode
leadership.variable[0].mode = None
else:
# leader's mode is minimum level
if modes[leader_mode] > modes[follower.mode]:
follower.mode = leader_mode
is_follower = True
leadership.mode = leader_mode
def _annotate_variable(self,
variable,
family_mode: str,
is_follower=False,
) -> None:
"""if the variable is mandatory and doesn't have any value
then the variable's mode is set to 'basic'
"""
# a boolean must have value, the default value is "True"
if not hasattr(variable, 'value') and variable.type == 'boolean': if not hasattr(variable, 'value') and variable.type == 'boolean':
new_value = self.objectspace.value(variable.xmlfiles) new_value = self.objectspace.value(variable.xmlfiles)
new_value.name = True new_value.name = True
new_value.type = 'boolean' new_value.type = 'boolean'
variable.value = [new_value] variable.value = [new_value]
# variable with default value is mandatory
if hasattr(variable, 'value') and variable.value: if hasattr(variable, 'value') and variable.value:
has_value = True has_value = True
for value in variable.value: for value in variable.value:
if value.type == 'calculation': if value.type == 'calculation':
has_value = False has_value = False
if hasattr(value, 'param'): break
for param in value.param:
if param.type == 'variable':
break
if has_value: if has_value:
# if has value but without any calculation # if has value without any calculation
variable.mandatory = True variable.mandatory = True
# mandatory variable without value is a basic variable
if variable.mandatory is True and (not hasattr(variable, 'value') or is_follower): if variable.mandatory is True and (not hasattr(variable, 'value') or is_follower):
variable.mode = modes_level[0] variable.mode = modes_level[0]
if variable.mode is not None and modes[variable.mode] < modes[family_mode] and (not is_follower or variable.mode != modes_level[0]): # none basic variable in high level family has to be in high level
if modes[variable.mode] < modes[family_mode] and \
(not is_follower or variable.mode != modes_level[0]):
variable.mode = family_mode variable.mode = family_mode
# hidden variable is also frozen
if variable.hidden is True: if variable.hidden is True:
variable.frozen = True variable.frozen = True
if not variable.auto_save is True and \ if not variable.auto_save and \
not variable.auto_freeze and \ not variable.auto_freeze and \
'force_default_on_freeze' not in vars(variable): '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_family_mode(self):
if not hasattr(self.objectspace.space, 'variables'): """change mode of a family
return """
for variables in self.objectspace.space.variables.values(): for families in self.objectspace.space.variables.values():
if hasattr(variables, 'family'): for family in families.family.values():
for family in variables.family.values(): # default is high level
family_mode = family.mode mode = modes_level[-1]
if hasattr(family, 'variable'): # get de lower sub variable mode
for variable in family.variable.values(): for variable in family.variable.values():
variable_mode = variable.mode
if modes[mode] > modes[variable_mode]:
mode = variable_mode
# set the lower variable mode to family
family.mode = mode
if isinstance(variable, self.objectspace.leadership): def dynamic_families(self):
for idx, follower in enumerate(variable.variable): """link dynamic families to object
if follower.auto_save is True: """
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) for families in self.objectspace.space.variables.values():
raise DictConsistencyError(_(f'leader/followers "{follower.name}" could not be auto_save in {xmlfiles}'), 29) for family in families.family.values():
if follower.auto_freeze is True: if 'dynamic' not in vars(family):
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) continue
raise DictConsistencyError(_(f'leader/followers "{follower.name}" could not be auto_freeze in {xmlfiles}'), 30) namespace = self.objectspace.paths.get_variable_namespace(family.dynamic)
is_follower = idx != 0 varpath = self.objectspace.paths.get_variable_path(family.dynamic,
self.annotate_variable(follower, namespace,
family_mode, )
is_follower, obj = self.objectspace.paths.get_variable_obj(varpath)
) if not obj.multi:
# leader's mode is minimum level xmlfiles = self.objectspace.display_xmlfiles(family.xmlfiles)
if modes[variable.variable[0].mode] > modes[follower.mode]: msg = _(f'dynamic family "{family.name}" must be linked '
follower.mode = variable.variable[0].mode f'to multi variable in {xmlfiles}')
variable.mode = variable.variable[0].mode raise DictConsistencyError(msg, 16)
else: family.dynamic = varpath
# auto_save's variable is set in 'basic' mode if its mode is 'normal'
if variable.auto_save is True and variable.mode != modes_level[-1]:
variable.mode = modes_level[0]
# 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,
)