add xmlfiles in various error message

This commit is contained in:
Emmanuel Garette 2020-11-11 16:24:06 +01:00
parent f7db6b0289
commit 3d49f2fe8c
6 changed files with 150 additions and 55 deletions

View file

@ -38,7 +38,7 @@ modes = mode_factory()
# that shall not be present in the exported (flatened) XML # that shall not be present in the exported (flatened) XML
ERASED_ATTRIBUTES = ('redefine', 'exists', 'fallback', 'optional', 'remove_check', 'namespace', ERASED_ATTRIBUTES = ('redefine', 'exists', 'fallback', 'optional', 'remove_check', 'namespace',
'remove_condition', 'path', 'instance_mode', 'index', 'is_in_leadership', 'remove_condition', 'path', 'instance_mode', 'index', 'is_in_leadership',
'level', 'remove_fill') 'level', 'remove_fill', 'xmlfiles')
ERASED_CONTAINER_ATTRIBUTES = ('id', 'container', 'group_id', 'group', 'container_group') ERASED_CONTAINER_ATTRIBUTES = ('id', 'container', 'group_id', 'group', 'container_group')
FORCE_CHOICE = {'oui/non': ['oui', 'non'], FORCE_CHOICE = {'oui/non': ['oui', 'non'],
@ -125,7 +125,7 @@ class GroupAnnotator:
# if variable.hidden: # if variable.hidden:
# leader_is_hidden = True # leader_is_hidden = True
else: else:
leader_space = self.objectspace.Leadership() leader_space = self.objectspace.Leadership(variable.xmlfiles)
leader_is_hidden = self.manage_leader(leader_space, leader_is_hidden = self.manage_leader(leader_space,
leader_family_name, leader_family_name,
leader_name, leader_name,
@ -233,7 +233,7 @@ class ServiceAnnotator:
families = {} families = {}
for idx, service_name in enumerate(self.objectspace.space.services.service.keys()): for idx, service_name in enumerate(self.objectspace.space.services.service.keys()):
service = self.objectspace.space.services.service[service_name] service = self.objectspace.space.services.service[service_name]
new_service = self.objectspace.service() new_service = self.objectspace.service(service.xmlfiles)
for elttype, values in vars(service).items(): for elttype, values in vars(service).items():
if not isinstance(values, (dict, list)) or elttype in ERASED_ATTRIBUTES: if not isinstance(values, (dict, list)) or elttype in ERASED_ATTRIBUTES:
setattr(new_service, elttype, values) setattr(new_service, elttype, values)
@ -242,6 +242,7 @@ class ServiceAnnotator:
path = '.'.join(['services', service_name, eltname]) path = '.'.join(['services', service_name, eltname])
family = self.gen_family(eltname, family = self.gen_family(eltname,
path, path,
service.xmlfiles,
) )
if isinstance(values, dict): if isinstance(values, dict):
values = list(values.values()) values = list(values.values())
@ -258,8 +259,9 @@ class ServiceAnnotator:
def gen_family(self, def gen_family(self,
name, name,
path, path,
xmlfiles
): ):
family = self.objectspace.family() family = self.objectspace.family(xmlfiles)
family.name = normalize_family(name) family.name = normalize_family(name)
family.doc = name family.doc = name
family.mode = None family.mode = None
@ -307,7 +309,10 @@ class ServiceAnnotator:
if not self.objectspace.paths.family_is_defined(subpath): if not self.objectspace.paths.family_is_defined(subpath):
break break
idx += 1 idx += 1
family = self.gen_family(c_name, subpath) family = self.gen_family(c_name,
subpath,
elt.xmlfiles,
)
family.variable = [] family.variable = []
listname = '{}list'.format(name) listname = '{}list'.format(name)
activate_path = '.'.join([subpath, 'activate']) activate_path = '.'.join([subpath, 'activate'])
@ -345,7 +350,7 @@ class ServiceAnnotator:
elt, elt,
path, path,
): ):
variable = self.objectspace.variable() variable = self.objectspace.variable(elt.xmlfiles)
variable.name = normalize_family(key) variable.name = normalize_family(key)
variable.mode = None variable.mode = None
if key == 'name': if key == 'name':
@ -370,7 +375,7 @@ class ServiceAnnotator:
variable.multi = None variable.multi = None
else: else:
variable.doc = key variable.doc = key
val = self.objectspace.value() val = self.objectspace.value(elt.xmlfiles)
val.type = type_ val.type = type_
val.name = value val.name = value
variable.value = [val] variable.value = [val]
@ -469,17 +474,17 @@ class VariableAnnotator:
path, path,
): ):
if variable.type in FORCE_CHOICE: if variable.type in FORCE_CHOICE:
check = self.objectspace.check() check = self.objectspace.check(variable.xmlfiles)
check.name = 'valid_enum' check.name = 'valid_enum'
check.target = path check.target = path
check.namespace = namespace check.namespace = namespace
check.param = [] check.param = []
for value in FORCE_CHOICE[variable.type]: for value in FORCE_CHOICE[variable.type]:
param = self.objectspace.param() param = self.objectspace.param(variable.xmlfiles)
param.text = value param.text = value
check.param.append(param) check.param.append(param)
if not hasattr(self.objectspace.space, 'constraints'): if not hasattr(self.objectspace.space, 'constraints'):
self.objectspace.space.constraints = self.objectspace.constraints() self.objectspace.space.constraints = self.objectspace.constraints(variable.xmlfiles)
self.objectspace.space.constraints.namespace = namespace self.objectspace.space.constraints.namespace = namespace
if not hasattr(self.objectspace.space.constraints, 'check'): if not hasattr(self.objectspace.space.constraints, 'check'):
self.objectspace.space.constraints.check = [] self.objectspace.space.constraints.check = []
@ -542,14 +547,14 @@ class VariableAnnotator:
def convert_auto_freeze(self): # pylint: disable=C0111 def convert_auto_freeze(self): # pylint: disable=C0111
def _convert_auto_freeze(variable, namespace): def _convert_auto_freeze(variable, namespace):
if variable.auto_freeze: if variable.auto_freeze:
new_condition = self.objectspace.condition() new_condition = self.objectspace.condition(variable.xmlfiles)
new_condition.name = 'auto_hidden_if_not_in' new_condition.name = 'auto_hidden_if_not_in'
new_condition.namespace = namespace new_condition.namespace = namespace
new_condition.source = FREEZE_AUTOFREEZE_VARIABLE new_condition.source = FREEZE_AUTOFREEZE_VARIABLE
new_param = self.objectspace.param() new_param = self.objectspace.param(variable.xmlfiles)
new_param.text = 'oui' new_param.text = 'oui'
new_condition.param = [new_param] new_condition.param = [new_param]
new_target = self.objectspace.target() new_target = self.objectspace.target(variable.xmlfiles)
new_target.type = 'variable' new_target.type = 'variable'
path = variable.namespace + '.' + normalize_family(family.name) + '.' + variable.name path = variable.namespace + '.' + normalize_family(family.name) + '.' + variable.name
new_target.name = path new_target.name = path
@ -583,7 +588,8 @@ class VariableAnnotator:
subpath = self.objectspace.paths.get_variable_path(separator.name, subpath = self.objectspace.paths.get_variable_path(separator.name,
separator.namespace, separator.namespace,
) )
raise DictConsistencyError(_('{} already has a separator').format(subpath)) xmlfiles = self.objectspace.display_xmlfiles(separator.xmlfiles)
raise DictConsistencyError(_(f'{subpath} already has a separator in {xmlfiles}'))
option.separator = separator.text option.separator = separator.text
del family.separators del family.separators
@ -622,7 +628,8 @@ class ConstraintAnnotator:
remove_indexes = [] remove_indexes = []
for check_idx, check in enumerate(self.objectspace.space.constraints.check): for check_idx, check in enumerate(self.objectspace.space.constraints.check):
if not check.name in self.functions: if not check.name in self.functions:
raise DictConsistencyError(_('cannot find check function {}').format(check.name)) xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'cannot find check function "{check.name}" in {xmlfiles}'))
if hasattr(check, 'param'): if hasattr(check, 'param'):
param_option_indexes = [] param_option_indexes = []
for idx, param in enumerate(check.param): for idx, param in enumerate(check.param):
@ -630,7 +637,8 @@ class ConstraintAnnotator:
if param.optional is True: if param.optional is True:
param_option_indexes.append(idx) param_option_indexes.append(idx)
else: else:
raise DictConsistencyError(_(f'unknown param {param.text} in check')) xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'cannot find check param "{param.text}" in {xmlfiles}'))
if param.type != 'variable': if param.type != 'variable':
param.notraisepropertyerror = None param.notraisepropertyerror = None
param_option_indexes = list(set(param_option_indexes)) param_option_indexes = list(set(param_option_indexes))
@ -766,7 +774,7 @@ class ConstraintAnnotator:
for listvar in listvars: for listvar in listvars:
variable = self.objectspace.paths.get_variable_obj(listvar) variable = self.objectspace.paths.get_variable_obj(listvar)
type_ = 'variable' type_ = 'variable'
new_target = self.objectspace.target() new_target = self.objectspace.target(variable.xmlfiles)
new_target.type = type_ new_target.type = type_
new_target.name = listvar new_target.name = listvar
new_target.index = target.index new_target.index = target.index
@ -891,7 +899,7 @@ class ConstraintAnnotator:
if hasattr(leader_or_variable, actions[0]) and getattr(leader_or_variable, actions[0]) is True: if hasattr(leader_or_variable, actions[0]) and getattr(leader_or_variable, actions[0]) is True:
continue continue
for idx, action in enumerate(actions): for idx, action in enumerate(actions):
prop = self.objectspace.property_() prop = self.objectspace.property_(leader_or_variable.xmlfiles)
prop.type = 'calculation' prop.type = 'calculation'
prop.inverse = inverse prop.inverse = inverse
prop.source = condition.source prop.source = condition.source
@ -924,7 +932,7 @@ class ConstraintAnnotator:
} }
choices = [] choices = []
for value in values: for value in values:
choice = self.objectspace.choice() choice = self.objectspace.choice(variable.xmlfiles)
try: try:
if value is not None: if value is not None:
choice.name = CONVERSION.get(type_, str)(value) choice.name = CONVERSION.get(type_, str)(value)
@ -948,7 +956,7 @@ class ConstraintAnnotator:
if cvalue not in choices: if cvalue not in choices:
raise DictConsistencyError(_('value "{}" of variable "{}" is not in list of all expected values ({})').format(value.name, variable.name, choices)) raise DictConsistencyError(_('value "{}" of variable "{}" is not in list of all expected values ({})').format(value.name, variable.name, choices))
else: else:
new_value = self.objectspace.value() new_value = self.objectspace.value(variable.xmlfiles)
new_value.name = choices[0] new_value.name = choices[0]
new_value.type = type_ new_value.type = type_
variable.value = [new_value] variable.value = [new_value]
@ -973,7 +981,7 @@ class ConstraintAnnotator:
else: else:
raise DictConsistencyError(_(f'unknown parameter {param.text} in check "valid_entier" for variable {check.target}')) raise DictConsistencyError(_(f'unknown parameter {param.text} in check "valid_entier" for variable {check.target}'))
else: else:
check_ = self.objectspace.check() check_ = self.objectspace.check(variable.xmlfiles)
if name == 'valid_differ': if name == 'valid_differ':
name = 'valid_not_equal' name = 'valid_not_equal'
elif name == 'valid_network_netmask': elif name == 'valid_network_netmask':
@ -1026,7 +1034,8 @@ class ConstraintAnnotator:
) )
if suffix is not None: if suffix is not None:
raise DictConsistencyError(_(f'Cannot add fill function to "{fill.target}" only with the suffix "{suffix}"')) raise DictConsistencyError(_(f'Cannot add fill function to "{fill.target}" only with the suffix "{suffix}"'))
value = self.objectspace.value() variable = self.objectspace.paths.get_variable_obj(fill.target)
value = self.objectspace.value(variable.xmlfiles)
value.type = 'calculation' value.type = 'calculation'
value.name = fill.name value.name = fill.name
if hasattr(fill, 'param'): if hasattr(fill, 'param'):
@ -1058,7 +1067,6 @@ class ConstraintAnnotator:
for param_idx in param_to_delete: for param_idx in param_to_delete:
fill.param.pop(param_idx) fill.param.pop(param_idx)
value.param = fill.param value.param = fill.param
variable = self.objectspace.paths.get_variable_obj(fill.target)
variable.value = [value] variable.value = [value]
del self.objectspace.space.constraints.fill del self.objectspace.space.constraints.fill
@ -1066,6 +1074,7 @@ class ConstraintAnnotator:
if hasattr(self.objectspace.space.constraints, 'index'): if hasattr(self.objectspace.space.constraints, 'index'):
del self.objectspace.space.constraints.index del self.objectspace.space.constraints.index
del self.objectspace.space.constraints.namespace del self.objectspace.space.constraints.namespace
del self.objectspace.space.constraints.xmlfiles
if vars(self.objectspace.space.constraints): if vars(self.objectspace.space.constraints):
raise Exception('constraints again?') raise Exception('constraints again?')
del self.objectspace.space.constraints del self.objectspace.space.constraints
@ -1126,7 +1135,7 @@ class FamilyAnnotator:
# 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'
if not hasattr(variable, 'value') and variable.type == 'boolean': if not hasattr(variable, 'value') and variable.type == 'boolean':
new_value = self.objectspace.value() 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]

