Home > database >  Python argparse with optional positional and default None
Python argparse with optional positional and default None

Time:01-05

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.

  • Related