I would like to pass an arbitrary set of arguments in the format --arg1 value1 to my python script and retrieve them in a dictionary of the kind {'arg1': 'value1}. I want to use argparse to achieve that. The function parse_known_args allows for extra args, but they can be retrieved as a simple list and are not named.
- 453
- 1
- 4
- 15
-
you can simply define the option using the `add_argument` method. `parse_known_args` is a method that will parse all the options defined via `add_argument` and return the remaining command line, while using `parse_args` will raise an error if there are left over arguments. – Bakuriu Sep 07 '16 at 11:32
-
The extra arguments can be of any name/value, not known a priori. – Fabrizio Demaria Sep 07 '16 at 11:34
-
Then `argparse` has no chance of knowing what to do with it. That is the point of `parse_known_args`: **you** have to manually handle the remaining arguments as you please. – Bakuriu Sep 07 '16 at 11:36
-
Alternatively you could change your syntax from `--arg value` to something like `--define arg value` and define a custom `Action` that will do what you want. – Bakuriu Sep 07 '16 at 11:38
-
I see your point. My idea was mainly to have a cmd line syntax like `... --arg1 val1` and `argparse` would make a dictionary like `extra_args = {"arg1": "val1"}`. But I guess there is no such option and I have to build the dictionary myself. – Fabrizio Demaria Sep 07 '16 at 11:42
2 Answers
A better idea is to define one option that takes two arguments, a name and a value, and use a custom action to update a dictionary using those two arguments.
class OptionAppend(Action):
def __call__(self, parser, namespace, values, option_string):
d = getattr(namespace, self.dest)
name, value = values
d[name] = value
p.add_argument("-o", "--option", nargs=2, action=OptionAppend, default={})
Then instead of myscript --arg1 value1 --arg2 value2, you would write myscript -o arg1 value1 -o arg2value1, and after args = parser.parse_args(), you would have args.o == {'arg1': 'value1, 'arg2': 'value2'}.
This is somewhat analogous to the use of a list or dictionary to hold a set of related variables, instead of a set of individually named variables.
# Good
v = [x, y, z]
v = { 'key1': x, 'key2': y, 'key3': z}
# Bad
v1 = x
v2 = y
v3 = z
- 497,756
- 71
- 530
- 681
The question of handling arbitrary key/value pairs has come up a number of times. argparse does not have a builtin mechanism for that.
Is it possible to use argparse to capture an arbitrary set of optional arguments? (almost a duplicate from last May)
Your idea of using parse_know_args and then doing your own dictionary build from the extras is good - and perhaps the simplest. How you handle the extras list will depend on how well behaved your users are (predicable '--key', 'value' pairs). This basically the same as if you parsed sys.arv[1:] directly.
If the user gives input like --options key1:value1 key2=value2 "key3 value3" you can parse those pairs in a custom Action class (e.g. split the string on the delimiter etc).
Input like --options "{key1: value1, key2: value2}" can be handled as a JSON string, with a type function like: type=json.load (I'd have to look that up).