Working with Python and argparse
, trying to accomplish the following:
$> my_app
Namespace(positional=None)
$> my_app file.txt somedir
Namespace(positional=['file.txt', 'somedir'])
i.e., a positional argument of type list, whose default is None. I would expect the following code to accomplish this:
p = argparse.ArgumentParser()
p.add_argument("positional", nargs='*', default=None)
print(p.parse_args())
But I get:
$> my_app
Namespace(positional=[])
$> my_app file.txt somedir
Namespace(positional=['file.txt', 'somedir'])
The rest of my code uses None
as defaults for lists. If None
is provided, the code select a sensible default. Thus passing []
is not an option.
The behavior of argparse
does rather feel like a bug, but maybe I'm missing something. Any thoughts?
Answer (thx hpaulj) seems to be "as intended" to which I would add "completely unintuitively".
CodePudding user response:
You can achieve the desired behavior like this
import argparse
p = argparse.ArgumentParser()
p.add_argument("positional", nargs='*', default=argparse.SUPPRESS)
print(p.parse_args(namespace=argparse.Namespace(positional=None)))
This prevents the arguments from appearing at all in the namespace which on turn causes the default namespace to take over.
CodePudding user response:
Your case is handled in
def _get_values(self, action, arg_strings):
...
# when nargs='*' on a positional, if there were no command-line
# args, use the default if it is anything other than None
elif (not arg_strings and action.nargs == ZERO_OR_MORE and
not action.option_strings):
if action.default is not None:
value = action.default
self._check_value(action, value)
else:
# since arg_strings is always [] at this point
# there is no need to use self._check_value(action, value)
value = arg_strings
Normally the default
is placed in the Namespace at the start of parsing. During parsing that default is overwritten with value(s) provided by the user. optionals
are 'seen' when the right flag is used. positionals
are 'seen' when the right number of strings are present. Since '*' and '?' accept 0 strings, they will always be 'seen'. Thus their defaults require special handling, if at all.