diff --git a/src/rougail/convert/convert.py b/src/rougail/convert/convert.py index cde2eba16..00cf4f771 100644 --- a/src/rougail/convert/convert.py +++ b/src/rougail/convert/convert.py @@ -344,6 +344,8 @@ class ParserVariable: family_is_leadership: bool = False, family_is_dynamic: bool = False, parent_dynamic: Optional[str] = None, + copy_before_set: bool = False, + force_redefine: bool = False, ) -> None: if name.startswith("_"): msg = f'the variable or family name "{name}" is incorrect, it must not starts with "_" character' @@ -377,6 +379,8 @@ class ParserVariable: family_is_leadership=family_is_leadership, family_is_dynamic=family_is_dynamic, parent_dynamic=parent_dynamic, + copy_before_set=copy_before_set, + force_redefine=force_redefine, ) def parse_family( @@ -392,6 +396,8 @@ class ParserVariable: family_is_leadership: bool = False, family_is_dynamic: bool = False, parent_dynamic: Optional[str] = None, + copy_before_set: bool = False, + force_redefine: Union[bool, str] = False, ) -> None: """Parse a family""" if obj is None: @@ -402,7 +408,7 @@ class ParserVariable: exists = obj.pop("exists", None) else: exists = None - redefine = obj.pop("redefine", False) + redefine = obj.pop("redefine", False) or force_redefine is True obj_type = self.get_family_or_variable_type(obj) force_to_attrs = list(self.list_attributes(obj, sources, obj_type)) for key, value in obj.items(): @@ -427,7 +433,9 @@ class ParserVariable: "", # comment family_is_dynamic=family_is_dynamic, parent_dynamic=parent_dynamic, + copy_before_set=True, ) + force_redefine=True family_obj["type"] = self.paths[path].type if path in self.paths: # it's just for modify subfamily or subvariable, do not redefine @@ -494,7 +502,10 @@ class ParserVariable: if self.paths[path].type == "leadership": family_is_leadership = True for idx, key in enumerate(subfamily_obj): - value = subfamily_obj[key] + if copy_before_set: + value = subfamily_obj[key].copy() + else: + value = subfamily_obj[key] first_variable = not force_not_first and idx == 0 if isinstance(obj, CommentedMap): comment = self.get_comment(key, obj) @@ -510,6 +521,8 @@ class ParserVariable: family_is_leadership=family_is_leadership, family_is_dynamic=family_is_dynamic, parent_dynamic=parent_dynamic, + force_redefine=force_redefine, + copy_before_set=copy_before_set, ) def list_attributes( @@ -657,6 +670,8 @@ class ParserVariable: family_is_leadership: bool = False, family_is_dynamic: bool = False, parent_dynamic: Optional[str] = None, + copy_before_set: bool = False, + force_redefine: bool = False, ) -> None: """Parse variable""" if self.version == "1.0" or isinstance(obj, dict): @@ -684,7 +699,7 @@ class ParserVariable: self.parse_params(path, obj, sources) self.parse_secret_manager(path, obj, sources, family_is_dynamic) exists = obj.pop("exists", None) - redefine = obj.pop("redefine", False) + redefine = obj.pop("redefine", False) or force_redefine is True if not redefine and not exists: obj_type = obj.get("type") if obj_type in self.custom_variable_types: @@ -786,7 +801,16 @@ class ParserVariable: """Parse variable params""" if "params" not in obj: return - if not isinstance(obj["params"], dict): + if isinstance(obj["params"], list): + for v in obj["params"]: + if not isinstance(v, AnyParam): + raise DictConsistencyError( + _("params must be a dict for {0}").format(path), + 55, + sources, + ) + return + elif not isinstance(obj["params"], dict): raise DictConsistencyError( _("params must be a dict for {0}").format(path), 55, diff --git a/src/rougail/tiramisu.py b/src/rougail/tiramisu.py index 5b742e146..1c7afc9d8 100644 --- a/src/rougail/tiramisu.py +++ b/src/rougail/tiramisu.py @@ -64,6 +64,8 @@ except ModuleNotFoundError: def display_xmlfiles(xmlfiles: list) -> str: """The function format xmlfiles informations to generate errors""" + if not isinstance(xmlfiles, list): + xmlfiles = [xmlfiles] if len(xmlfiles) == 1: return '"' + xmlfiles[0] + '"' return '"' + '", "'.join(xmlfiles[:-1]) + '"' + " and " + '"' + xmlfiles[-1] + '"' diff --git a/tests/test_types.py b/tests/test_types.py index 526b4028f..9f60e1989 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -55,3 +55,15 @@ def test_type_variables(): def test_type_family(): type_variable("family") + + +def test_type_family_redefine(): + type_variable("family_redefine") + + +def test_type_family_subfamily(): + type_variable("family_subfamily") + + +def test_type_variable_hidden(): + type_variable("variable_hidden") diff --git a/tests/types/result/family_redefine/tiramisu.py b/tests/types/result/family_redefine/tiramisu.py new file mode 100644 index 000000000..527ff85a2 --- /dev/null +++ b/tests/types/result/family_redefine/tiramisu.py @@ -0,0 +1,22 @@ +from tiramisu import * +from tiramisu.setting import ALLOWED_LEADER_PROPERTIES +from re import compile as re_compile +from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription +try: + groups.namespace +except: + groups.addgroup('namespace') +ALLOWED_LEADER_PROPERTIES.add("basic") +ALLOWED_LEADER_PROPERTIES.add("standard") +ALLOWED_LEADER_PROPERTIES.add("advanced") +option_3 = StrOption(name="a_first_variable", doc="a first variable", default="a modified value", properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['tests/types/types/family_redefine/00_structure.yml', 'tests/types/structures/family_redefine/00_structure.yml'], 'type': 'string'}) +option_4 = StrOption(name="a_second_variable", doc="a second variable", default="a modified value", properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['tests/types/types/family_redefine/00_structure.yml', 'tests/types/structures/family_redefine/00_structure.yml'], 'type': 'string'}) +optiondescription_2 = OptionDescription(name="my_family_1", doc="My family type", children=[option_3, option_4], properties=frozenset({"standard"}), informations={'ymlfiles': ['tests/types/types/family_redefine/00_structure.yml', 'tests/types/structures/family_redefine/00_structure.yml']}) +option_6 = StrOption(name="a_first_variable", doc="a first variable", default="a value", properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['tests/types/types/family_redefine/00_structure.yml'], 'type': 'string'}) +option_7 = StrOption(name="a_second_variable", doc="a second variable", properties=frozenset({"basic", "mandatory"}), informations={'ymlfiles': ['tests/types/types/family_redefine/00_structure.yml'], 'type': 'string'}) +optiondescription_5 = OptionDescription(name="my_family_2", doc="My family type", children=[option_6, option_7], properties=frozenset({"basic"}), informations={'ymlfiles': ['tests/types/types/family_redefine/00_structure.yml', 'tests/types/structures/family_redefine/00_structure.yml']}) +option_9 = StrOption(name="a_first_variable", doc="a first variable", default="a value", properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['tests/types/types/family_redefine/00_structure.yml'], 'type': 'string'}) +option_10 = StrOption(name="a_second_variable", doc="a second variable", default="a modified value 2", properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['tests/types/types/family_redefine/00_structure.yml', 'tests/types/structures/family_redefine/00_structure.yml'], 'type': 'string'}) +optiondescription_8 = OptionDescription(name="my_family_3", doc="My family type", children=[option_9, option_10], properties=frozenset({"standard"}), informations={'ymlfiles': ['tests/types/types/family_redefine/00_structure.yml', 'tests/types/structures/family_redefine/00_structure.yml']}) +optiondescription_1 = OptionDescription(name="rougail", doc="rougail", group_type=groups.namespace, children=[optiondescription_2, optiondescription_5, optiondescription_8], properties=frozenset({"basic"})) +option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1]) diff --git a/tests/types/result/family_redefine/variables.json b/tests/types/result/family_redefine/variables.json new file mode 100644 index 000000000..95151a824 --- /dev/null +++ b/tests/types/result/family_redefine/variables.json @@ -0,0 +1,8 @@ +{ + "rougail.my_family_1.a_first_variable": "a modified value", + "rougail.my_family_1.a_second_variable": "a modified value", + "rougail.my_family_2.a_first_variable": "a value", + "rougail.my_family_2.a_second_variable": null, + "rougail.my_family_3.a_first_variable": "a value", + "rougail.my_family_3.a_second_variable": "a modified value 2" +} \ No newline at end of file diff --git a/tests/types/structures/family_redefine/00_structure.yml b/tests/types/structures/family_redefine/00_structure.yml new file mode 100644 index 000000000..e412ca47e --- /dev/null +++ b/tests/types/structures/family_redefine/00_structure.yml @@ -0,0 +1,19 @@ +%YAML 1.2 +--- +version: 1.1 + +my_family_1: + type: my_family_type + + a_first_variable: a modified value + + a_second_variable: a modified value + +my_family_2: + type: my_family_type + +my_family_3: + type: my_family_type + + a_second_variable: a modified value 2 +...