From 086667d7a432e8a33124b7021bb38613958bcaca Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Tue, 22 Oct 2024 13:54:16 +0200 Subject: [PATCH] feat: suffix to identifier --- src/rougail/object_model.py | 88 ++++++++++++++++---------------- src/rougail/tiramisu.py | 35 +++++++------ src/rougail/tiramisureflector.py | 35 +++++++++---- src/rougail/utils.py | 6 +-- 4 files changed, 91 insertions(+), 73 deletions(-) diff --git a/src/rougail/object_model.py b/src/rougail/object_model.py index 0cb3ffbf3..7ff25b128 100644 --- a/src/rougail/object_model.py +++ b/src/rougail/object_model.py @@ -137,16 +137,16 @@ class VariableParam(Param): optional: bool = False -class SuffixParam(Param): +class IdentifierParam(Param): type: str - suffix: Optional[int] = None + identifier: Optional[int] = None def __init__( self, **kwargs, ) -> None: if not kwargs["family_is_dynamic"]: - msg = f'suffix parameter for "{kwargs["attribute"]}" in "{kwargs["path"]}" cannot be set none dynamic family' + msg = f'identifier parameter for "{kwargs["attribute"]}" in "{kwargs["path"]}" cannot be set none dynamic family' raise DictConsistencyError(msg, 10, kwargs["xmlfiles"]) super().__init__(**kwargs) @@ -174,7 +174,7 @@ class IndexParam(Param): PARAM_TYPES = { "any": AnyParam, "variable": VariableParam, - "suffix": SuffixParam, + "identifier": IdentifierParam, "information": InformationParam, "index": IndexParam, } @@ -209,7 +209,7 @@ class Calculation(BaseModel): path = self.path else: path = self.ori_path - variable, suffix = objectspace.paths.get_with_dynamic( + variable, identifier = objectspace.paths.get_with_dynamic( param["variable"], self.path_prefix, path, @@ -225,15 +225,15 @@ class Calculation(BaseModel): if not isinstance(variable, objectspace.variable): raise Exception("pfff it's a family") param["variable"] = variable - if suffix: - param["suffix"] = suffix + if identifier: + param["identifier"] = identifier if param.get("type") == "information": if param["variable"]: if self.ori_path is None: path = self.path else: path = self.ori_path - variable, suffix = objectspace.paths.get_with_dynamic( + variable, identifier = objectspace.paths.get_with_dynamic( param["variable"], self.path_prefix, path, @@ -245,7 +245,7 @@ class Calculation(BaseModel): msg = f'cannot find variable "{param["variable"]}" defined in "{self.attribute_name}" for "{self.path}"' raise DictConsistencyError(msg, 14, self.xmlfiles) param["variable"] = variable - if suffix: + if identifier: msg = f'variable "{param["variable"]}" defined in "{self.attribute_name}" for "{self.path}" is a dynamic variable' raise DictConsistencyError(msg, 15, self.xmlfiles) else: @@ -311,7 +311,7 @@ class JinjaCalculation(Calculation): path = self.path else: path = self.ori_path - for sub_variable, suffix, true_path in get_jinja_variable_to_param( + for sub_variable, identifier, true_path in get_jinja_variable_to_param( path, self.jinja, objectspace, @@ -333,8 +333,8 @@ class JinjaCalculation(Calculation): "type": "variable", "variable": sub_variable, } - if suffix: - default["params"][true_path]["suffix"] = suffix + if identifier: + default["params"][true_path]["identifier"] = identifier return default def to_function( @@ -410,7 +410,7 @@ class _VariableCalculation(Calculation): path = self.path else: path = self.ori_path - variable, suffix = objectspace.paths.get_with_dynamic( + variable, identifier = objectspace.paths.get_with_dynamic( self.variable, self.path_prefix, path, @@ -421,13 +421,13 @@ class _VariableCalculation(Calculation): if variable and not isinstance(variable, objectspace.variable): # FIXME remove the pfff raise Exception("pfff it's a family") - return variable, suffix + return variable, identifier def get_params( self, objectspace, variable: "Variable", - suffix: Optional[str], + identifier: Optional[str], *, needs_multi: Optional[bool] = None, ): @@ -439,8 +439,8 @@ class _VariableCalculation(Calculation): "variable": variable, "propertyerror": self.propertyerror, } - if suffix: - param["suffix"] = suffix + if identifier: + param["identifier"] = identifier params = {None: [param]} if self.default_values: params["__default_value"] = self.default_values @@ -454,7 +454,7 @@ class _VariableCalculation(Calculation): calc_variable_is_multi = variable.path in objectspace.multis if not calc_variable_is_multi: if variable.path in objectspace.paths._dynamics and ( - suffix is None or suffix[-1] is None + identifier is None or identifier[-1] is None ): self_dyn_path = objectspace.paths._dynamics.get(self.path) if self_dyn_path is not None: @@ -465,7 +465,7 @@ class _VariableCalculation(Calculation): calc_variable_is_multi = True else: calc_variable_is_multi = True - elif suffix and '{{ suffix }}' in suffix: + elif identifier and '{{ identifier }}' in identifier: calc_variable_is_multi = True if needs_multi: if calc_variable_is_multi: @@ -499,12 +499,12 @@ class VariableCalculation(_VariableCalculation): 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) + variable, identifier = self.get_variable(objectspace) if not variable and self.optional: raise VariableCalculationDependencyError() params = self.get_params(objectspace, variable, - suffix, + identifier, ) return { "function": "calc_value", @@ -521,10 +521,10 @@ class VariablePropertyCalculation(_VariableCalculation): self, objectspace, ) -> dict: - variable, suffix = self.get_variable(objectspace) + variable, identifier = self.get_variable(objectspace) params = self.get_params(objectspace, variable, - suffix, + identifier, needs_multi=False,) variable = params[None][0]["variable"] if self.when is not undefined: @@ -579,7 +579,7 @@ class InformationCalculation(Calculation): path = self.path else: path = self.ori_path - variable, suffix = objectspace.paths.get_with_dynamic( + variable, identifier = objectspace.paths.get_with_dynamic( self.variable, self.path_prefix, path, @@ -587,7 +587,7 @@ class InformationCalculation(Calculation): self.namespace, self.xmlfiles, ) - if variable is None or suffix is not None: + if variable is None or identifier is not None: raise Exception("pfff") params[None][0]["variable"] = variable if self.default_values: @@ -598,33 +598,33 @@ class InformationCalculation(Calculation): } -class _SuffixCalculation(Calculation): - suffix: Optional[int] = None +class _IdentifierCalculation(Calculation): + identifier: Optional[int] = None - def get_suffix(self) -> dict: - suffix = {"type": "suffix"} - if self.suffix is not None: - suffix["suffix"] = self.suffix - return suffix + def get_identifier(self) -> dict: + identifier = {"type": "identifier"} + if self.identifier is not None: + identifier["identifier"] = self.identifier + return identifier -class SuffixCalculation(_SuffixCalculation): +class IdentifierCalculation(_IdentifierCalculation): attribute_name: Literal["default", "choice", "dynamic"] def to_function( self, objectspace, ) -> dict: - suffix = {"type": "suffix"} - if self.suffix is not None: - suffix["suffix"] = self.suffix + identifier = {"type": "identifier"} + if self.identifier is not None: + identifier["identifier"] = self.identifier return { "function": "calc_value", - "params": {None: [self.get_suffix()]}, + "params": {None: [self.get_identifier()]}, } -class SuffixPropertyCalculation(_SuffixCalculation): +class IdentifierPropertyCalculation(_IdentifierCalculation): attribute_name: Literal[*PROPERTY_ATTRIBUTE] when: Any = undefined when_not: Any = undefined @@ -638,7 +638,7 @@ class SuffixPropertyCalculation(_SuffixCalculation): raise DictConsistencyError(msg, 105, variable.xmlfiles) if self.when is not undefined: if self.when_not is not undefined: - msg = f'the suffix has an invalid attribute "{self.attribute_name}", when and when_not cannot set together' + msg = f'the identifier has an invalid attribute "{self.attribute_name}", when and when_not cannot set together' raise DictConsistencyError(msg, 35, variable.xmlfiles) when = self.when inverse = False @@ -646,9 +646,9 @@ class SuffixPropertyCalculation(_SuffixCalculation): when = self.when_not inverse = True else: - msg = f'the suffix has an invalid attribute "{self.attribute_name}", when and when_not cannot set together' + msg = f'the identifier has an invalid attribute "{self.attribute_name}", when and when_not cannot set together' raise DictConsistencyError - params = {None: [self.attribute_name, self.get_suffix()], + params = {None: [self.attribute_name, self.get_identifier()], "when": when, "inverse": inverse, } @@ -679,14 +679,14 @@ CALCULATION_TYPES = { "jinja": JinjaCalculation, "variable": VariableCalculation, "information": InformationCalculation, - "suffix": SuffixCalculation, + "identifier": IdentifierCalculation, "index": IndexCalculation, } CALCULATION_PROPERTY_TYPES = { "jinja": JinjaCalculation, "variable": VariablePropertyCalculation, "information": InformationCalculation, - "suffix": SuffixPropertyCalculation, + "identifier": IdentifierPropertyCalculation, "index": IndexCalculation, } BASETYPE_CALC = Union[StrictBool, StrictInt, StrictFloat, StrictStr, Calculation, None] @@ -729,7 +729,7 @@ class Variable(BaseModel): help: Optional[str] = None hidden: Union[bool, Calculation] = False disabled: Union[bool, Calculation] = False - mandatory: Union[None, bool, Calculation] = True + mandatory: Union[None, bool, Calculation] = None empty: Union[None, bool, Calculation] = True auto_save: bool = False mode: Optional[str] = None diff --git a/src/rougail/tiramisu.py b/src/rougail/tiramisu.py index 432b0a916..4aea49626 100644 --- a/src/rougail/tiramisu.py +++ b/src/rougail/tiramisu.py @@ -138,35 +138,36 @@ func['valid_with_jinja'] = valid_with_jinja class ConvertDynOptionDescription(DynOptionDescription): - """Suffix could be an integer, we should convert it in str - Suffix could also contain invalid character, so we should "normalize" it + """Identifier could be an integer, we should convert it in str + Identifier could also contain invalid character, so we should "normalize" it """ - def convert_suffix_to_path(self, suffix): - if suffix is None: - return suffix - if not isinstance(suffix, str): - suffix = str(suffix) - return normalize_family(suffix) + def convert_identifier_to_path(self, identifier): + if identifier is None: + return identifier + if not isinstance(identifier, str): + identifier = str(identifier) + return normalize_family(identifier) def impl_getname( self, - suffix=None, + identifier=None, ) -> str: """get name""" name = super().impl_getname(None) - if suffix is None: + if identifier is None: return name - path_suffix = self.convert_suffix_to_path(suffix) - if "{{ suffix }}" in name: - return name.replace("{{ suffix }}", path_suffix) - return name + path_suffix + path_identifier = self.convert_identifier_to_path(identifier) + if "{{ identifier }}" in name: + return name.replace("{{ identifier }}", path_identifier) + return name + path_identifier def impl_get_display_name( self, subconfig, + with_quote: bool=False, ) -> str: - display = super().impl_get_display_name(subconfig) - if "{{ suffix }}" in display: - return display.replace("{{ suffix }}", self.convert_suffix_to_path(self.get_suffixes(subconfig)[-1])) + display = super().impl_get_display_name(subconfig, with_quote=with_quote) + if "{{ identifier }}" in display: + return display.replace("{{ identifier }}", self.convert_identifier_to_path(self.get_identifiers(subconfig)[-1])) return display diff --git a/src/rougail/tiramisureflector.py b/src/rougail/tiramisureflector.py index fb87c7e42..5754a6bba 100644 --- a/src/rougail/tiramisureflector.py +++ b/src/rougail/tiramisureflector.py @@ -89,6 +89,12 @@ class TiramisuReflector: continue self.text["header"].append(f"load_functions('{funcs_path}')") if self.objectspace.export_with_import: + if objectspace.main_namespace: + self.text["header"].extend(["try:", + " groups.namespace", + "except:", + " groups.addgroup('namespace')", + ]) for mode in self.objectspace.modes_level: self.text["header"].append(f'ALLOWED_LEADER_PROPERTIES.add("{mode}")') self.make_tiramisu_objects() @@ -322,17 +328,17 @@ class Common: information_variable.informations.append(information_name) return information_name return f'ParamInformation("{param["information"]}", {default})' - if param["type"] == "suffix": - if "suffix" in param and param["suffix"] != None: - return f"ParamSuffix(suffix_index={param['suffix']})" - return "ParamSuffix()" + if param["type"] == "identifier": + if "identifier" in param and param["identifier"] != None: + return f"ParamIdentifier(identifier_index={param['identifier']})" + return "ParamIdentifier()" if param["type"] == "index": return "ParamIndex()" if param["type"] == "variable": return self.build_option_param( param["variable"], param.get("propertyerror", True), - param.get("suffix"), + param.get("identifier"), param.get("dynamic"), param.get('whole', False), ) @@ -348,7 +354,7 @@ class Common: self, variable, propertyerror, - suffix: Optional[str], + identifier: Optional[str], dynamic, whole: bool, ) -> str: @@ -362,9 +368,14 @@ class Common: self.calls, self.elt.path ) params = [f"{option_name}"] - if suffix is not None: + if identifier is not None: param_type = "ParamDynOption" - params.append(self.convert_str(suffix)) + identifiers = [] + for ident in identifier: + if isinstance(ident, str): + ident = self.convert_str(ident) + identifiers.append(str(ident)) + params.append('[' + ', '.join(identifiers) + ']') else: param_type = "ParamOption" if not propertyerror: @@ -518,6 +529,10 @@ class Family(Common): self.object_type = "Leadership" else: self.object_type = "OptionDescription" + if hasattr(self.elt, 'name') and self.elt.name == self.elt.namespace: + self.group_type = 'groups.namespace' + else: + self.group_type = None self.children = [] def add(self, child): @@ -528,8 +543,10 @@ class Family(Common): self, keys: list, ) -> None: + if self.group_type: + keys["group_type"] = self.group_type if self.elt.type == "dynamic": - keys["suffixes"] = self.populate_calculation(self.elt.dynamic) + keys["identifiers"] = self.populate_calculation(self.elt.dynamic) children = [] for path in self.objectspace.parents[self.elt.path]: children.append(self.objectspace.paths[path]) diff --git a/src/rougail/utils.py b/src/rougail/utils.py index e609a0841..5cad10d9e 100644 --- a/src/rougail/utils.py +++ b/src/rougail/utils.py @@ -124,7 +124,7 @@ def get_jinja_variable_to_param( founded_variables = {} unknown_variables = [] for variable_path in variables: - variable, suffix = objectspace.paths.get_with_dynamic( + variable, identifier = objectspace.paths.get_with_dynamic( variable_path, path_prefix, current_path, @@ -133,7 +133,7 @@ def get_jinja_variable_to_param( xmlfiles, ) if variable and variable.path in objectspace.variables: - founded_variables[variable_path] = (suffix, variable) + founded_variables[variable_path] = (identifier, variable) else: sub_family = variable_path + '.' for founded_variable in chain(founded_variables, unknown_variables): @@ -151,7 +151,7 @@ def get_jinja_variable_to_param( vpath = variable_path while '.' in vpath: vpath = vpath.rsplit('.', 1)[0] - variable, suffix = objectspace.paths.get_with_dynamic( + variable, identifier = objectspace.paths.get_with_dynamic( vpath, path_prefix, current_path,