ShanZhengYang
ShanZhengYang

Reputation: 17641

Python argparse for infinite number of inputs and flag requiring multiple arguments?

I have a Python library which users currently run via

python main.py

main.py will call other *.py scripts within the same directory, and the program runs to completion.

My problem is, users of this software should be able to input (in theory) an infinite number of "events", whereby users need to specific 4 pieces of information: "category" (string), "type" (string), "start_time" (integer), and "end_time" (integer). By default, if nothing is no flag is used, no "events" are schedule, and the program runs by default. Users must give each of the 4 arguments at once for each "event", or otherwise there's an error message. Users should be able to schedule as many "events" as need be.

At the moment, I'm not sure of the best way to allow users to pass in argument variables using argparse, whereby (1) they can pass in dozens of arguments at once and (2) 4 categories are required. Is this possible? What is the data structure used, a dicitionary via argparse?

For only one such input, the naïve approach could be to use argparse, and force users to use the following format

python main.py ---user_specify "category1", 1233, 1452, 1673

whereby in the main.py script I have something like

 import argparse
 parser = argparse.ArgumentParser()
 parser.add_argument("user_specify", action="store_true", default=False)

That's quite clumsy. The bigger problem is that it doesn't solve the issue of allowing users to pass through dozens of such arguments.

What is the correct pythonic way to do this?

Is it possible to pass through dictionaries? How does one would with multiple inputs using the same argparse flag though?

Upvotes: 1

Views: 2332

Answers (1)

hpaulj
hpaulj

Reputation: 231530

In [1]: import argparse
In [2]: parser = argparse.ArgumentParser()
In [3]: parser.add_argument('-e','--event',action='append',nargs=4)

In [5]: args = parser.parse_args('--event cetegory1 123 2 4 -e cat2 23 4 343'.split())
In [6]: args
Out[6]: Namespace(event=[['cetegory1', '123', '2', '4'], ['cat2', '23', '4', '343']])

Each --event flag marks a new list of 4 items. Post parsing code could iterate through the sublists of args.event and convert the last 2 elements to integers.

Strings could also contain spaces if quoted.

For many such 'events' you could put them in a @file as described in

https://docs.python.org/3/library/argparse.html#fromfile-prefix-chars

If using the idea in https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.convert_arg_line_to_args

the file could look like

--event cetegory1 123 2 4 
-e "cat 2" 23 4 343
--event foo bar 4 2
...

Data like that could also be read as a csv file. Parsing a json string is also an option. An argparse argument with a type=json.loads parameter can read such a string from the input or an @file.

In [7]: import json
In [8]: parser.add_argument('-j',type=json.loads)
In [9]: argv = ['-j', '[["category1","123",3,4]]']
In [10]: parser.parse_args(argv)
Out[10]: Namespace(event=None, j=[['category1', '123', 3, 4]])

Upvotes: 2

Related Questions