2021-01-17 18:00:29 +01:00
|
|
|
"""Annotate check
|
|
|
|
"""
|
|
|
|
from typing import List, Any
|
|
|
|
|
|
|
|
from .variable import CONVERT_OPTION
|
|
|
|
|
2021-01-19 19:05:07 +01:00
|
|
|
from ..utils import load_modules
|
2021-01-17 18:00:29 +01:00
|
|
|
from ..i18n import _
|
|
|
|
from ..error import DictConsistencyError
|
|
|
|
|
|
|
|
INTERNAL_FUNCTIONS = ['valid_enum', 'valid_in_network', 'valid_differ', 'valid_entier']
|
|
|
|
|
|
|
|
class CheckAnnotator:
|
|
|
|
"""Annotate check
|
|
|
|
"""
|
|
|
|
def __init__(self,
|
|
|
|
objectspace,
|
|
|
|
eosfunc_file,
|
|
|
|
):
|
|
|
|
if not hasattr(objectspace.space, 'constraints') or \
|
|
|
|
not hasattr(objectspace.space.constraints, 'check'):
|
|
|
|
return
|
|
|
|
self.objectspace = objectspace
|
2021-01-19 19:05:07 +01:00
|
|
|
self.functions = dir(load_modules(eosfunc_file))
|
2021-01-17 18:00:29 +01:00
|
|
|
self.functions.extend(INTERNAL_FUNCTIONS)
|
|
|
|
self.check_check()
|
|
|
|
self.check_valid_enum()
|
|
|
|
self.check_change_warning()
|
|
|
|
self.convert_check()
|
|
|
|
|
|
|
|
def check_check(self):
|
|
|
|
"""valid and manage <check>
|
|
|
|
"""
|
|
|
|
remove_indexes = []
|
|
|
|
for check_idx, check in enumerate(self.objectspace.space.constraints.check):
|
|
|
|
if not check.name in self.functions:
|
|
|
|
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
|
|
|
|
msg = _(f'cannot find check function "{check.name}" in {xmlfiles}')
|
|
|
|
raise DictConsistencyError(msg, 1)
|
|
|
|
check_name = check.target
|
|
|
|
# let's replace the target by the an object
|
|
|
|
try:
|
2021-01-17 18:04:49 +01:00
|
|
|
check.target = self.objectspace.paths.get_variable(check.target)
|
2021-01-17 18:00:29 +01:00
|
|
|
except DictConsistencyError as err:
|
|
|
|
if err.errno == 36:
|
|
|
|
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
|
|
|
|
msg = _(f'the target "{check.target}" in check cannot be a dynamic '
|
|
|
|
f'variable in {xmlfiles}')
|
|
|
|
raise DictConsistencyError(msg, 22)
|
|
|
|
raise err
|
|
|
|
check.is_in_leadership = self.objectspace.paths.is_in_leadership(check_name)
|
|
|
|
if not hasattr(check, 'param'):
|
|
|
|
continue
|
|
|
|
param_option_indexes = []
|
|
|
|
for idx, param in enumerate(check.param):
|
|
|
|
if param.type == 'variable':
|
|
|
|
if not self.objectspace.paths.path_is_defined(param.text):
|
|
|
|
if not param.optional:
|
|
|
|
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
|
|
|
|
msg = _(f'cannot find check param "{param.text}" in {xmlfiles}')
|
|
|
|
raise DictConsistencyError(msg, 2)
|
|
|
|
param_option_indexes.append(idx)
|
|
|
|
else:
|
|
|
|
# let's replace params by the path
|
2021-01-17 18:04:49 +01:00
|
|
|
param.text = self.objectspace.paths.get_variable(param.text)
|
2021-01-17 18:00:29 +01:00
|
|
|
param_option_indexes.sort(reverse=True)
|
|
|
|
for idx in param_option_indexes:
|
|
|
|
check.param.pop(idx)
|
|
|
|
if check.param == []:
|
|
|
|
remove_indexes.append(check_idx)
|
|
|
|
remove_indexes.sort(reverse=True)
|
|
|
|
for idx in remove_indexes:
|
|
|
|
del self.objectspace.space.constraints.check[idx]
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
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)
|
|
|
|
|
|
|
|
def check_valid_enum(self):
|
|
|
|
"""verify valid_enum
|
|
|
|
"""
|
|
|
|
remove_indexes = []
|
|
|
|
for idx, check in enumerate(self.objectspace.space.constraints.check):
|
|
|
|
if check.name != 'valid_enum':
|
|
|
|
continue
|
|
|
|
if check.target.path in self.objectspace.valid_enums:
|
|
|
|
check_xmlfiles = self.objectspace.valid_enums[check.target.path]['xmlfiles']
|
|
|
|
old_xmlfiles = self.objectspace.display_xmlfiles(check_xmlfiles)
|
|
|
|
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
|
|
|
|
msg = _(f'valid_enum define in {xmlfiles} but already set in {old_xmlfiles} '
|
|
|
|
f'for "{check.target.name}", did you forget remove_check?')
|
|
|
|
raise DictConsistencyError(msg, 3)
|
|
|
|
if not hasattr(check, 'param'):
|
|
|
|
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
|
|
|
|
msg = _(f'param is mandatory for a valid_enum of variable "{check.target.name}" '
|
|
|
|
f'in {xmlfiles}')
|
|
|
|
raise DictConsistencyError(msg, 4)
|
|
|
|
variable_type = check.target.type
|
|
|
|
values = self._set_valid_enum(check.target,
|
|
|
|
check,
|
|
|
|
)
|
|
|
|
if values:
|
|
|
|
if hasattr(check.target, 'value'):
|
|
|
|
# check value
|
|
|
|
self.check_valid_enum_value(check.target, 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
|
|
|
|
check.target.value = [new_value]
|
|
|
|
remove_indexes.append(idx)
|
|
|
|
remove_indexes.sort(reverse=True)
|
|
|
|
for idx in remove_indexes:
|
|
|
|
del self.objectspace.space.constraints.check[idx]
|
|
|
|
|
|
|
|
def _set_valid_enum(self,
|
|
|
|
variable,
|
|
|
|
check,
|
|
|
|
) -> List[Any]:
|
|
|
|
# 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 = 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:
|
|
|
|
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.objectspace.valid_enums[check.target.path] = {'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
|
|
|
|
|
|
|
|
def convert_check(self) -> None:
|
|
|
|
"""valid and manage <check>
|
|
|
|
"""
|
|
|
|
for check in self.objectspace.space.constraints.check:
|
|
|
|
if check.name == 'valid_entier':
|
|
|
|
if not hasattr(check, 'param'):
|
|
|
|
msg = _(f'{check.name} must have, at least, 1 param')
|
|
|
|
raise DictConsistencyError(msg, 17)
|
|
|
|
for param in check.param:
|
|
|
|
if param.type != 'number':
|
|
|
|
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
|
|
|
|
msg = _(f'param in "valid_entier" must be an "integer", not "{param.type}"'
|
|
|
|
f' in {xmlfiles}')
|
|
|
|
raise DictConsistencyError(msg, 18)
|
|
|
|
if param.name == 'mini':
|
|
|
|
check.target.min_number = int(param.text)
|
|
|
|
elif param.name == 'maxi':
|
|
|
|
check.target.max_number = int(param.text)
|
|
|
|
else:
|
|
|
|
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
|
|
|
|
msg = _(f'unknown parameter "{param.name}" in check "valid_entier" '
|
|
|
|
f'for variable "{check.target.name}" in {xmlfiles}')
|
|
|
|
raise DictConsistencyError(msg, 19)
|
|
|
|
else:
|
|
|
|
if not hasattr(check.target, 'check'):
|
|
|
|
check.target.check = []
|
|
|
|
check.target.check.append(check)
|