From d0e10a1101588766cc2fc53d14c5eda8b4b4a6a3 Mon Sep 17 00:00:00 2001 From: Andy Mikhaylenko Date: Sat, 21 Oct 2023 19:08:13 +0200 Subject: [PATCH] fix: positionals cannot have action=store_{true,false} --- src/argh/assembling.py | 4 +++- tests/test_assembling.py | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/argh/assembling.py b/src/argh/assembling.py index a666e3b..737b958 100644 --- a/src/argh/assembling.py +++ b/src/argh/assembling.py @@ -221,6 +221,7 @@ def guess_extra_parser_add_argument_spec_kwargs( # TODO: use typing to extract other_add_parser_kwargs = parser_add_argument_spec.other_add_parser_kwargs guessed: Dict[str, Any] = {} + is_positional = not parser_add_argument_spec.cli_arg_names[0].startswith("-") # Parser actions that accept argument 'type' TYPE_AWARE_ACTIONS = "store", "append" @@ -229,8 +230,9 @@ def guess_extra_parser_add_argument_spec_kwargs( default_value = parser_add_argument_spec.default_value if default_value not in (None, NotDefined): if isinstance(default_value, bool): - if other_add_parser_kwargs.get("action") is None: + if not is_positional and other_add_parser_kwargs.get("action") is None: # infer action from default value + # (not applicable to positionals: _StoreAction doesn't accept `nargs`) guessed["action"] = "store_false" if default_value else "store_true" elif other_add_parser_kwargs.get("type") is None: # infer type from default value diff --git a/tests/test_assembling.py b/tests/test_assembling.py index 0abf5aa..d9f50a5 100644 --- a/tests/test_assembling.py +++ b/tests/test_assembling.py @@ -52,13 +52,21 @@ def test_guess_type_from_default(): def test_guess_action_from_default(): - # True → store_false + # positional, default True → ignore given = ParserAddArgumentSpec("foo", ["foo"], default_value=False) + assert {} == argh.assembling.guess_extra_parser_add_argument_spec_kwargs(given) + + # named, default True → store_false + given = ParserAddArgumentSpec("foo", ["--foo"], default_value=False) guessed = {"action": "store_true"} assert guessed == argh.assembling.guess_extra_parser_add_argument_spec_kwargs(given) - # True → store_false + # positional, default False → ignore given = ParserAddArgumentSpec("foo", ["foo"], default_value=True) + assert {} == argh.assembling.guess_extra_parser_add_argument_spec_kwargs(given) + + # named, True → store_false + given = ParserAddArgumentSpec("foo", ["--foo"], default_value=True) guessed = {"action": "store_false"} assert guessed == argh.assembling.guess_extra_parser_add_argument_spec_kwargs(given) @@ -75,6 +83,26 @@ def test_guess_action_from_default(): assert guessed == argh.assembling.guess_extra_parser_add_argument_spec_kwargs(given) +def test_positional_with_default_int(): + def func(pos_int_default=123): + ... + + parser = argh.ArghParser() + parser.set_default_command(func) + assert parser.format_usage() == "usage: pytest [-h] [pos-int-default]\n" + assert "pos-int-default 123" in parser.format_help() + + +def test_positional_with_default_bool(): + def func(pos_bool_default=False): + ... + + parser = argh.ArghParser() + parser.set_default_command(func) + assert parser.format_usage() == "usage: pytest [-h] [pos-bool-default]\n" + assert "pos-bool-default False" in parser.format_help() + + def test_set_default_command(): def func(**kwargs): pass