Search code examples
pythonargparse

argparse required argument list competes with optional argument list


I have a Python program with argparse. The required arguments are list of filenames, and optional are a list of strings that are to be removed from all files.

import argparse

parser = argparse.ArgumentParser("File formatter")
parser.add_argument("filename", type=str, nargs="+")

parser.add_argument("-r", "--remove", metavar="STRING", nargs="+")

args = parser.parse_args()
print(args.filename)
print(args.remove)

The above gives

usage: filefmt [-h] [-r STRING [STRING ...]] filename [filename ...]

The problem: In a call like

filefmt -r str1x gg24 a.txt b.dat

the program has no way of knowing which of the arguments is a remove STRING and which a filename. I'd have to call it like this

filefmt a.txt b.dat -r str1x gg24

but sometimes, environments require me that the filenames come last.

Any idea how to fix this? I'd like to avoid having to prefix the filenames with an option string, this is the default use:

filefmt a.txt b.txt

Solution

  • To resolve the ambiguity you'll have to require the -r option for each STRING

    For example:

    import argparse
    
    parser = argparse.ArgumentParser("File formatter")
    parser.add_argument("filename", type=str, nargs="+")
    
    parser.add_argument("-r", "--remove", metavar="STRING", default=[], action='append', help='string to remove (repeat this option for each string)')
    
    args = parser.parse_args()
    print(args.filename)
    print(args.remove)
    

    Run like this:

    args1.py -r a -r b qwe asd zcx
    

    output:

    ['qwe', 'asd', 'zcx']
    ['a', 'b']
    

    The usage doesn't show you can repeat the -r so I added that in the help for -r:

    usage: File formatter [-h] [-r STRING] filename [filename ...]
    
    positional arguments:
      filename
    
    optional arguments:
      -h, --help            show this help message and exit
      -r STRING, --remove STRING
                            string to remove (repeat this option for each string)