Repository navigation
Positional arguments with boolean actions behave differently #85935
Description
Activity
argparse allow the use of
store_trueandstore_falsefor positional arguments, and although it is weird, it should be fine, but using either action raises a behavior I believe is wrong.Given the following Python code:
import argparse arg = argparse.ArgumentParser() arg.add_argument("opt", action="store_false") arg.parse_args(["-h"])The output is:
usage: t.py [-h] positional arguments: opt optional arguments: -h, --help show this help message and exitNote that the positional argument is not shown in the
usageline.When any string parameter is given, the result is:
usage: t.py [-h] t.py: error: unrecognized arguments:(add to the end of the output the value of the argument.)
Even if the use of a positional value is not the best way to describe boolean parameter (optional arguments provide a much better interface for such values), if argparse is to support positional boolean values they should work as other positional arguments.
I'd suggest raising an error if store_true or store_false is used along with positional values.
- added3.8 (EOL)end of lifeend of lifestdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
on Sep 12, 2020 You think the behavior is wrong. Does it disagree with the doc? If not, this is an design change (enhancement) issue limited to future version. If so, it might be a bug that can be backported.
However, when I run the code on Windows with an argument
f:\dev\3x>py -3.8 f:/python/a/tem3.py a b
usage: tem3.py [-h]
...I do not get an error, but get the same usage message as without. Adding quotes on the command line makes no difference.
- changed the title
[-]Positional arguments which use store boolean actions do not behave as other actions.[/-][+]Positional arguments with boolean actions behave differently[/+]on Sep 18, 2020 - changed the title
[-]Positional arguments which use store boolean actions do not behave as other actions.[/-][+]Positional arguments with boolean actions behave differently[/+]on Sep 18, 2020 'store_true/false' are subclasses of 'store_const'. All have a 'nargs=0' value. It's that value which explains their behavior. ('append_const' would also fall in this category)
In [2]: parser = argparse.ArgumentParser() In [3]: parser.add_argument('foo', action='store_const', default='xxx', const='yyy') Out[3]: _StoreConstAction(option_strings=[], dest='foo', nargs=0, const='yyy', default='xxx', type=None, choices=None, help=None, metavar=None) In [4]: _.required Out[4]: True In [5]: parser.print_help() usage: ipython3 [-h] positional arguments: foo optional arguments: -h, --help show this help message and exit In [6]: parser.parse_args([]) Out[6]: Namespace(foo='yyy') In [7]: parser.parse_args(['zzz']) usage: ipython3 [-h] ipython3: error: unrecognized arguments: zzz
Like '*' and '?' this argument is 'satisfied' with nothing, an empty list of values. For those nargs, 'get_values' takes a the special step of assigning the default. For 'store_const' it's the 'const' that's placed in the namespace. 'store_true' does store True, and 'store_false' does store False.
Providing a string produces an error because there isn't any Action to consume it. With nargs=0, this Action can't use it. Usage is also correct since we can't provide any string to meet this Action's needs.
Technically then the Action behaves correctly - both in usage and what it does. That said, it normally isn't useful, since it will always assign the 'const/True/False' to the namespace. Even without an in depth knowledge of how parsing is done, this should be logically evident (if not obvious).
I don't recall any previous issues like this, though I wouldn't be surprised if there were. I don't recall anything on Stackoverflow either.
I think adding an error would be overkill. It doesn't come up often, and some user might have their own obscure reason for using it.
A note to the docs might be in order, but until a user has encountered this behavior as you have, such a note might be more confusing than useful.
As a general rule, parameter checking in add_argument() is rather loose (and multilayered). While 'action' is used to select the Action subclass, most of the rest are passed on to that Action. The Action __init__ check a few key parameters (for example 'store_const' will complain if we don't provide a 'const'), but accept or ignore the rest.
I don't think many users will try to use a boolean positional argument. I only excited this behavior because I was writing an abstraction over argparse to define the command line interface based on a configuration file, and I was trying to add some type checking.
I think documenting the behavior is enough.
See also #97848,
There are checks for 'store' and 'append' actions:
if nargs == 0: raise ValueError('nargs for store actions must be != 0; if you ' 'have nothing to store, actions such as store ' 'true or store const may be more appropriate')
if nargs == 0: raise ValueError('nargs for append actions must be != 0; if arg ' 'strings are not supplying the value to append, ' 'the append const action may be more appropriate')
They were here from the initial release of argparse.
There are also few general checks in
add_argument().So there are precedences. We can either add checks in constructors of
BooleanOptionalAction,_StoreConstAction,_AppendConstAction,_CountAction,_HelpActionand_VersionAction, or add a general check inadd_argument(). The latter looks easier.I wonder if there is a case for an "anchor" action. For example, subparsers could have a positional argument with
action='store_const'and differenceconstvalues, so the stored value would indicate what subparser was executed. But the same goal can be achieved by usingdestinadd_subparsers()orset_defaults()for subparser.3 remaining items
- added 5 commits that reference this issue
on Oct 2, 2024 - added 3 commits that reference this issue
on Oct 12, 2024
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsDoc issues
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
Linked PRs