208 lines
8.3 KiB
Python
208 lines
8.3 KiB
Python
"""Annotate family
|
|
"""
|
|
from ..i18n import _
|
|
from ..error import DictConsistencyError
|
|
from ..utils import normalize_family
|
|
from .variable import RENAME_ATTIBUTES
|
|
|
|
|
|
#mode order is important
|
|
modes_level = ('basic', 'normal', 'expert')
|
|
|
|
|
|
class Mode: # pylint: disable=R0903
|
|
"""Class to manage mode level
|
|
"""
|
|
def __init__(self,
|
|
name: str,
|
|
level: int,
|
|
) -> None:
|
|
self.name = name
|
|
self.level = level
|
|
|
|
def __gt__(self,
|
|
other: int,
|
|
) -> bool:
|
|
return other.level < self.level
|
|
|
|
|
|
modes = {name: Mode(name, idx) for idx, name in enumerate(modes_level)}
|
|
|
|
|
|
class FamilyAnnotator:
|
|
"""Annotate family
|
|
"""
|
|
def __init__(self,
|
|
objectspace,
|
|
):
|
|
self.objectspace = objectspace
|
|
if not hasattr(self.objectspace.space, 'variables'):
|
|
return
|
|
self.family_names()
|
|
self.remove_empty_families()
|
|
self.change_variable_mode()
|
|
self.change_family_mode()
|
|
self.dynamic_families()
|
|
self.convert_help()
|
|
|
|
def family_names(self) -> None:
|
|
"""Set doc, path, ... to family
|
|
"""
|
|
for families in self.objectspace.space.variables.values():
|
|
families.doc = families.name
|
|
families.path = families.name
|
|
for family in families.family.values():
|
|
if not hasattr(family, 'description'):
|
|
family.description = family.name
|
|
for key, value in RENAME_ATTIBUTES.items():
|
|
setattr(family, value, getattr(family, key))
|
|
setattr(family, key, None)
|
|
family.name = normalize_family(family.name)
|
|
|
|
def remove_empty_families(self) -> None:
|
|
"""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 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 _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
|
|
break
|
|
if has_value:
|
|
# 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]
|
|
# 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 and \
|
|
not variable.auto_freeze and \
|
|
'force_default_on_freeze' not in vars(variable):
|
|
variable.force_default_on_freeze = True
|
|
|
|
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
|
|
|
|
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
|
|
family.dynamic = self.objectspace.paths.get_variable(family.dynamic)
|
|
if not family.dynamic.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)
|
|
|
|
def convert_help(self):
|
|
"""Convert variable help
|
|
"""
|
|
for families in self.objectspace.space.variables.values():
|
|
for family in families.family.values():
|
|
if hasattr(family, 'help'):
|
|
if not hasattr(family, 'information'):
|
|
family.information = self.objectspace.information(family.xmlfiles)
|
|
family.information.help = family.help
|
|
del family.help
|