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,7 +74,8 @@ 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:
return
if variable.namespace != Config['variable_namespace']: if variable.namespace != Config['variable_namespace']:
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
msg = _(f'auto_freeze is not allowed in extra "{variable.namespace}" in {xmlfiles}') msg = _(f'auto_freeze is not allowed in extra "{variable.namespace}" in {xmlfiles}')

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
if hasattr(self.objectspace.space, 'variables'):
self.remove_empty_families() self.remove_empty_families()
self.change_variable_mode() self.change_variable_mode()
self.change_family_mode() self.change_family_mode()
self.dynamic_families() self.dynamic_families()
def remove_empty_families(self): # pylint: disable=C0111,R0201 def remove_empty_families(self):
if hasattr(self.objectspace.space, 'variables'): """Remove all families without any variable
for family in self.objectspace.space.variables.values(): """
if hasattr(family, 'family'): for families in self.objectspace.space.variables.values():
space = family.family
removed_families = [] removed_families = []
for family_name, sfamily in space.items(): for family_name, family in families.family.items():
if not hasattr(sfamily, 'variable') or len(sfamily.variable) == 0: if not hasattr(family, 'variable') or len(family.variable) == 0:
removed_families.append(family_name) removed_families.append(family_name)
for family_name in removed_families: for family_name in removed_families:
del space[family_name] del families.family[family_name]
def change_family_mode(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
mode = modes_level[-1] for variable in family.variable.values():
for variable in vfamily.variable.values(): if not isinstance(variable, self.objectspace.leadership):
if isinstance(variable, self.objectspace.leadership): func = self._change_variabe_mode
variable_mode = variable.variable[0].mode
variable.variable[0].mode = None
variable.mode = variable_mode
else: else:
variable_mode = variable.mode func = self._change_variable_mode_leader
if variable_mode is not None and modes[mode] > modes[variable_mode]: func(variable,
mode = variable_mode family_mode,
vfamily.mode = mode )
def dynamic_families(self): # pylint: disable=C0111 def _change_variabe_mode(self,
if not hasattr(self.objectspace.space, 'variables'): variable,
return family_mode: str,
for family in self.objectspace.space.variables.values(): ) -> None:
if hasattr(family, 'family'): # auto_save or auto_freeze variable is set to 'basic' mode
for vfamily in family.family.values(): # if its mode is not defined by the user
if 'dynamic' in vars(vfamily): if 'mode' not in vars(variable) and \
namespace = self.objectspace.paths.get_variable_namespace(vfamily.dynamic) (variable.auto_save is True or variable.auto_freeze is True):
varpath = self.objectspace.paths.get_variable_path(vfamily.dynamic, namespace) variable.mode = modes_level[0]
obj = self.objectspace.paths.get_variable_obj(varpath) self._annotate_variable(variable,
if not obj.multi: family_mode,
xmlfiles = self.objectspace.display_xmlfiles(vfamily.xmlfiles) )
raise DictConsistencyError(_(f'dynamic family "{vfamily.name}" must be linked to multi variable in {xmlfiles}'), 16)
vfamily.dynamic = varpath
def annotate_variable(self, 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, variable,
family_mode: str, family_mode: str,
is_follower=False, is_follower=False,
) -> None: ) -> 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'
"""
# 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'):
for param in value.param:
if param.type == 'variable':
break 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,
)
# leader's mode is minimum level
if modes[variable.variable[0].mode] > modes[follower.mode]:
follower.mode = variable.variable[0].mode
variable.mode = variable.variable[0].mode
else:
# 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,
) )
obj = self.objectspace.paths.get_variable_obj(varpath)
if not obj.multi:
xmlfiles = self.objectspace.display_xmlfiles(family.xmlfiles)
msg = _(f'dynamic family "{family.name}" must be linked '
f'to multi variable in {xmlfiles}')
raise DictConsistencyError(msg, 16)
family.dynamic = varpath