Argparse Optional Positional Arguments

Argparse optional positional arguments?

Use nargs='?' (or nargs='*' if you need more than one dir)

parser.add_argument('dir', nargs='?', default=os.getcwd())

extended example:

>>> import os, argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('-v', action='store_true')
_StoreTrueAction(option_strings=['-v'], dest='v', nargs=0, const=True, default=False, type=None, choices=None, help=None, metavar=None)
>>> parser.add_argument('dir', nargs='?', default=os.getcwd())
_StoreAction(option_strings=[], dest='dir', nargs='?', const=None, default='/home/vinay', type=None, choices=None, help=None, metavar=None)
>>> parser.parse_args('somedir -v'.split())
Namespace(dir='somedir', v=True)
>>> parser.parse_args('-v'.split())
Namespace(dir='/home/vinay', v=True)
>>> parser.parse_args(''.split())
Namespace(dir='/home/vinay', v=False)
>>> parser.parse_args(['somedir'])
Namespace(dir='somedir', v=False)
>>> parser.parse_args('somedir -h -v'.split())
usage: [-h] [-v] [dir]

positional arguments:
dir

optional arguments:
-h, --help show this help message and exit
-v

Argparse value for optional positional argument

I can't tell if the optional argument was not defined, or was defined but without a value

If you create your parser like this:

parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS)

Now it is possible to distinguish between the three cases.

  • If -c val was passed, it will be present in args with value "val".
  • If -c was passed without value, it will be present in args with value None.
  • If -c was omitted entirely, it won't be present in args.

The same goes for -p.

If you only want this suppression to apply for one option, rather than on the whole parser, that is possible too:

parser.add_argument('-c', '--csv', nargs='?', default=argparse.SUPPRESS)

Optional positional arguments with Python's argparse

This is a limitation of argparse—but one that's partially lifted in 3.7.

Unix tools generally don't claim to support intermixing of options and arguments, even though they often do. The problem is that combining it with some other features, like subcommands, leads to ambiguity. So, typically, libraries that support any of those features punt on the problem and don't allow intermixing. Or they do something kind of hacky—allowing options at the end, at the start, and in certain hard-to-predict cases but not others in the middle.

That's what argparse originally did. But 3.7 adds Intermixed parsing.

You have to manually call parse_intermixed_args instead of parse_args.

And if you try to use this with any of the features it doesn't go well with, you'll get an exception (even if there's no ambiguity for the particular set of args you pass—which should make it easier to debug).

But otherwise, it'll work as expected: options (together with their values, of course) can be freely mixed with positional arguments anywhere in the command line.


Unfortunately, I don't know of a drop-in backport on PyPI to get 3.7 argparse in earlier versions; the semi-official argparse backport is mainly for pre-2.7/3.2 versions that don't have it at all, and only backports the 3.4 version.

How to use sub-commands along with optional positional arguments in argparse

You're looking for the action='store_true' property on the argument specification.
https://docs.python.org/3/library/argparse.html#action

parser.add_argument('-d', '--display', dest='disp',
action='store_true', help='Opens a webpage')
#main.py

import os, numpy
import argparse
import webbrowser

new=2

def main():
parser = argparse.ArgumentParser()
parser.add_argument('-i','--input',type=str, help='Choose input')
parser.add_argument('-d','--display',dest='disp', action='store_true', help='Opens a webpage')

args = parser.parse_args()

if args.input == 'infile':
print('This is input file')

if args.disp:
url = "https://stackoverflow.com/"
webbrowser.open(url,new=new,autoraise=True)

if __name__=='__main__':
main()

argparse: optional argument between positional arguments

Starting from Python 3.7, it seems argparse now supports this kind of Unix-style parsing:

Intermixed parsing

ArgumentParser.parse_intermixed_args(args=None, namespace=None)

A number of Unix commands allow the user to intermix optional arguments with positional arguments. The parse_intermixed_args() and parse_known_intermixed_args() methods support this parsing style.

There is a caveat, but for "simple" options, it does not affect them:

These parsers do not support all the argparse features, and will raise exceptions if unsupported features are used. In particular, subparsers, argparse.REMAINDER, and mutually exclusive groups that include both optionals and positionals are not supported.

(I posted this FAQ-style question after spending 1 hour trying to understand why the examples in the Python argparse documentation didn't seem to include it, and only by chance found a somewhat unrelated question which contained the mention to this "intermixed" function in a comment, which I am unable to find again to cite it properly.)

Optional positional argument, that only accepts values from a specified list

You can use the add_argument method once for each option in your list, supplying the whole list as possible choices for each argument, and then use the '?' for the nargs field

for example here:

import sys
import argparse

parser = argparse.ArgumentParser(sys.argv[0])
choices = ["A", "B", "C", "D", "E"]
for i, choice in enumerate(choices):
parser.add_argument(choice, metavar=choice,
help="Help Message For Choice" + choice,
choices=choices, nargs='?')

args = parser.parse_args()

This will accept 0, 1, 2, ... len(choices) arguments. You will probably want to override the usage string if you go this route.

python3 name_of_pythonfile.py -h

usage: name_of_pythonfile.py [-h] [A] [B] [C] [D] [E]

positional arguments:
A Help Message for ChoiceA
B Help Message for ChoiceB
C Help Message for ChoiceC
D Help Message for ChoiceD
E Help Message for ChoiceE

options:
-h, --help show this help message and exit

To override the default usage message you just need to pass a string to the usage keyword argument in the ArgumentParser constructor.

parser = ArgumentParser(prog, usage="My New Usage String")

argparse docs

Argparse: Required arguments listed under optional arguments?

Parameters starting with - or -- are usually considered optional. All other parameters are positional parameters and as such required by design (like positional function arguments). It is possible to require optional arguments, but this is a bit against their design. Since they are still part of the non-positional arguments, they will still be listed under the confusing header “optional arguments” even if they are required. The missing square brackets in the usage part however show that they are indeed required.

See also the documentation:

In general, the argparse module assumes that flags like -f and --bar indicate optional arguments, which can always be omitted at the command line.

Note: Required options are generally considered bad form because users expect options to be optional, and thus they should be avoided when possible.

That being said, the headers “positional arguments” and “optional arguments” in the help are generated by two argument groups in which the arguments are automatically separated into. Now, you could “hack into it” and change the name of the optional ones, but a far more elegant solution would be to create another group for “required named arguments” (or whatever you want to call them):

parser = argparse.ArgumentParser(description='Foo')
parser.add_argument('-o', '--output', help='Output file name', default='stdout')
requiredNamed = parser.add_argument_group('required named arguments')
requiredNamed.add_argument('-i', '--input', help='Input file name', required=True)
parser.parse_args(['-h'])
usage: [-h] [-o OUTPUT] -i INPUT

Foo

optional arguments:
-h, --help show this help message and exit
-o OUTPUT, --output OUTPUT
Output file name

required named arguments:
-i INPUT, --input INPUT
Input file name


Related Topics



Leave a reply



Submit