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 .service import ServiceAnnotator, ERASED_ATTRIBUTES
from .variable import VariableAnnotator, CONVERT_OPTION

View file

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

View file

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