ArgumentParser extend values of positional and optional arguments into same namespace

Viewed 70

I'm doing some script which should allow to pass values both as chain of positional arguments and multiple files using optional arguments (-f or --file). It's easy to implement using "extend" action, so I've done something like this:

from argparse import ArgumentParser, FileType

with open("file1.txt", "w") as f1, open("file2.txt", "w") as f2:
    f1.write("arg3")
    f2.write("arg4")

parser = ArgumentParser()
parser.add_argument("pos", nargs="*")
parser.add_argument("-f", "--file", action="extend", type=FileType())
args = parser.parse_args([
    "arg1",
    "arg2",
    "-f", "file1.txt",
    "--file", "file2.txt"
])
print(args)

It works and I got next result:

Namespace(pos=['arg1', 'arg2'], file=['arg3', 'arg4'])

Now I have to work with two separate lists which is possible, but I feel like there's a way to let ArgumentParser collect all arguments into same list.

What I've already tried:

  1. Provide same dest for both arguments:
    parser = ArgumentParser()
    parser.add_argument("pos", nargs="*", dest="values")
    parser.add_argument("-f", "--file", action="extend", type=FileType(), dest="values")
    
    It leads to exception:
    ValueError: dest supplied twice for positional argument
    
  2. Use same name (which actually worked, but I have to use -f and --file for optional arguments and renaming positional breaks help):
    parser = ArgumentParser()
    parser.add_argument("pos", nargs="*")
    parser.add_argument("-p", "--pos", action="extend", type=FileType())
    # Namespace(pos=['arg1', 'arg2', 'arg3', 'arg4'])
    
    parser = ArgumentParser()
    parser.add_argument("file", nargs="*")
    parser.add_argument("-f", "--file", action="extend", type=FileType())
    # Namespace(file=['arg1', 'arg2', 'arg3', 'arg4'])
    
1 Answers

The solution is so simple, but it appeared in my head just after I'd finished writing this question... Anyway, I haven't found a similar question, so I'd leave this answer for future researchers.

Idea with dest argument is the correct one, the only thing is that we should add it only to optional argument and value have to be equal to name of positional argument.

from argparse import ArgumentParser, FileType

with open("file1.txt", "w") as f1, open("file2.txt", "w") as f2:
    f1.write("arg3")
    f2.write("arg4")

parser = ArgumentParser()
parser.add_argument("pos", nargs="*", action="extend")
parser.add_argument("-f", "--file", action="extend", type=FileType(), dest="pos")
args = parser.parse_args([
    "arg1",
    "arg2",
    "-f", "file1.txt",
    "--file", "file2.txt"
])
print(args)

Output:

Namespace(pos=['arg1', 'arg2', 'arg3', 'arg4'])
Related