32

I would like to have the following syntax:

python utility.py file1 FILE1 file2 FILE2

where file1 and file2 are optional arguments. It is simple to make it working with this syntax:

python utility.py --file1 FILE1 --file2 FILE2

using

parser.add_argument('--file1',type=file)
parser.add_argument('--file2',type=file)

however, if I remove the dashes, argparse starts to interprete it as a positional rather than optional argument...

In other words, is it possible to specifically tell argparse whether an argument is optional or positional so that I can have optional parameters without the dashes?

6
  • 3
    That syntax (no dashes) is confusing as hell! There is a reason the convention exists. Commented Jul 3, 2012 at 12:15
  • 7
    @MartijnPieters: counterexample: the git or svn command line interface. Commented Jul 14, 2014 at 14:21
  • 3
    @RodyOldenhuis: those are subcommands, not switches. Each subcommand takes options, which use dashes. Commented Jul 14, 2014 at 14:34
  • 2
    @MartijnPieters: that is just semantics, no difference from the syntax point of view - arguments with no dashes. Not (directly) supported by argparse for whatever semantics. BTW, they are not switches in my example either (but that is irrelevant as I have just mentioned). Commented Dec 30, 2014 at 17:56
  • 2
    @jvm: subcommands do not usually share switches. There is a shared level (git --version) and per-subcommand switches (git checkout --patch). Don't just dismiss the semantics here. Commented Dec 30, 2014 at 19:31

3 Answers 3

15

There is no way to get argparse to do this for you. However, you can make argparse accept any number of positional arguments:

parser.add_argument('FILES',nargs='*')
options=parser.parse_args()
file1,optional_files=options.FILES[0],options.FILES[1:]

Of course, you may want to add some checks to make sure that at least 1 file was given, etc.

EDIT

I'm still not 100% sure what you want here, but if file1 and file2 are literal strings, you can work around that a little bit by preprocessing sys.argv. Of course, this will still format your help message strangely, but you can always add an epilog explaining that either form is OK:

import argparse
import sys

mangle_args=('file1','file2')
arguments=['--'+arg if arg in mangle_args else arg for arg in sys.argv[1:]]

parser=argparse.ArgumentParser()
parser.add_argument('--file1')
parser.add_argument('--file2')
options=parser.parse_args(arguments)
Sign up to request clarification or add additional context in comments.

7 Comments

Positional arguments are not sufficient for me. For example, file1 may be skipped, file2 inputted, file3 skipped, file4 inputted and the assignment is important (ie I need to know that it was file2 and file4 that were specified by the user)
@jvm -- How is argparse (or anything) supposed to know that the file you gave is file2 instead of file1? If you can't sort it out from the order it came on the commandline, certainly argparse can't do it either.
Are file1 and file2 constant strings, or are they names of files -- maybe that's what I'm not understanding here...
@jvm -- I think I now understand what you're trying to do. I've posted a "workaround". It's a little ugly, but it might be good enough for your purposes.
Thanks, this is a working solution indeed. I was hoping I was missing some argparse function that would allow me this directly but if that is not possible then your workaround is probably the best. Just some nitpicking - of course you also need to import argparse in your example.
|
3

Another Example would be:

train.py

import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Arguments for wake_word")
    parser.add_argument('data', type=str, help="path to data")
    parser.add_argument('output', type=str, help="model save path")
    parser.add_argument('batch_size', type=int, help="batch size")
    parser.add_argument('epochs', type=int, help="no.s of epochs")
    args = parser.parse_args()
print(args.data + args.output + args.batch_size + args.epochs)

then you can just run this code with arguments without dash

train.py /path/to/data/ /path/to/output_files/ 128 100

And, in ascending order

1 Comment

the question is talking about optional arguments without dashes, not positional arguments
2

Had same problem. My workaround is:

lastarg = sys.argv[-1]
if len(sys.argv) > 1 and lastarg[0] != '-':
    sys.argv[-1] = '-file'
    sys.argv.append(lastarg)

argparser = argparse.ArgumentParser()
argparser.add_argument('-d', action='store_true')
argparser.add_argument('-nrv', action='store_true')
argparser.add_argument('-file', type=str, default='')
args = argparser.parse_args()

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.