You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
argparse: Strange behaviour of positional arguments with store_true, store_false, or store_const action #97848
When store_true, store_false, or store_const is set as an action of positional argument, the behaviour is counterintuitive. Running this small program:
I believe there is no good reason to allow setting those actions to positional arguments. Trying to do so should result in raising an exception (as is the case when trying to set required).
It doesn't seem to have caused problems in practice. If an exception does get added, it should not be backported. Essentially, this is a feature request to provide early warning about an action that doesn't make sense for positional arguments.
changed the title [-]Strange behaviour of positional arguments with `store_true`, `store_false`, or `store_const` action[/-][+]argparse: Strange behaviour of positional arguments with `store_true`, `store_false`, or `store_const` action[/+]on Nov 13, 2022
It's not entirely clear where such a test or warning should be added. add_argument doesn't do a whole lot of testing itself. Based on the absence of prefixchars, it calls _get_positional_kwargs to tweak the args/kwargs mix. Same for optionals. For both, the action is actually created with action = action_class(**kwargs). The action class may be one of the registered subclasses, or a user defined subclass. No one checks whether that 'action_class' is appropriate for optionals or positionals.
This _get_positional_kwargs is used before it looks for the action class.
nargs=0, unless provided by the user, is set by the action_class. The 'store_const' subclasses are distinct in that they use nargs=0. Subclasses like this don't normally test whether they are creating a positional or optional, though I suppose it could test whether the option_strings argument is empty to not (that's how later code distinguishes between the two).
Given this calling structure there isn't a whole lot checking of the kwargs. Wrong or unnecessary kwargs are ignored, or allowed to raise some sort of low level error (such as in the Action subclass). This keeps the overall code simple, without potentially large and complex "checking" routines. It also allows you, the developer, to write custom Action classes without being blocked by some master-parameter-checker.
Also errors like this will arise normally during development and testing. That's when the programmer can easily correct things. What we don't want are un-caught errors during production use. There every error should result in a proper call to self.error, with a message aimed at the final user.
Many of these complaints about add_argument parameters come from developers who are pushing the bounds of what's documented. They want 'store_true' that accept arguments, or use a type that isn't a callable, or use some unrealistic combination of kwargs. These problems can usually be tracked down by matching the error message with the argparse.py code (which is linked in the doc page). It's hard to anticipate this kind of error without imposing a straight-jacket on everyone.
This is a duplicate of #85935. #124839 provides a more general solution that does not depend on the name of the action or how the action is provided (by name or by class).
How on earth am I supposed to do this now with Python 3.14?
parser_help = sub_parser.add_parser("help", help="Print a summary of available commands")
parser_help.add_argument(
"help", help="Print a summary of available commands", action="store_true", default=False
)
To get a flag named help=False when anything but cmd help is passed?
It worked just fine. And now it is ok with Python 3.14 too. 🙂
$ ./ns3 help --help
usage: ns3 help [-h]
positional arguments:
help Print a summary of available commands
options:
-h, --help show this help message and exit
$ ./ns3 --help
or
$ ./ns3 help
ns-3 wrapper for the CMake build system
usage: ns3 [-h] [--compile-or-die compile_or_die compile_or_die] [--dry-run] [-j JOBS] [--quiet] [-v] {help,build,configure,clean,distclean,install,uninstall,run,shell,docs,show} ...
or: ns3 help [-h]
or: ns3 build [-h] [--dry-run] [-j BUILD_JOBS] [--quiet] [-v] [target ...]
or: ns3 configure [-h] [-d {debug,default,release,optimized,minsizerel}] [-G G] [--cxx-standard {23,26}] [--enable-asserts] [--...
or: ns3 clean [-h] [--dry-run]
or: ns3 distclean [-h] [--dry-run]
or: ns3 install [-h]
or: ns3 uninstall [-h]
or: ns3 run [-h] [--no-build] [--command-template COMMAND_TEMPLATE] [--cwd CWD] [--gdb] [--lldb] [-g] [--memray] [--heaptrack] [--perf] [--vis] [--enable-sudo] [--dry-run] [-j RUN_JOBS] [--quiet] [-v] [target]
or: ns3 shell [-h]
or: ns3 docs [-h] [--dry-run] [-v] {contributing,installation,manual,models,tutorial,sphinx,doxygen-no-build,doxygen,all}
or: ns3 show [-h] [--dry-run] [--quiet] {profile,version,config,targets,typeid,all} ...
positional arguments:
{help,build,configure,clean,distclean,install,uninstall,run,shell,docs,show}
help Print a summary of available commands
build Accepts a list of targets to build, or builds the entire project if no target is given
configure Try "./ns3 configure --help" for more configuration options
clean Removes files created by ns3
distclean Removes files created by ns3, tests and documentation
install Install ns-3
uninstall Uninstall ns-3
run Try "./ns3 run --help" for more runtime options
shell Try "./ns3 shell --help" for more shell options
docs Try "./ns3 docs --help" for more documentation options
show Try "./ns3 show --help" for more show options
options:
-h, --help Print a summary of available commands
--compile-or-die compile_or_die compile_or_die
Build and test each individual commit between a base and an head commits. This is especially useful when preparing MRs or rewriting git history, and ensuring refactor-or-die principle is being followed
--dry-run Do not execute the commands.
-j, --jobs JOBS Set number of parallel jobs.
--quiet Don't print task lines, i.e. messages saying which tasks are being executed.
-v, --verbose Print which commands were executed
Activity
rhettinger commentedon Oct 5, 2022
That behavior is weird.
It doesn't seem to have caused problems in practice. If an exception does get added, it should not be backported. Essentially, this is a feature request to provide early warning about an action that doesn't make sense for positional arguments.
[-]Strange behaviour of positional arguments with `store_true`, `store_false`, or `store_const` action[/-][+]argparse: Strange behaviour of positional arguments with `store_true`, `store_false`, or `store_const` action[/+]hpaulj commentedon Mar 8, 2023
It's not entirely clear where such a test or warning should be added.
add_argumentdoesn't do a whole lot of testing itself. Based on the absence of prefixchars, it calls_get_positional_kwargsto tweak the args/kwargs mix. Same for optionals. For both, the action is actually created withaction = action_class(**kwargs). The action class may be one of the registered subclasses, or a user defined subclass. No one checks whether that 'action_class' is appropriate for optionals or positionals.This
_get_positional_kwargsis used before it looks for the action class.nargs=0, unless provided by the user, is set by theaction_class. The 'store_const' subclasses are distinct in that they usenargs=0. Subclasses like this don't normally test whether they are creating a positional or optional, though I suppose it could test whether theoption_stringsargument is empty to not (that's how later code distinguishes between the two).Given this calling structure there isn't a whole lot checking of the
kwargs. Wrong or unnecessary kwargs are ignored, or allowed to raise some sort of low level error (such as in the Action subclass). This keeps the overall code simple, without potentially large and complex "checking" routines. It also allows you, the developer, to write custom Action classes without being blocked by some master-parameter-checker.Also errors like this will arise normally during development and testing. That's when the programmer can easily correct things. What we don't want are un-caught errors during production use. There every error should result in a proper call to
self.error, with a message aimed at the final user.Many of these complaints about
add_argumentparameters come from developers who are pushing the bounds of what's documented. They want 'store_true' that accept arguments, or use atypethat isn't a callable, or use some unrealistic combination of kwargs. These problems can usually be tracked down by matching the error message with theargparse.pycode (which is linked in the doc page). It's hard to anticipate this kind of error without imposing a straight-jacket on everyone.serhiy-storchaka commentedon Oct 9, 2024
This is a duplicate of #85935. #124839 provides a more general solution that does not depend on the name of the action or how the action is provided (by name or by class).
Gabrielcarvfer commentedon Oct 9, 2025
How on earth am I supposed to do this now with Python 3.14?
To get a flag named help=False when anything but
cmd helpis passed?serhiy-storchaka commentedon Oct 9, 2025
Use the
destargument withadd_subparsers().Gabrielcarvfer commentedon Oct 9, 2025
Meh, looks terrible, but I guess it works. Thanks for the help.
serhiy-storchaka commentedon Oct 9, 2025
Your old parser may produce weird result for
cmd help --help(showing non-existent parameter "HELP").Gabrielcarvfer commentedon Oct 9, 2025
It worked just fine. And now it is ok with Python 3.14 too. 🙂