Search code examples
pythonargparsepython-3.9

Python argparse with optional positional and default None


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".


Solution

  • 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.