From 0e86a7ef43c699a59369e2344b231636d12a4cf1 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Tue, 29 Apr 2025 08:49:20 +0200 Subject: [PATCH] feat: for boolean always add --xxx and --no-xxx --- tests/test_leadership.py | 6 +-- tiramisu_cmdline_parser/api.py | 93 ++++++++++++++++------------------ 2 files changed, 47 insertions(+), 52 deletions(-) diff --git a/tests/test_leadership.py b/tests/test_leadership.py index 6787203..c0bfd2a 100644 --- a/tests/test_leadership.py +++ b/tests/test_leadership.py @@ -121,7 +121,7 @@ options: -h, --help show this help message and exit leader: - -l [LEADER ...], --leader.leader [LEADER ...] + -l, --leader.leader [LEADER ...] Leader var """ parser = TiramisuCmdlineParser(get_config(json, with_mandatory=True, with_symlink=True, with_default_value=False), 'prog.py', add_extra_options=False, formatter_class=TestHelpFormatter) @@ -138,13 +138,13 @@ options: -h, --help show this help message and exit leader: - -l [LEADER ...], --leader.leader [LEADER ...] + -l, --leader.leader [LEADER ...] Leader var --leader.follower INDEX [FOLLOWER] Follower --leader.follower_submulti INDEX [FOLLOWER_SUBMULTI ...] Follower submulti - -i INDEX [FOLLOWER_INTEGER], --leader.follower_integer INDEX [FOLLOWER_INTEGER] + -i, --leader.follower_integer INDEX [FOLLOWER_INTEGER] Follower integer --leader.follower_boolean INDEX Follower boolean diff --git a/tiramisu_cmdline_parser/api.py b/tiramisu_cmdline_parser/api.py index c022aa6..c7103a0 100644 --- a/tiramisu_cmdline_parser/api.py +++ b/tiramisu_cmdline_parser/api.py @@ -59,6 +59,30 @@ def get_choice_list(config, properties, display): return choices +def gen_argument_name(name, is_short_name, force_no, force_del): + if force_no: + if is_short_name: + prefix = "n" + else: + prefix = "no-" + if "." in name: + sname = name.rsplit(".", 1) + name = sname[0] + "." + prefix + sname[1] + else: + name = prefix + name + if force_del: + if is_short_name: + prefix = "p" + else: + prefix = "pop-" + if "." in name: + sname = name.rsplit(".", 1) + name = sname[0] + "." + prefix + sname[1] + else: + name = prefix + name + return name + + class TiramisuNamespace(Namespace): def __init__(self, config: Config, root: Optional[str]) -> None: super().__setattr__("_config", config) @@ -224,34 +248,31 @@ class _BuildKwargs: (not self.force_no or not add_extra_options) or (not_display and not display_modified_value) ) and not self.force_del: - if self.force_no: - description = option.information.get("negative_description", None) - else: - description = None - if description is None: - description = option.description() + description = option.description() self.kwargs["help"] = description if "positional" not in self.properties: is_short_name = self.cmdlineparser._is_short_name( name, "longargument" in self.properties ) if self.force_no: - ga_name = self.gen_argument_name(name, is_short_name) - ga_path = self.gen_argument_name(option.path(), is_short_name) + ga_name = gen_argument_name(name, is_short_name, self.force_no, self.force_del) + ga_path = gen_argument_name(option.path(), is_short_name, self.force_no, self.force_del) self.cmdlineparser.namespace.list_force_no[ga_path] = option.path() elif self.force_del: - ga_name = self.gen_argument_name(name, is_short_name) - ga_path = self.gen_argument_name(option.path(), is_short_name) + ga_name = gen_argument_name(name, is_short_name, self.force_no, self.force_del) + ga_path = gen_argument_name(option.path(), is_short_name, self.force_no, self.force_del) self.cmdlineparser.namespace.list_force_del[ga_path] = option.path() else: ga_name = name - self.kwargs["dest"] = self.gen_argument_name(option.path(), False) + self.kwargs["dest"] = gen_argument_name(option.path(), False, self.force_no, self.force_del) argument = self.cmdlineparser._gen_argument(ga_name, is_short_name) self.cmdlineparser.namespace.arguments[option.path()] = argument self.args = [argument] + self.ga_name = ga_name else: self.cmdlineparser.namespace.arguments[option.path()] = option.path() self.args = [option.path()] + self.ga_name = name def __setitem__(self, key: str, value: Any) -> None: self.kwargs[key] = value @@ -261,38 +282,15 @@ class _BuildKwargs: option.name(), "longargument" in self.properties ) if self.force_no: - name = self.gen_argument_name(option.name(), is_short_name) + name = gen_argument_name(option.name(), is_short_name, self.force_no, self.force_del) elif self.force_del: - name = self.gen_argument_name(option.name(), is_short_name) + name = gen_argument_name(option.name(), is_short_name, self.force_no, self.force_del) else: name = option.name() argument = self.cmdlineparser._gen_argument(name, is_short_name) self.cmdlineparser.namespace.arguments[option.path()] = argument self.args.insert(0, argument) - def gen_argument_name(self, name, is_short_name): - if self.force_no: - if is_short_name: - prefix = "n" - else: - prefix = "no-" - if "." in name: - sname = name.rsplit(".", 1) - name = sname[0] + "." + prefix + sname[1] - else: - name = prefix + name - if self.force_del: - if is_short_name: - prefix = "p" - else: - prefix = "pop-" - if "." in name: - sname = name.rsplit(".", 1) - name = sname[0] + "." + prefix + sname[1] - else: - name = prefix + name - return name - def get(self) -> Tuple[Dict]: return self.args, self.kwargs @@ -454,7 +452,7 @@ class TiramisuCmdlineParser(ArgumentParser): elif ( self.add_extra_options and obj.type() == "boolean" - and not obj.issymlinkoption() +# and not obj.issymlinkoption() ): if not obj.isleader(): yield obj, False, None @@ -472,15 +470,6 @@ class TiramisuCmdlineParser(ArgumentParser): and obj.type() == "boolean" and obj.value.get() is True ): - negative_description = obj.information.get( - "negative_description", None - ) - if _forhelp and not negative_description: - raise ValueError( - _( - f'the boolean "{obj.path()}" cannot have a default value to "True" with option add_extra_options if there is no negative_description' - ) - ) yield obj, True, None else: yield obj, None, None @@ -488,7 +477,7 @@ class TiramisuCmdlineParser(ArgumentParser): # no follower found, search if there is a symlink for sobj in config.list(uncalculated=True): try: - if sobj.issymlinkoption() and sobj.index is None and sobj.option().isleader(): + if sobj.issymlinkoption() and sobj.index() is None and sobj.option().isleader(): yield sobj, None, None except ConfigError: pass @@ -510,11 +499,17 @@ class TiramisuCmdlineParser(ArgumentParser): _('name cannot startswith "{}"').format(self.prefix_chars) ) if option.issymlinkoption(): - symlink_name = option.option().name() + if self.fullpath: + argument_name = option.option().path() + else: + argument_name = option.option().name() + is_short_name = len(option.option().name()) == 1 + symlink_name = gen_argument_name(argument_name, is_short_name, force_no, force_del) if symlink_name in options_is_not_default: options_is_not_default[symlink_name]["name"] = name if symlink_name in actions: for action in actions[symlink_name]: + action.force_no = force_no action.add_argument(option) continue if force_del: @@ -663,7 +658,7 @@ class TiramisuCmdlineParser(ArgumentParser): kwargs["type"] = float else: pass - actions.setdefault(option.name(), []).append(kwargs) + actions.setdefault(kwargs.ga_name, []).append(kwargs) for option_is_not_default in options_is_not_default.values(): self._option_is_not_default(**option_is_not_default)