2

In Perl, One can easily read in multiple key=value pair into a variable (a hash) using Getopt::Long (see here )

Basically it says

 GetOptions ("define=s" => \%defines);
 And on command line: <prog> --define os=linux --define vendor=redhat

I have been looking an equivalent in Python but hasn't found any so far [argparse] doesn't take in dictionary from bash shell easily see type=dict in argparse.add_argument() . Although I can work around this by reading in the arguments and programmatically create a dictionary out of it, I just wanted to know a clean and simple way to do it (like Perl has)

Community
  • 1
  • 1
Anshul
  • 680
  • 1
  • 5
  • 19
  • An `argparse` style input would be more like: `python stack18800328.py --os=linux --vendor=redhat`. But that requires knowing the possible 'key' values ahead of time. – hpaulj Sep 16 '13 at 20:36
  • `define` as an `append` argument in `argparse` followed by this one liner is the most compact way I can think of: `args.define = {k:v for k,v in (a.split('=') for a in args.define)}` – hpaulj Sep 16 '13 at 21:04

1 Answers1

4

Use argparse with a custom action:

import argparse
import copy


class DictAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        try:
            k, v = values.split("=", 1)
        except ValueError:
            raise argparse.ArgumentError(self, "Format must be key=value")

        # Implementation is from argparse._AppendAction
        items = copy.copy(argparse._ensure_value(namespace, self.dest, {}))  # Default mutables, use copy!
        items[k] = v
        setattr(namespace, self.dest, items)

# Usage:
parser = argparse.ArgumentParser()
parser.add_argument("--define", action=DictAction)

print parser.parse_args("--define k=v --define x=y".split())
# Gives
# Namespace(d={'x': 'y', 'k': 'v'})

print parser.parse_args("--define k=v --define x=y --define z".split())
# Gives
# usage: args.py [-h] [--define D]
# args.py: error: argument --define: Format must be key=value

Note that this won't support having an equals sign inside a parameter, but you can expand on the "dumb" k, v = values.split("=", 1) to address this.

Thomas Orozco
  • 53,284
  • 11
  • 113
  • 116
  • I know of this work-around [not exactly the way you have written though] and I have been using this. However, I just wanted to know if there is some python module already up there [like perl's getopt] that does it without adding extra lines. So far I found none. Thanks for the response though :) – Anshul Sep 14 '13 at 09:59