Getting argparse to manage arguments with multiple names?

I’m running Python 3.15 under Debian linux version 13. This question refers only to the use of “argparse”, and it is not in any way meant to be any kind of “XY” question. If I can’t do what I describe here using argparse, I already know that there are several other argument-parsing packages for Python, and I know how to use them. In other words, this question is solely about the specific use of argparse, and I am not in any way looking for alternatives to argparse.

I’d like to be able to use argparse to accept alternate names for the same argument, if that is possible.

For one example out of many possibilities, I’d like ‘-o’, and ‘-O’, and ‘–outputfile’, and ‘–outfile’, ‘–output’, and ‘–out’ to all manage the same parameter variable.

I know I can do this via multiple instances of parser.add_argument(), or by calling parser.add_argument() within a “for” loop that loops through all of these argument name values.

But is there any way at all to get argparse to do this via one, single parser.add_argument() call, and without needing a loop?

Except for this issue, I like argparse, and I’m hoping that I won’t need to switch to any alternative argument-parsing utility in order to make use of this capability.

Thank you very much in advance for thoughts and suggestions.

ArgumentParser.add_argument accepts multiple flag names as the first argument(s). Does this do what you’re looking for?

>>> parser.add_argument('-o', '-O', '--outfile', '--outputfile', '--output', '--out')

>>> parser.parse_args(['--output', 'foo'])
Namespace(outfile='foo')
>>> parser.parse_args(['-O', 'foo'])
Namespace(outfile='foo')

ArgumentParser.add_argument accepts multiple flag names as the first argument(s). Does this do what you’re looking for?

Ah … thank you.

This is definitely better than having to make multiple parser.add_argument calls, but the multiple parser.parse_args calls are still inconvenient.

But I suppose that this is the best that I can do with argparse.

To be clear, you don’t need to call parse_args multiple times. Those two lines were just to show that the same parser will handle either flag name.

Brian, you should swap the order of the 3 and 4th arguments in the first line of your example code to make it match the outputs.

Thank you. So does this mean that I could do the following? (I am not able to test this on a computer for a day or so, which is why I’m asking here) …

parser.add_argument('-o', '-O', '--outputfile', '--outfile', '--output', '--out')
parser.parse_args(['-o', '-O', '--outputfile', '--outfile', '--output', '--out', 'foo'])
Namespace(outfile='foo')

The reason I would want to do this is because I want the user to be able to enter any of those six flag possibilities on the command line, and always get the same result, no matter which flag possibility is entered.

Or would there have to be six parser.parse_args() calls made in order to enable this capability, one for each flag possibility?

UPDATE: And of course I know that I could also do something like the following:

flags = [ '-o', '-O', '--outputfile', '--outfile', '--output', '--out' ]
parser.add_argument(*flags)
for flag in flags:
    parser.parse_args([ flag, 'foo' ])
Namespace(outfile='foo')

I’m just not wanting to have to use looping nor multiple parser.parse_args() calls for this functionality.

But if I’m stuck with having to do something like this, I guess I could live with that.

I unexpectedly got an opportunity to try this on the computer just now. And it fails as follows:

: error: argument -o/-O/--outputfile/--outfile/--output/--out: expected one argument

So indeed I would have to make multiple parser.parse_args() calls in order to enable the argument-parsing functionality that I describe above.

It’s sad (at least for me) that argparse requires this extra verbosity in order to accomplish this.

If I use getopt instead of argparse, I can do the following:

opts, args = getopt.getopt(
sys.argv[1:],
'o:O:',
[ 'outputfile=', 'outfile=', 'output=', 'out=' ]
)
for o, a in opts:
if o in ( '-o', '-O', '--outputfile', '--outfile', '--output', '--out' ):
foo = a

To me, this is less objectionable than the argparse methodology. Nonethless, argparse offers more capabilities than getopt, so like I wrote above, now I think that I’m just going to bite the bullet and settle for argparse anyway.

You could do this by passing nargs='?', which makes it so that argument accepts either no values or a single value:

from argparse import ArgumentParser

parser = ArgumentParser()
parser.add_argument('-o', '-O', '--outputfile', '--outfile', '--output', '--out', dest='outfile', nargs='?')

args = parser.parse_args(['-o', '-O', '--outputfile', '--outfile', '--output', '--out', '1'])
outfile = args.outfile[-1] # equals '1'

Although this makes it so that a value isn’t required at any point, so you’d have to check the length of args.outfile and handle it being empty accordingly.

I am admittedly curious what use case you have for this, though.

That error means that argparse expected a value after the flag, and there wasn’t one. You’ve provided a list of flags, all of which are missing a value apart from the last one i.e. '--out', 'foo'

You mentioned you want to invoke this from the command line, so there’s no need to supply anything to parse_args() - just define them all in one call to add_argument(), then parse. This seems to work fine for me:

# arg_demo.py
import argparse

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-o", "-O", "--outfile", "--outputfile", "--output", "--out"
    )
    args = parser.parse_args()
    print(args)
$ python arg_demo.py 
Namespace(outfile=None)

$ python arg_demo.py -o FOO
Namespace(outfile='FOO')

$ python arg_demo.py -O BAR
Namespace(outfile='BAR')

Ah! Now I see from your example above that the name of the variable that will get set in the program if any of the flags appear on the command line is the name of the first flag in the list which begins with a double-hyphen: ‘–outfile’ in this case.

And I now therefore understand that if instead, I code the argument list as follows …

"-o", "-O", "--out", "--outputfile", "--output", "--outfile"

… then the name of the variable that will get set in the program if any of the flags appear on the command line will be “out”.

This is indeed straightforward and doesn’t require all of the argparse verbiage that I mistakenly thought that I needed.

Thank you very much! This answers my question, and now I see that argparse isn’t objectionable like I previously thought.

I want to be able to write python programs which can accept several different versions of command-line flags, but always set the same python variable in the program when any of these flags are given, no matter which version of the flag might appear on the command line.

In other words, using the example that I gave above, I would always want the value “the-output-file” to be put into a python variable specifically named “outfile”, no matter which of the six following invocations of my script might be performed:

myscript -o the-output-file
myscript -O the-output-file
myscript --outfile the-output-file
myscript --output the-output-file
myscript --outputfile the-output-file
myscript --out the-output-file

And I want this to be done without lots of argparse verbiage.

And now I can see from the latest message here from Matt cheviot and from what I wrote in my response to that message that this is indeed possible.

So, now I feel comfortable using argparse, after all.

If I’m not mistaken, how argparse picks which name to use on the resulting object from parser.parse_args() is it uses the first long-form option given if present, or if no long names are given it uses the first short one (-s, --start outputs to start, -s, -S outputs to s, --start, -s outputs to start…), but something useful to remember in cases like this is the dest option to add_argument(), which lets you explicitly give a destination name for that option. e.g. parser.add_argument('-o', '--output', dest='outfile') after parsing will have that option’s value available at args.outfile, regardless of the option strings given.

Thank very much for explaining the ‘dest’ option. Now I see how to accomplish what I want, even if there are no long-form arguments.