From 06bb8f8fadff96499a7d2632e7044bc4de15925d Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Mon, 30 Sep 2024 17:59:25 +0200 Subject: [PATCH] feat: better debugging --- src/rougail/error.py | 9 +-------- src/rougail/object_model.py | 20 +++++++++++++++----- src/rougail/tiramisu.py | 19 ++++++++++++++----- src/rougail/utils.py | 15 +++++++++++---- 4 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/rougail/error.py b/src/rougail/error.py index 53f8b3f10..a1c03fd8c 100644 --- a/src/rougail/error.py +++ b/src/rougail/error.py @@ -83,11 +83,4 @@ class NotFoundError(Exception): ## ---- specific exceptions ---- class VariableCalculationDependencyError(Exception): - """When an attribute is set, and - the target of this attribute doesn't exists. - """ - def __init__(self, msg, errno, xmlfiles): - if xmlfiles: - msg = _(f"{msg} in {display_xmlfiles(xmlfiles)}") - super().__init__(msg) - self.errno = errno + pass diff --git a/src/rougail/object_model.py b/src/rougail/object_model.py index da8536501..82ecdce40 100644 --- a/src/rougail/object_model.py +++ b/src/rougail/object_model.py @@ -293,6 +293,9 @@ class JinjaCalculation(Calculation): "__internal_jinja": jinja_path, "__internal_type": return_type, "__internal_multi": multi, + "__internal_files": self.xmlfiles, + "__internal_attribute": self.attribute_name, + "__internal_variable": self.path, }, } if self.default_values: @@ -461,6 +464,8 @@ class _VariableCalculation(Calculation): calc_variable_is_multi = True else: calc_variable_is_multi = True + elif suffix and '{{ suffix }}' in suffix: + calc_variable_is_multi = True if needs_multi: if calc_variable_is_multi: if self.inside_list: @@ -473,8 +478,12 @@ class _VariableCalculation(Calculation): msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", it\'s a list' raise DictConsistencyError(msg, 23, self.xmlfiles) elif calc_variable_is_multi: - msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", the variable "{variable.path}" is a multi' - raise DictConsistencyError(msg, 21, self.xmlfiles) + if variable.multi or variable.path.rsplit('.', 1)[0] != self.path.rsplit('.', 1)[0]: + # it's not a follower or not in same leadership + msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", the variable "{variable.path}" is a multi' + raise DictConsistencyError(msg, 21, self.xmlfiles) + else: + params[None][0]['index'] = {'index': {'type': 'index'}} return params @@ -486,13 +495,12 @@ class VariableCalculation(_VariableCalculation): self, objectspace, ) -> dict: - if self.attribute_name != "default" and self.optional is True: + if self.attribute_name != "default" and self.optional: msg = f'"{self.attribute_name}" variable shall not have an "optional" attribute for variable "{self.variable}"' raise DictConsistencyError(msg, 33, self.xmlfiles) variable, suffix = self.get_variable(objectspace) if not variable and self.optional: - msg = f'the dependent variable was not found "{self.optional}" for attribute "{self.attribute_name}" in variable "{self.path}"' - raise VariableCalculationDependencyError(msg, 90, self.xmlfiles) + raise VariableCalculationDependencyError() params = self.get_params(objectspace, variable, suffix, @@ -728,6 +736,7 @@ class Variable(BaseModel): path: str namespace: Optional[str] version: str + path_prefix: Optional[str] xmlfiles: List[str] = [] model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True) @@ -740,6 +749,7 @@ class SymLink(BaseModel): opt: Variable namespace: Optional[str] version: str + path_prefix: Optional[str] xmlfiles: List[str] = [] model_config = ConfigDict(extra="forbid") diff --git a/src/rougail/tiramisu.py b/src/rougail/tiramisu.py index 40ea9c794..432b0a916 100644 --- a/src/rougail/tiramisu.py +++ b/src/rougail/tiramisu.py @@ -36,7 +36,8 @@ from importlib.util import spec_from_loader as _spec_from_loader, module_from_sp from jinja2 import StrictUndefined, DictLoader from jinja2.sandbox import SandboxedEnvironment from rougail.object_model import CONVERT_OPTION -from tiramisu.error import ValueWarning +from rougail.error import display_xmlfiles +from tiramisu.error import ValueWarning, ConfigError from .utils import normalize_family @@ -66,7 +67,7 @@ def rougail_calc_value(*args, __default_value=None, **kwargs): return values -def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, __default_value=None, **kwargs): +def jinja_to_function(__internal_variable, __internal_attribute, __internal_jinja, __internal_type, __internal_multi, __internal_files, __default_value=None, **kwargs): global ENV, CONVERT_OPTION kw = {} for key, value in kwargs.items(): @@ -77,15 +78,23 @@ def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, __def c_kw = c_kw.setdefault(subkey, {}) c_kw[var] = value else: + if key in kw: + raise ConfigError(f'internal error, multi key for "{key}" in jinja_to_function') kw[key] = value - values = ENV.get_template(__internal_jinja).render(kw, **func).strip() + try: + values = ENV.get_template(__internal_jinja).render(kw, **func).strip() + except Exception as err: + raise ConfigError(f'cannot calculating "{__internal_attribute}" attribute for variable "{__internal_variable}" in {display_xmlfiles(__internal_files)}: {err}') from err convert = CONVERT_OPTION[__internal_type].get('func', str) if __internal_multi: - values = [convert(val) for val in values.split()] + values = [convert(val) for val in values.split('\n') if val != ""] if not values and __default_value is not None: return __default_value return values - values = convert(values) + try: + values = convert(values) + except Exception as err: + raise ConfigError(f'cannot converting "{__internal_attribute}" attribute for variable "{__internal_variable}" in {display_xmlfiles(__internal_files)}: {err}') from err values = values if values != '' and values != 'None' else None if values is None and __default_value is not None: return __default_value diff --git a/src/rougail/utils.py b/src/rougail/utils.py index cf4e30f72..cdb500c58 100644 --- a/src/rougail/utils.py +++ b/src/rougail/utils.py @@ -30,6 +30,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA from typing import List, Union from unicodedata import normalize, combining import re +from itertools import chain from importlib.machinery import SourceFileLoader from importlib.util import spec_from_loader, module_from_spec @@ -116,10 +117,10 @@ def get_jinja_variable_to_param( for g in parsed_content.find_all(Getattr): variables.add(recurse_getattr(g)) except TemplateSyntaxError as err: - msg = _(f'error in jinja "{jinja_text}": {err}') - raise Exception(msg) from err + msg = _(f'error in jinja "{jinja_text}" for the variable "{ current_path }": {err}') + raise DictConsistencyError(msg, 39, xmlfiles) from err variables = list(variables) - variables.sort() + variables.sort(reverse=True) founded_variables = {} unknown_variables = [] for variable_path in variables: @@ -134,7 +135,13 @@ def get_jinja_variable_to_param( if variable and variable.path in objectspace.variables: founded_variables[variable_path] = (suffix, variable) else: - unknown_variables.append(variable_path) + sub_family = variable_path + '.' + for founded_variable in chain(founded_variables, unknown_variables): + if founded_variable.startswith(sub_family): + break + else: + unknown_variables.append(variable_path) + for variable_path in unknown_variables: for v in founded_variables: if get_common_path(v, variable_path) == v: