When making a CLI with argparser
, as soon as the number of arguments increase the code start to repeat itself significantly.
It can be seen with the example from the docs already:
import argparse
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
const=sum, default=max,
help='sum the integers (default: find the max)')
args = parser.parse_args()
print(args.accumulate(args.integers))
This is a basic example and it's good that it's written in such a way, however it is possible to see the duplication of add_argument
calls. You can likely assume that for a more complex CLI that quickly becomes a problem. Here is a real example.
Is there a way to overcome this to make the initialization more compact but still readable? (Please no suggestions for alternative CLI frameworks)
Update to clarify
We are repeatedly calling the same function with different arguments one after the other. My gut feeling is there might be a way to group those arguments into a structure, and then execute parser.add_argument
with combination of star/"double star" operators on a list containing the above mentioned structures.
ArgumentParser.add_argument has the following declaration:
ArgumentParser.add_argument(single positional argument, lots of optional keyword arguments)
I'm looking for a data structure together with the asterisk operators which could be unpacked into single positional argument, lots of optional keyword arguments
.
First of all, I don't think it violates DRY. We use the same function couple of times, but we don't repeat its code.
What's about your question in the comments about summing of integers in the list, you suggested to use the for cycle and call "add_to_sum" function once. But what's against applying it to the "add_argument"?
ARGS = (
(('-x', '--crossbar'), {'type': str}),
(('-c', '--config'), {'type': str})
)
parser = argparse.ArgumentParser()
for arg in ARGS:
parser.add_argument(*arg[0], **arg[1])