-1

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.

Fabrizio Demaria
  • 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 Answers2

2

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
chepner
  • 497,756
  • 71
  • 530
  • 681
0

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).

Community
  • 1
  • 1
hpaulj
  • 221,503
  • 14
  • 230
  • 353