From a593fa3d35b57fdc172797e0f7ff2ce7449a0548 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Mon, 12 Jan 2026 08:59:44 +0100 Subject: [PATCH] fix: better error messages --- src/rougail/user_data.py | 58 +++++++++++++++---- .../20_7help_family/makedict/after.json | 10 ++++ .../20_7help_family/makedict/base.json | 4 ++ .../20_7help_family/makedict/before.json | 10 ++++ .../20_7help_family/makedict/mandatory.json | 1 + .../20_7help_family/makedict/read_write.json | 4 ++ .../20_7help_family/tiramisu/base.py | 18 ++++++ .../20_7help_family/tiramisu/no_namespace.py | 17 ++++++ tests/test_1_flattener.py | 5 +- tests/test_others.py | 5 +- tests/test_types.py | 5 +- 11 files changed, 122 insertions(+), 15 deletions(-) create mode 100644 tests/dictionaries/20_7help_family/makedict/after.json create mode 100644 tests/dictionaries/20_7help_family/makedict/base.json create mode 100644 tests/dictionaries/20_7help_family/makedict/before.json create mode 100644 tests/dictionaries/20_7help_family/makedict/mandatory.json create mode 100644 tests/dictionaries/20_7help_family/makedict/read_write.json create mode 100644 tests/dictionaries/20_7help_family/tiramisu/base.py create mode 100644 tests/dictionaries/20_7help_family/tiramisu/no_namespace.py diff --git a/src/rougail/user_data.py b/src/rougail/user_data.py index 6e231812f..ab969ca89 100644 --- a/src/rougail/user_data.py +++ b/src/rougail/user_data.py @@ -56,11 +56,12 @@ class UserData: self.errors = [] self.warnings = [] self.invalid_user_data_error = invalid_user_data_error + self.unknown_user_data_error = unknown_user_data_error if self.invalid_user_data_error: self.invalids = self.errors else: self.invalids = self.warnings - if unknown_user_data_error: + if self.unknown_user_data_error: self.unknowns = self.errors else: self.unknowns = self.warnings @@ -299,7 +300,14 @@ class UserData: def _display_value(self, option, value): if not self.show_secrets and option.type() == "password": - return "*" * 10 + if not isinstance(value, list): + value = "*" * 10 + else: + value = ["*" * 10 for val in value] + if isinstance(value, list): + value = display_list(value, add_quote=True) + else: + value = '"' + value + '"' return value def _populate_error_warnings(self): @@ -310,16 +318,24 @@ class UserData: option = self.config.forcepermissive.option(path) else: option = self.config.option(path) + if option.issymlinkoption(): + err = _('it\'s a symlink option so we cannot set the value {0}').format(self._display_value(option, value)) + if self.invalid_user_data_error: + msg = _('{0}, it has been loading from {1}').format(err, options["source"]) + else: + msg = _('{0}, it will be ignored when loading from {1}').format(err, options["source"]) + self.unknowns.append({msg: option._subconfig}) + continue try: if option.isoptiondescription(): if value: if self.invalid_user_data_error: msg = _( - 'is a family so we cannot set the value "{0}", it has been loading from {1}' + 'it\'s a family so we cannot set the value {0}, it has been loading from {1}' ) else: msg = _( - 'is a family so we cannot set the value "{0}", it will be ignored when loading from {1}' + 'it\'s a family so we cannot set the value {0}, it will be ignored when loading from {1}' ) self.invalids.append({msg.format( self._display_value(option, value), @@ -339,7 +355,7 @@ class UserData: continue except AttributeOptionError as err: if err.code == "option-not-found": - if self.invalid_user_data_error: + if self.unknown_user_data_error: msg = _( 'variable or family "{0}" does not exist, it has been loading from {1}' ) @@ -392,7 +408,7 @@ class UserData: display_name = option.description(with_quote=True) if index is not None: if path == err_path: - if self.invalid_user_data_error: + if self.unknown_user_data_error: msg = _( 'variable {0} at index "{1}" is {2}, it has been loading from {3}' ) @@ -409,7 +425,7 @@ class UserData: ): option._subconfig} ) else: - if self.invalid_user_data_error: + if self.unknown_user_data_error: msg = _( 'family {0} is {1}, {2} at index "{3}", it has been loading from {4}' ) @@ -428,7 +444,7 @@ class UserData: ) else: if path == err_path: - if self.invalid_user_data_error: + if self.unknown_user_data_error: msg = _( "variable has propery {0}, it has been loading from {1}" ) @@ -442,7 +458,7 @@ class UserData: ): option._subconfig} ) else: - if self.invalid_user_data_error: + if self.unknown_user_data_error: msg = _( "family {0} has property {1}, so cannot access to {2}, it has been loading from {3}" ) @@ -459,11 +475,29 @@ class UserData: ): option._subconfig} ) else: + if self.unknown_user_data_error: + msg = _( + "{0}, it has been loading from {1}" + ) + else: + msg = _( + "{0}, it will be ignored when loading from {1}" + ) self.unknowns.append({ - _("{0} in {1}").format(err, options["source"]): option._subconfig} + msg.format(err, options["source"]): option._subconfig} ) except LeadershipError as err: - self.unknowns.append({_("{0} in {1}").format(err, options["source"]): option._subconfig}) + if self.unknown_user_data_error: + msg = _( + "{0}, it has been loading from {1}" + ) + else: + msg = _( + "{0}, it will be ignored when loading from {1}" + ) + self.unknowns.append({ + msg.format(err, options["source"]): option._subconfig} + ) except ConfigError as err: err.prefix = "" if self.invalid_user_data_error: @@ -474,7 +508,7 @@ class UserData: except ValueError as err: err.prefix = "" type_ = option.type(translation=True) - msg = _('the value "{0}" is an invalid {1}, {2}').format( + msg = _('the value {0} is an invalid {1}, {2}').format( self._display_value(option, value), type_, err, diff --git a/tests/dictionaries/20_7help_family/makedict/after.json b/tests/dictionaries/20_7help_family/makedict/after.json new file mode 100644 index 000000000..d689d8abe --- /dev/null +++ b/tests/dictionaries/20_7help_family/makedict/after.json @@ -0,0 +1,10 @@ +{ + "rougail.family1.var": { + "owner": "default", + "value": null + }, + "rougail.family2.var": { + "owner": "default", + "value": null + } +} diff --git a/tests/dictionaries/20_7help_family/makedict/base.json b/tests/dictionaries/20_7help_family/makedict/base.json new file mode 100644 index 000000000..990d7941c --- /dev/null +++ b/tests/dictionaries/20_7help_family/makedict/base.json @@ -0,0 +1,4 @@ +{ + "rougail.family1.var": null, + "rougail.family2.var": null +} diff --git a/tests/dictionaries/20_7help_family/makedict/before.json b/tests/dictionaries/20_7help_family/makedict/before.json new file mode 100644 index 000000000..d689d8abe --- /dev/null +++ b/tests/dictionaries/20_7help_family/makedict/before.json @@ -0,0 +1,10 @@ +{ + "rougail.family1.var": { + "owner": "default", + "value": null + }, + "rougail.family2.var": { + "owner": "default", + "value": null + } +} diff --git a/tests/dictionaries/20_7help_family/makedict/mandatory.json b/tests/dictionaries/20_7help_family/makedict/mandatory.json new file mode 100644 index 000000000..40bbfa8dd --- /dev/null +++ b/tests/dictionaries/20_7help_family/makedict/mandatory.json @@ -0,0 +1 @@ +["rougail.family1.var", "rougail.family2.var"] \ No newline at end of file diff --git a/tests/dictionaries/20_7help_family/makedict/read_write.json b/tests/dictionaries/20_7help_family/makedict/read_write.json new file mode 100644 index 000000000..990d7941c --- /dev/null +++ b/tests/dictionaries/20_7help_family/makedict/read_write.json @@ -0,0 +1,4 @@ +{ + "rougail.family1.var": null, + "rougail.family2.var": null +} diff --git a/tests/dictionaries/20_7help_family/tiramisu/base.py b/tests/dictionaries/20_7help_family/tiramisu/base.py new file mode 100644 index 000000000..71f128aa8 --- /dev/null +++ b/tests/dictionaries/20_7help_family/tiramisu/base.py @@ -0,0 +1,18 @@ +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 +load_functions('../rougail-tests/funcs/test.py') +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="var", doc="var", properties=frozenset({"basic", "mandatory"}), informations={'ymlfiles': ['../rougail-tests/structures/20_7help_family/rougail/00-base.yml'], 'type': 'string'}) +optiondescription_2 = OptionDescription(name="family1", doc="the first family", children=[option_3], properties=frozenset({"basic"}), informations={'ymlfiles': ['../rougail-tests/structures/20_7help_family/rougail/00-base.yml'], 'help': 'Multi line\n\nHelp\n\nWith useful information'}) +option_5 = StrOption(name="var", doc="var", properties=frozenset({"basic", "mandatory"}), informations={'ymlfiles': ['../rougail-tests/structures/20_7help_family/rougail/00-base.yml'], 'type': 'string'}) +optiondescription_4 = OptionDescription(name="family2", doc="the second family", children=[option_5], properties=frozenset({"basic"}), informations={'ymlfiles': ['../rougail-tests/structures/20_7help_family/rougail/00-base.yml'], 'help': 'Multi line\nHelp\nWith useful information'}) +optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[optiondescription_2, optiondescription_4], properties=frozenset({"basic"})) +option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1]) diff --git a/tests/dictionaries/20_7help_family/tiramisu/no_namespace.py b/tests/dictionaries/20_7help_family/tiramisu/no_namespace.py new file mode 100644 index 000000000..9f783d6fd --- /dev/null +++ b/tests/dictionaries/20_7help_family/tiramisu/no_namespace.py @@ -0,0 +1,17 @@ +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 +load_functions('../rougail-tests/funcs/test.py') +try: + groups.namespace +except: + groups.addgroup('namespace') +ALLOWED_LEADER_PROPERTIES.add("basic") +ALLOWED_LEADER_PROPERTIES.add("standard") +ALLOWED_LEADER_PROPERTIES.add("advanced") +option_2 = StrOption(name="var", doc="var", properties=frozenset({"basic", "mandatory"}), informations={'ymlfiles': ['../rougail-tests/structures/20_7help_family/rougail/00-base.yml'], 'type': 'string'}) +optiondescription_1 = OptionDescription(name="family1", doc="the first family", children=[option_2], properties=frozenset({"basic"}), informations={'ymlfiles': ['../rougail-tests/structures/20_7help_family/rougail/00-base.yml'], 'help': 'Multi line\n\nHelp\n\nWith useful information'}) +option_4 = StrOption(name="var", doc="var", properties=frozenset({"basic", "mandatory"}), informations={'ymlfiles': ['../rougail-tests/structures/20_7help_family/rougail/00-base.yml'], 'type': 'string'}) +optiondescription_3 = OptionDescription(name="family2", doc="the second family", children=[option_4], properties=frozenset({"basic"}), informations={'ymlfiles': ['../rougail-tests/structures/20_7help_family/rougail/00-base.yml'], 'help': 'Multi line\nHelp\nWith useful information'}) +option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_3]) diff --git a/tests/test_1_flattener.py b/tests/test_1_flattener.py index 8512f87cc..7a67fd488 100644 --- a/tests/test_1_flattener.py +++ b/tests/test_1_flattener.py @@ -111,7 +111,10 @@ def load_rougail_object(test_dir, rougailconfig, multi=False, namespace=False): if namespace is False and not multi: return None rougailconfig['extra_namespaces'] = extra_namespaces - rougailconfig['tiramisu_cache'] = get_tiramisu_filename(test_dir, 'tmp', multi, namespace) + try: + rougailconfig['tiramisu_cache'] = get_tiramisu_filename(test_dir, 'tmp', multi, namespace) + except: + rougailconfig['cli.tiramisu_cache'] = get_tiramisu_filename(test_dir, 'tmp', multi, namespace) rougailconfig['custom_types']['custom'] = CustomOption return Rougail(rougailconfig) diff --git a/tests/test_others.py b/tests/test_others.py index e2c5a4793..35b8720ef 100644 --- a/tests/test_others.py +++ b/tests/test_others.py @@ -35,7 +35,10 @@ def test_personalize_mode(): rougailconfig['modes_level'] = ['level1', 'level2'] rougailconfig['default_variable_mode'] = 'level1' rougailconfig['default_family_mode'] = 'level1' - rougailconfig['tiramisu_cache'] = None + try: + rougailconfig['tiramisu_cache'] = None + except: + rougailconfig['cli.tiramisu_cache'] = None eolobj = Rougail(rougailconfig=rougailconfig) eolobj.run() diff --git a/tests/test_types.py b/tests/test_types.py index 55a97fdb6..526b4028f 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -17,7 +17,10 @@ def type_variable(test_name): rougailconfig = RougailConfig.copy() rougailconfig['types'] = [f'tests/types/types/{test_name}'] rougailconfig['main_structural_directories'] = [f'tests/types/structures/{ test_name }'] - rougailconfig['tiramisu_cache'] = str(tmp_file) + try: + rougailconfig['tiramisu_cache'] = str(tmp_file) + except: + rougailconfig['cli.tiramisu_cache'] = str(tmp_file) rougail = Rougail(rougailconfig=rougailconfig) config = rougail.run() #