From f9c73783c56bf7d9fc053ade61ec319cf34cd4cf Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Fri, 16 Jan 2026 08:48:46 +0100 Subject: [PATCH] =?UTF-8?q?bump:=20version=201.2.0a56=20=E2=86=92=201.2.0a?= =?UTF-8?q?57?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 + pyproject.toml | 2 +- rougail-base-pyproject.toml | 2 +- rougail-pyproject.toml | 4 +- src/rougail/__version__.py | 2 +- src/rougail/annotator/property.py | 4 +- src/rougail/annotator/variable.py | 4 +- src/rougail/config/__init__.py | 1 + src/rougail/convert/convert.py | 2 +- src/rougail/convert/object_model.py | 157 +++++++++++++---------- src/rougail/convert/tiramisureflector.py | 2 +- tests/test_types.py | 15 +++ 12 files changed, 120 insertions(+), 81 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2983ef3f4..d904e9761 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.2.0a57 (2026-01-16) + +### Fix + +- add transition + ## 1.2.0a56 (2026-01-15) ### Fix diff --git a/pyproject.toml b/pyproject.toml index bae412319..0e5518346 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "rougail" -version = "1.2.0a56" +version = "1.2.0a57" [tool.commitizen] name = "cz_conventional_commits" diff --git a/rougail-base-pyproject.toml b/rougail-base-pyproject.toml index 66715cc38..eb0d026be 100644 --- a/rougail-base-pyproject.toml +++ b/rougail-base-pyproject.toml @@ -4,7 +4,7 @@ requires = ["flit_core >=3.8.0,<4"] [project] name = "rougail-base" -version = "1.2.0a56" +version = "1.2.0a57" authors = [{name = "Emmanuel Garette", email = "gnunux@gnunux.info"}] readme = "README.md" description = "A consistency handling system that was initially designed in the configuration management" diff --git a/rougail-pyproject.toml b/rougail-pyproject.toml index 2df72ac72..11f77a28e 100644 --- a/rougail-pyproject.toml +++ b/rougail-pyproject.toml @@ -4,7 +4,7 @@ requires = ["flit_core >=3.8.0,<4"] [project] name = "rougail" -version = "1.2.0a56" +version = "1.2.0a57" authors = [{name = "Emmanuel Garette", email = "gnunux@gnunux.info"}] description = "A consistency handling system that was initially designed in the configuration management" classifiers = [ @@ -18,7 +18,7 @@ classifiers = [ dependencies = [ "ruamel.yaml ~= 0.18.6", "pydantic ~= 2.9.2", - "rougail-base == 1.2.0a56", + "rougail-base == 1.2.0a57", ] [tool.flit.sdist] diff --git a/src/rougail/__version__.py b/src/rougail/__version__.py index fab3c4696..09fa9569f 100644 --- a/src/rougail/__version__.py +++ b/src/rougail/__version__.py @@ -1 +1 @@ -__version__ = "1.2.0a56" +__version__ = "1.2.0a57" diff --git a/src/rougail/annotator/property.py b/src/rougail/annotator/property.py index c161212a2..7297b688b 100644 --- a/src/rougail/annotator/property.py +++ b/src/rougail/annotator/property.py @@ -124,8 +124,8 @@ class Annotator(Walk): for calculation in frozen: calculation_copy = calculation.model_copy() calculation_copy.attribute_name = "frozen" - calculation_copy.ori_path = calculation_copy.path - calculation_copy.path = path +# calculation_copy.ori_path = calculation_copy.path +# calculation_copy.path = path value.append(calculation_copy) if len(value) == 1: value = value[0] diff --git a/src/rougail/annotator/variable.py b/src/rougail/annotator/variable.py index dff87d4f3..35e5dbc44 100644 --- a/src/rougail/annotator/variable.py +++ b/src/rougail/annotator/variable.py @@ -147,7 +147,7 @@ class Annotator(Walk): # pylint: disable=R0903 variable.type = "integer" elif isinstance(variable.default, VariableCalculation): calculated_variable_path, calculated_variable, identifier = ( - variable.default.get_variable(self.objectspace) + variable.default.get_variable(self.objectspace, variable.path) ) if calculated_variable is not None: self._default_variable_copy_informations( @@ -236,7 +236,7 @@ class Annotator(Walk): # pylint: disable=R0903 variable.default, VariableCalculation ): calculated_variable_path, calculated_variable, identifier = ( - variable.default.get_variable(self.objectspace) + variable.default.get_variable(self.objectspace, variable.path) ) if calculated_variable is not None: if calculated_variable.multi is None: diff --git a/src/rougail/config/__init__.py b/src/rougail/config/__init__.py index 4cd7163b1..08f7e1428 100644 --- a/src/rougail/config/__init__.py +++ b/src/rougail/config/__init__.py @@ -586,6 +586,7 @@ def _rougail_config( tiram_obj = convert.save() optiondescription = {} + print(tiram_obj) exec(tiram_obj, {}, optiondescription) # pylint: disable=W0122 return optiondescription["option_0"], extra_vars diff --git a/src/rougail/convert/convert.py b/src/rougail/convert/convert.py index 00cf4f771..952c7dbf0 100644 --- a/src/rougail/convert/convert.py +++ b/src/rougail/convert/convert.py @@ -989,7 +989,7 @@ class ParserVariable: typ = calculation_object.pop("type") calculation_object["attribute_name"] = attribute - calculation_object["path"] = path +# calculation_object["path"] = path calculation_object["inside_list"] = inside_list calculation_object["version"] = self.version calculation_object["namespace"] = self.namespace diff --git a/src/rougail/convert/object_model.py b/src/rougail/convert/object_model.py index 0ab88d0b1..f1fc9ed27 100644 --- a/src/rougail/convert/object_model.py +++ b/src/rougail/convert/object_model.py @@ -247,10 +247,10 @@ PARAM_TYPES = { class Calculation(BaseModel): - path: str + # path: str inside_list: bool version: str - ori_path: Optional[str] = None + # ori_path: Optional[str] = None default_values: Any = None namespace: Optional[str] warnings: Optional[bool] = None @@ -258,7 +258,7 @@ class Calculation(BaseModel): model_config = ConfigDict(extra="forbid") - def get_params(self, objectspace): + def get_params(self, objectspace, path): if self.warnings is not None and self.attribute_name != "validators": msg = _( '"warnings" are only available with attribute "{self.attribute_name}" for variable "{self.ori_path}"' @@ -266,10 +266,10 @@ class Calculation(BaseModel): raise DictConsistencyError(msg, 83, xmlfiles) if not self.params: return {} - if self.ori_path is None: - path = self.path - else: - path = self.ori_path +# if self.ori_path is None: +# path = self.path +# else: +# path = self.ori_path params = {} for param_obj in self.params: param = param_obj.to_param( @@ -310,21 +310,22 @@ class JinjaCalculation(Calculation): return_type, multi, objectspace, + path, *, add_help=False, params: Optional[dict] = None, ): - variable = objectspace.paths[self.path] - jinja_path = f"{self.attribute_name}_{self.path}" + variable = objectspace.paths[path] + jinja_path = f"{self.attribute_name}_{path}" idx = 0 while jinja_path in objectspace.jinja: - jinja_path = f"{self.attribute_name}_{self.path}_{idx}" + jinja_path = f"{self.attribute_name}_{path}_{idx}" idx += 1 objectspace.jinja[jinja_path] = self.jinja if return_type in RENAME_TYPE: warning = _('the variable "{0}" has a depreciated return_type "{1}", please use "{2}" instead in {3}') warn( - warning.format(self.path, return_type, RENAME_TYPE[return_type], display_xmlfiles(self.xmlfiles)), + warning.format(path, return_type, RENAME_TYPE[return_type], display_xmlfiles(self.xmlfiles)), DeprecationWarning, stacklevel=2, ) @@ -337,7 +338,7 @@ class JinjaCalculation(Calculation): "__internal_multi": multi, "__internal_files": self.xmlfiles, "__internal_attribute": self.attribute_name, - "__internal_variable": self.path, + "__internal_variable": path, }, } if self.default_values: @@ -345,13 +346,13 @@ class JinjaCalculation(Calculation): if add_help: default["help"] = function + "_help" if self.params: - default["params"] |= self.get_params(objectspace) + default["params"] |= self.get_params(objectspace, path) if params: default["params"] |= params - if self.ori_path is None: - path = self.path - else: - path = self.ori_path +# if self.ori_path is None: +# path = self.path +# else: +# path = self.ori_path if self.warnings: default["warnings_only"] = True for sub_variable, identifier, true_path in get_jinja_variable_to_param( @@ -385,33 +386,35 @@ class JinjaCalculation(Calculation): def to_function( self, objectspace, + path, ) -> dict: if self.attribute_name in ["default", "secret_manager"]: if self.return_type: raise Exception("return_type not allowed!") - variable = objectspace.paths[self.path] + variable = objectspace.paths[path] return_type = variable.type if self.inside_list: multi = False - elif self.path in objectspace.followers: - multi = objectspace.multis[self.path] == "submulti" + elif path in objectspace.followers: + multi = objectspace.multis[path] == "submulti" else: - multi = self.path in objectspace.multis + multi = path in objectspace.multis return self._jinja_to_function( "jinja_to_function", return_type, multi, objectspace, + path, ) elif self.attribute_name == "validators": return_type = self.return_type if return_type is None: return_type = "string" if return_type not in ["string", "boolean"]: - if self.ori_path is None: - path = self.path - else: - path = self.ori_path + # if self.ori_path is None: + # path = path + # else: + # path = self.ori_path msg = _( 'variable "{0}" has a calculating "{1}" with an invalid return_type, should be boolean or string, not "{2}"' ).format(path, self.attribute_name, return_type) @@ -421,7 +424,7 @@ class JinjaCalculation(Calculation): if description is None: warning = _('the variable "{0}" has a return_type "{1}", for attribute "{2}" but has not description in {3}') warn( - warning.format(self.path, return_type, self.attribute_name, display_xmlfiles(self.xmlfiles)), + warning.format(path, return_type, self.attribute_name, display_xmlfiles(self.xmlfiles)), RougailWarning, ) self.description = _('value is invalid') @@ -432,17 +435,18 @@ class JinjaCalculation(Calculation): return_type, False, objectspace, - params={'description': description} + path, + params={'description': description}, ) elif self.attribute_name in PROPERTY_ATTRIBUTE: return_type = self.return_type if return_type is None: return_type = "string" if return_type not in ["string", "boolean"]: - if self.ori_path is None: - path = self.path - else: - path = self.ori_path + # if self.ori_path is None: + # path = .path + # else: + # path = self.ori_path msg = _( 'variable "{0}" has a calculating "{1}" with an invalid return_type, should be boolean or string, not "{2}"' ).format(path, self.attribute_name, return_type) @@ -453,6 +457,7 @@ class JinjaCalculation(Calculation): return_type, False, objectspace, + path, add_help=True, params={ None: [self.attribute_name, description], @@ -469,6 +474,7 @@ class JinjaCalculation(Calculation): return_type, not self.inside_list, objectspace, + path, ) elif self.attribute_name == "dynamic": return_type = self.return_type @@ -479,6 +485,7 @@ class JinjaCalculation(Calculation): return_type, True, objectspace, + path, ) raise Exception("hu?") @@ -492,11 +499,12 @@ class _VariableCalculation(Calculation): def get_variable( self, objectspace, + path, ) -> "Variable": - if self.ori_path is None: - path = self.path - else: - path = self.ori_path + # if self.ori_path is None: + # path = self.path + # else: + # path = self.ori_path if self.version != "1.0" and objectspace.paths.regexp_relative.search( self.variable ): @@ -521,11 +529,11 @@ class _VariableCalculation(Calculation): if isinstance(variable, objectspace.family): msg = _( 'a variable "{0}" is needs in attribute "{1}" for "{2}" but it\'s a family' - ).format(variable_full_path, self.attribute_name, self.path) + ).format(variable_full_path, self.attribute_name, path) raise DictConsistencyError(msg, 47, self.xmlfiles) else: msg = _('unknown object "{0}" in attribute "{1}" for "{2}"').format( - variable, self.attribute_name, self.path + variable, self.attribute_name, path ) raise DictConsistencyError(msg, 48, self.xmlfiles) return variable_full_path, variable, identifier @@ -533,6 +541,7 @@ class _VariableCalculation(Calculation): def get_params( self, objectspace, + path, variable_in_calculation_path: str, variable_in_calculation: "Variable", variable_in_calculation_identifier: Optional[str], @@ -540,10 +549,10 @@ class _VariableCalculation(Calculation): ): if not variable_in_calculation: if not objectspace.force_optional: - if self.ori_path is None: - path = self.path - else: - path = self.ori_path + # if self.ori_path is None: + # path = self.path + # else: + # path = self.ori_path msg = _( 'variable "{0}" has an attribute "{1}" calculated with the unknown variable "{2}"' ).format(path, self.attribute_name, self.variable) @@ -567,23 +576,23 @@ class _VariableCalculation(Calculation): if self.allow_none: params["allow_none"] = True self.check_multi( - objectspace, variable_in_calculation_path, variable_in_calculation + objectspace, path, variable_in_calculation_path, variable_in_calculation ) - if self.path in objectspace.followers: - multi = objectspace.multis[self.path] == "submulti" + if path in objectspace.followers: + multi = objectspace.multis[path] == "submulti" else: - multi = self.path in objectspace.multis + multi = path in objectspace.multis if multi and not self.inside_list: params["__internal_multi"] = True return params def check_multi( - self, objectspace, variable_in_calculation_path, variable_in_calculation + self, objectspace, path, variable_in_calculation_path, variable_in_calculation ): - if self.ori_path is None: - path = self.path - else: - path = self.ori_path + # if self.ori_path is None: + # path = self.path + # else: + # path = self.ori_path local_variable = objectspace.paths[path] local_variable_multi, variable_in_calculation_multi = ( calc_multi_for_type_variable( @@ -696,14 +705,14 @@ class _VariableCalculation(Calculation): ) raise DictConsistencyError(msg, 18, self.xmlfiles) - def get_default_value_optional(self, objectspace, default): + def get_default_value_optional(self, objectspace, path, default): if self.attribute_name == "default": if self.inside_list: expected_multiple_value = False - elif self.path in objectspace.followers: - expected_multiple_value = objectspace.multis[self.path] == "submulti" + elif path in objectspace.followers: + expected_multiple_value = objectspace.multis[path] == "submulti" else: - expected_multiple_value = self.path in objectspace.multis + expected_multiple_value = path in objectspace.multis elif self.attribute_name in PROPERTY_ATTRIBUTE: expected_multiple_value = False else: @@ -718,7 +727,7 @@ class _VariableCalculation(Calculation): msg = _( 'the variable "{0}" is not waiting for a list as "{1}" but the attribute "default" is a list ("{2}")' ) - msg = msg.format(self.path, self.attribute_name, default) + msg = msg.format(path, self.attribute_name, default) raise DictConsistencyError(msg, 77, self.xmlfiles) return default @@ -731,6 +740,7 @@ class VariableCalculation(_VariableCalculation): def to_function( self, objectspace, + path, ) -> dict: if ( self.attribute_name != "default" @@ -745,7 +755,7 @@ class VariableCalculation(_VariableCalculation): variable_in_calculation_path, variable_in_calculation, variable_in_calculation_identifier, - ) = self.get_variable(objectspace) + ) = self.get_variable(objectspace, path) if not variable_in_calculation and ( self.optional or objectspace.force_optional ): @@ -755,16 +765,17 @@ class VariableCalculation(_VariableCalculation): return self.default_values raise VariableCalculationDependencyError() if variable_in_calculation and self.attribute_name == "default": - local_variable = objectspace.paths[self.path] + local_variable = objectspace.paths[path] if CONVERT_OPTION.get(local_variable.type, {}).get( "func", str ) != CONVERT_OPTION.get(variable_in_calculation.type, {}).get("func", str): msg = _( 'variable "{0}" has a default value calculated with "{1}" which has incompatible type' - ).format(self.path, self.variable) + ).format(path, self.variable) raise DictConsistencyError(msg, 67, self.xmlfiles) params = self.get_params( objectspace, + path, variable_in_calculation_path, variable_in_calculation, variable_in_calculation_identifier, @@ -785,12 +796,13 @@ class VariablePropertyCalculation(_VariableCalculation): def to_function( self, objectspace, + path, ) -> dict: ( variable_in_calculation_path, variable_in_calculation, variable_in_calculation_identifier, - ) = self.get_variable(objectspace) + ) = self.get_variable(objectspace, path) if ( # self.default is not undefined and not variable_in_calculation @@ -804,11 +816,12 @@ class VariablePropertyCalculation(_VariableCalculation): msg = _( 'the variable "{0}" is waiting for a boolean as "{1}" but the attribute "default" is not a boolean ("{2}")' ) - msg = msg.format(self.path, self.attribute_name, default) + msg = msg.format(path, self.attribute_name, default) raise DictConsistencyError(msg, 79, self.xmlfiles) return self.get_default_value_optional(objectspace, default) params = self.get_params( objectspace, + path, variable_in_calculation_path, variable_in_calculation, variable_in_calculation_identifier, @@ -825,12 +838,12 @@ class VariablePropertyCalculation(_VariableCalculation): if self.version == "1.0": msg = _( '"when" is not allowed in format version 1.0 for attribute "{0}" for variable "{1}"' - ).format(self.attribute_name, self.path) + ).format(self.attribute_name, path) raise DictConsistencyError(msg, 103, variable.xmlfiles) if self.when_not is not undefined: msg = _( 'the variable "{0}" has an invalid attribute "{1}", "when" and "when_not" cannot set together' - ).format(self.path, self.attribute_name) + ).format(path, self.attribute_name) raise DictConsistencyError(msg, 31, variable.xmlfiles) when = self.when inverse = False @@ -838,7 +851,7 @@ class VariablePropertyCalculation(_VariableCalculation): if self.version == "1.0": msg = _( '"when_not" is not allowed in format version 1.0 for attribute "{0}" for variable "{1}"' - ).format(self.attribute_name, self.path) + ).format(self.attribute_name, path) raise DictConsistencyError(msg, 104, variable.xmlfiles) when = self.when_not inverse = True @@ -849,7 +862,7 @@ class VariablePropertyCalculation(_VariableCalculation): if variable.type != "boolean": msg = _( '"when" or "when_not" is mandatory for the not boolean variable "{0}" in attribute "{1}"' - ).format(self.path, self.attribute_name) + ).format(path, self.attribute_name) raise DictConsistencyError(msg, 106, variable.xmlfiles) when = True inverse = False @@ -872,6 +885,7 @@ class InformationCalculation(Calculation): def to_function( self, objectspace, + path, ) -> dict: params = { None: [ @@ -882,10 +896,10 @@ class InformationCalculation(Calculation): ] } if self.variable: - if self.ori_path is None: - path = self.path - else: - path = self.ori_path + # if self.ori_path is None: + # path = self.path + # else: + # path = self.ori_path variable, identifier = objectspace.paths.get_with_dynamic( self.variable, path, @@ -931,6 +945,7 @@ class IdentifierCalculation(_IdentifierCalculation): def to_function( self, objectspace, + path, ) -> dict: identifier = {"type": "identifier"} if self.identifier is not None: @@ -992,11 +1007,12 @@ class IndexCalculation(Calculation): def to_function( self, objectspace, + path, ) -> dict: - if self.path not in objectspace.followers: + if path not in objectspace.followers: msg = _( 'the variable "{0}" is not a follower, so cannot have index type for "{1}"' - ).format(self.path, self.attribute_name) + ).format(path, self.attribute_name) raise DictConsistencyError(msg, 60, self.xmlfiles) return { "function": "calc_value", @@ -1011,6 +1027,7 @@ class NamespaceCalculation(Calculation): def to_function( self, objectspace, + path, ) -> dict: namespace = self.namespace if namespace: diff --git a/src/rougail/convert/tiramisureflector.py b/src/rougail/convert/tiramisureflector.py index a2e51c295..f41522694 100644 --- a/src/rougail/convert/tiramisureflector.py +++ b/src/rougail/convert/tiramisureflector.py @@ -384,7 +384,7 @@ class Common: function, ) -> str: """Generate calculated value""" - child = function.to_function(self.objectspace) + child = function.to_function(self.objectspace, self.elt.path) if isinstance(child, str): return self.convert_str(child) elif not isinstance(child, dict): diff --git a/tests/test_types.py b/tests/test_types.py index 9f60e1989..ce0e7f028 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -43,6 +43,21 @@ def type_variable(test_name): with variables_file.open('r') as fh: loaded_configuration = load(fh) assert loaded_configuration == loads(dumps(configuration)), f"error in file {variables_file}" + # + print('--------------') + print('--------------') + print('--------------') + print(config.value.get()) + config.property.read_write() + print(config.value.get()) + variables_file = result / "variables_rw.json" + configuration = dict(config_to_dict(config.value.get())) + if not variables_file.is_file(): + with variables_file.open('w') as fh: + dump(configuration, fh, indent=4) + with variables_file.open('r') as fh: + loaded_configuration = load(fh) + assert loaded_configuration == loads(dumps(configuration)), f"error in file {variables_file}" def test_type_variable():