View file

@ -59,7 +59,10 @@ CONVERT_EXPORT = {'Leadership': 'leader',
# _____________________________________________________________________________ # _____________________________________________________________________________
# special types definitions for the Object Space's internal representation # special types definitions for the Object Space's internal representation
class RootCreoleObject: class RootCreoleObject:
"" def __init__(self, xmlfiles):
if not isinstance(xmlfiles, list):
xmlfiles = [xmlfiles]
self.xmlfiles = xmlfiles
class CreoleObjSpace: class CreoleObjSpace:
@ -157,12 +160,14 @@ class CreoleObjSpace:
self.fill_removed = [] self.fill_removed = []
self.check_removed = [] self.check_removed = []
self.condition_removed = [] self.condition_removed = []
self.xml_parse_document(document, self.xml_parse_document(xmlfile,
document,
self.space, self.space,
namespace, namespace,
) )
def xml_parse_document(self, def xml_parse_document(self,
xmlfile,
document, document,
space, space,
namespace, namespace,
@ -179,7 +184,7 @@ class CreoleObjSpace:
continue continue
if child.tag == 'family': if child.tag == 'family':
if child.attrib['name'] in family_names: if child.attrib['name'] in family_names:
raise DictConsistencyError(_('Family {} is set several times').format(child.attrib['name'])) raise DictConsistencyError(_(f'Family "{child.attrib["name"]}" is set several times in "{xmlfile}"'))
family_names.append(child.attrib['name']) family_names.append(child.attrib['name'])
if child.tag == 'variables': if child.tag == 'variables':
child.attrib['name'] = namespace child.attrib['name'] = namespace
@ -188,7 +193,8 @@ class CreoleObjSpace:
continue continue
# variable objects creation # variable objects creation
try: try:
variableobj = self.generate_variableobj(child, variableobj = self.generate_variableobj(xmlfile,
child,
space, space,
namespace, namespace,
) )
@ -197,7 +203,8 @@ class CreoleObjSpace:
self.set_text_to_obj(child, self.set_text_to_obj(child,
variableobj, variableobj,
) )
self.set_xml_attributes_to_obj(child, self.set_xml_attributes_to_obj(xmlfile,
child,
variableobj, variableobj,
) )
self.variableobj_tree_visitor(child, self.variableobj_tree_visitor(child,
@ -215,12 +222,14 @@ class CreoleObjSpace:
child, child,
) )
if list(child) != []: if list(child) != []:
self.xml_parse_document(child, self.xml_parse_document(xmlfile,
child,
variableobj, variableobj,
namespace, namespace,
) )
def generate_variableobj(self, def generate_variableobj(self,
xmlfile,
child, child,
space, space,
namespace, namespace,
@ -228,9 +237,10 @@ class CreoleObjSpace:
""" """
instanciates or creates Creole Object Subspace objects instanciates or creates Creole Object Subspace objects
""" """
variableobj = getattr(self, child.tag)() variableobj = getattr(self, child.tag)(xmlfile)
if isinstance(variableobj, self.Redefinable): if isinstance(variableobj, self.Redefinable):
variableobj = self.create_or_update_redefinable_object(child.attrib, variableobj = self.create_or_update_redefinable_object(xmlfile,
child.attrib,
space, space,
child, child,
namespace, namespace,
@ -248,6 +258,7 @@ class CreoleObjSpace:
return variableobj return variableobj
def create_or_update_redefinable_object(self, def create_or_update_redefinable_object(self,
xmlfile,
subspace, subspace,
space, space,
child, child,
@ -281,15 +292,17 @@ class CreoleObjSpace:
name = child.text name = child.text
else: else:
name = subspace['name'] name = subspace['name']
if self.is_already_exists(name, existed_var = self.is_already_exists(name,
space, space,
child, child,
namespace, namespace,
): )
if existed_var:
default_redefine = child.tag in FORCE_REDEFINABLES default_redefine = child.tag in FORCE_REDEFINABLES
redefine = self.convert_boolean(subspace.get('redefine', default_redefine)) redefine = self.convert_boolean(subspace.get('redefine', default_redefine))
exists = self.convert_boolean(subspace.get('exists', True)) exists = self.convert_boolean(subspace.get('exists', True))
if redefine is True: if redefine is True:
existed_var.xmlfiles.append(xmlfile)
return self.translate_in_space(name, return self.translate_in_space(name,
space, space,
child, child,
@ -297,12 +310,21 @@ class CreoleObjSpace:
) )
elif exists is False: elif exists is False:
raise SpaceObjShallNotBeUpdated() raise SpaceObjShallNotBeUpdated()
raise DictConsistencyError(_(f'Already present in another XML file, {name} cannot be re-created')) xmlfiles = self.display_xmlfiles(existed_var.xmlfiles)
raise DictConsistencyError(_(f'"{child.tag}" named "{name}" cannot be re-created in "{xmlfile}", already defined in {xmlfiles}'))
redefine = self.convert_boolean(subspace.get('redefine', False)) redefine = self.convert_boolean(subspace.get('redefine', False))
exists = self.convert_boolean(subspace.get('exists', False)) exists = self.convert_boolean(subspace.get('exists', False))
if redefine is False or exists is True: if redefine is False or exists is True:
return getattr(self, child.tag)() return getattr(self, child.tag)(xmlfile)
raise DictConsistencyError(_(f'Redefined object: {name} does not exist yet')) raise DictConsistencyError(_(f'Redefined object in "{xmlfile}": "{name}" does not exist yet'))
def display_xmlfiles(self,
xmlfiles: list,
) -> str:
if len(xmlfiles) == 1:
return '"' + xmlfiles[0] + '"'
else:
return '"' + '", "'.join(xmlfiles[:-1]) + '"' + ' and ' + '"' + xmlfiles[-1] + '"'
def create_tree_structure(self, def create_tree_structure(self,
space, space,
@ -329,16 +351,25 @@ class CreoleObjSpace:
raise OperationError(_("Creole object {} " raise OperationError(_("Creole object {} "
"has a wrong type").format(type(variableobj))) "has a wrong type").format(type(variableobj)))
def is_already_exists(self, name, space, child, namespace): def is_already_exists(self,
name: str,
space: str,
child,
namespace: str,
):
if isinstance(space, self.family): # pylint: disable=E1101 if isinstance(space, self.family): # pylint: disable=E1101
if namespace != Config['variable_namespace']: if namespace != Config['variable_namespace']:
name = space.path + '.' + name name = space.path + '.' + name
return self.paths.path_is_defined(name) if self.paths.path_is_defined(name):
return self.paths.get_variable_obj(name)
return
if child.tag == 'family': if child.tag == 'family':
norm_name = normalize_family(name) norm_name = normalize_family(name)
else: else:
norm_name = name norm_name = name
return norm_name in getattr(space, child.tag, {}) children = getattr(space, child.tag, {})
if norm_name in children:
return children[norm_name]
def convert_boolean(self, value): # pylint: disable=R0201 def convert_boolean(self, value): # pylint: disable=R0201
"""Boolean coercion. The Creole XML may contain srings like `True` or `False` """Boolean coercion. The Creole XML may contain srings like `True` or `False`
@ -451,6 +482,7 @@ class CreoleObjSpace:
variableobj.text = text variableobj.text = text
def set_xml_attributes_to_obj(self, def set_xml_attributes_to_obj(self,
xmlfile,
child, child,
variableobj, variableobj,
): ):
@ -463,7 +495,8 @@ class CreoleObjSpace:
# UNREDEFINABLE concerns only 'variable' node so we can fix name # UNREDEFINABLE concerns only 'variable' node so we can fix name
# to child.attrib['name'] # to child.attrib['name']
name = child.attrib['name'] name = child.attrib['name']
raise DictConsistencyError(_(f'cannot redefine attribute {attr} for variable {name}')) xmlfiles = self.display_xmlfiles(variableobj.xmlfiles[:-1])
raise DictConsistencyError(_(f'cannot redefine attribute "{attr}" for variable "{name}" in "{xmlfile}", already defined in {xmlfiles}'))
if attr in self.booleans_attributs: if attr in self.booleans_attributs:
val = self.convert_boolean(val) val = self.convert_boolean(val)
if not (attr == 'name' and getattr(variableobj, 'name', None) != None): if not (attr == 'name' and getattr(variableobj, 'name', None) != None):

View file

@ -0,0 +1,27 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services/>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="string" description="No change">
<value>b</value>
</variable>
<variable name="int" type="number" description="No change"/>
</family>
<separators/>
</variables>
<constraints>
<check name="unknown" target="int">
<param name="mini">0</param>
<param name="maxi">100</param>
</check>
</constraints>
<help/>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View file

@ -0,0 +1,26 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services/>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="string" description="No change">
<value>b</value>
</variable>
</family>
<separators/>
</variables>
<constraints>
<check name="valid_differ" target="mode_conteneur_actif">
<param type="variable">int3</param>
</check>
</constraints>
<help/>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->