2

As shown in the following code, I want to have an optional positional argument files, I want to specify a default value for it, when paths are passed in, use specified path.

But because --bar can have multiple arguments, the path passed in didn't go into args.files, how do I fix that? Thanks!

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
parser.add_argument('--bar', nargs='*')
parser.add_argument('files', nargs='?')

cmd = '--foo a --bar b c d '
print parser.parse_args(cmd.split())
# Namespace(bar=['b', 'c', 'd'], files=None, foo='a')


cmd = '--foo a --bar b c d /path/to/file1'
print parser.parse_args(cmd.split())
# Namespace(bar=['b', 'c', 'd', '/path/to/file1'], files=None, foo='a')
1
  • 2
    How is argparse supposed to know that /path/to/file1 goes with files and not with bar? Commented Oct 14, 2016 at 0:59

1 Answer 1

1

Your argument spec is inherently ambiguous (since --bar can take infinite arguments, there is no good way to tell when it ends, particularly since files is optional), so it requires user disambiguation. Specifically, argparse can be told "this is the end of the switches section, all subsequent argument are positional" by putting -- before the positional only section. If you do:

cmd = '--foo a --bar b c d -- /path/to/file1'
print parser.parse_args(cmd.split())

You should get:

Namespace(bar=['b', 'c', 'd'], files='/path/to/file1', foo='a')

(Tested on Py3, but should apply to Py2 as well)

Alternatively, the user can pass the positional argument anywhere it's unambiguous by avoiding putting positional arguments after --bar e.g.:

cmd = '/path/to/file1 --foo a --bar b c d'

or

cmd = '--foo a /path/to/file1 --bar b c d'

Lastly, you could avoid using nargs='*' for switches, given the ambiguity it introduces. Instead, define --bar to be accepted multiple times with a single value per switch, accumulating all uses to a list:

parser.add_argument('--bar', action='append')

then you pass --bar multiple times to supply multiple values one at a time, instead of passing it once with many values:

cmd = '--foo a --bar b --bar c --bar d /path/to/file1'
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.