WIP: Expand the developer documentation #27

Draft
gremond wants to merge 62 commits from develop into developer_docs
4 changed files with 41 additions and 22 deletions
Showing only changes of commit 04bf6a1d38 - Show all commits

View file

@ -83,11 +83,4 @@ class NotFoundError(Exception):
## ---- specific exceptions ---- ## ---- specific exceptions ----
class VariableCalculationDependencyError(Exception): class VariableCalculationDependencyError(Exception):
"""When an attribute is set, and pass
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

View file

@ -293,6 +293,9 @@ class JinjaCalculation(Calculation):
"__internal_jinja": jinja_path, "__internal_jinja": jinja_path,
"__internal_type": return_type, "__internal_type": return_type,
"__internal_multi": multi, "__internal_multi": multi,
"__internal_files": self.xmlfiles,
"__internal_attribute": self.attribute_name,
"__internal_variable": self.path,
}, },
} }
if self.default_values: if self.default_values:
@ -461,6 +464,8 @@ class _VariableCalculation(Calculation):
calc_variable_is_multi = True calc_variable_is_multi = True
else: else:
calc_variable_is_multi = True calc_variable_is_multi = True
elif suffix and '{{ suffix }}' in suffix:
calc_variable_is_multi = True
if needs_multi: if needs_multi:
if calc_variable_is_multi: if calc_variable_is_multi:
if self.inside_list: 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' msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", it\'s a list'
raise DictConsistencyError(msg, 23, self.xmlfiles) raise DictConsistencyError(msg, 23, self.xmlfiles)
elif calc_variable_is_multi: 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' if variable.multi or variable.path.rsplit('.', 1)[0] != self.path.rsplit('.', 1)[0]:
raise DictConsistencyError(msg, 21, self.xmlfiles) # 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 return params
@ -486,13 +495,12 @@ class VariableCalculation(_VariableCalculation):
self, self,
objectspace, objectspace,
) -> dict: ) -> 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}"' msg = f'"{self.attribute_name}" variable shall not have an "optional" attribute for variable "{self.variable}"'
raise DictConsistencyError(msg, 33, self.xmlfiles) raise DictConsistencyError(msg, 33, self.xmlfiles)
variable, suffix = self.get_variable(objectspace) variable, suffix = self.get_variable(objectspace)
if not variable and self.optional: 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()
raise VariableCalculationDependencyError(msg, 90, self.xmlfiles)
params = self.get_params(objectspace, params = self.get_params(objectspace,
variable, variable,
suffix, suffix,
@ -728,6 +736,7 @@ class Variable(BaseModel):
path: str path: str
namespace: Optional[str] namespace: Optional[str]
version: str version: str
path_prefix: Optional[str]
xmlfiles: List[str] = [] xmlfiles: List[str] = []
model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True) model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True)
@ -740,6 +749,7 @@ class SymLink(BaseModel):
opt: Variable opt: Variable
namespace: Optional[str] namespace: Optional[str]
version: str version: str
path_prefix: Optional[str]
xmlfiles: List[str] = [] xmlfiles: List[str] = []
model_config = ConfigDict(extra="forbid") model_config = ConfigDict(extra="forbid")

View file

@ -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 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment from jinja2.sandbox import SandboxedEnvironment
from rougail.object_model import CONVERT_OPTION 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 from .utils import normalize_family
@ -66,7 +67,7 @@ def rougail_calc_value(*args, __default_value=None, **kwargs):
return values 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 global ENV, CONVERT_OPTION
kw = {} kw = {}
for key, value in kwargs.items(): 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 = c_kw.setdefault(subkey, {})
c_kw[var] = value c_kw[var] = value
else: else:
if key in kw:
raise ConfigError(f'internal error, multi key for "{key}" in jinja_to_function')
kw[key] = value 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) convert = CONVERT_OPTION[__internal_type].get('func', str)
if __internal_multi: 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: if not values and __default_value is not None:
return __default_value return __default_value
return values 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 values = values if values != '' and values != 'None' else None
if values is None and __default_value is not None: if values is None and __default_value is not None:
return __default_value return __default_value

View file

@ -30,6 +30,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
from typing import List, Union from typing import List, Union
from unicodedata import normalize, combining from unicodedata import normalize, combining
import re import re
from itertools import chain
from importlib.machinery import SourceFileLoader from importlib.machinery import SourceFileLoader
from importlib.util import spec_from_loader, module_from_spec 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): for g in parsed_content.find_all(Getattr):
variables.add(recurse_getattr(g)) variables.add(recurse_getattr(g))
except TemplateSyntaxError as err: except TemplateSyntaxError as err:
msg = _(f'error in jinja "{jinja_text}": {err}') msg = _(f'error in jinja "{jinja_text}" for the variable "{ current_path }": {err}')
raise Exception(msg) from err raise DictConsistencyError(msg, 39, xmlfiles) from err
variables = list(variables) variables = list(variables)
variables.sort() variables.sort(reverse=True)
founded_variables = {} founded_variables = {}
unknown_variables = [] unknown_variables = []
for variable_path in variables: for variable_path in variables:
@ -134,7 +135,13 @@ def get_jinja_variable_to_param(
if variable and variable.path in objectspace.variables: if variable and variable.path in objectspace.variables:
founded_variables[variable_path] = (suffix, variable) founded_variables[variable_path] = (suffix, variable)
else: 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 variable_path in unknown_variables:
for v in founded_variables: for v in founded_variables:
if get_common_path(v, variable_path) == v: if get_common_path(v, variable_path) == v: