Reputation: 1881
I want to receive a dict(str -> str)
argument from the command line. Does argparse.ArgumentParser
provide it? Or any other library?
For the command line:
program.py --dict d --key key1 --value val1 --key key2 --value val2
I expect the following dictionary:
d = {"key1": "val1", "key2": "val2"}
Upvotes: 35
Views: 54067
Reputation: 31
Python one-line argparse dictionary arguments argparse_dictionary.py
# $ python argparse_dictionary.py --arg_dict=1=11,2=22;3=33 --arg_dict=a=,b,c=cc,=dd,=ee=,
# Namespace(arg_dict={'1': '11', '2': '22', '3': '33', 'a': '', 'c': 'cc', '': 'dd'})
import argparse
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument(
'--arg_dict',
action=type(
'', (argparse.Action, ),
dict(__call__=lambda self, parser, namespace, values, option_string: getattr(
namespace, self.dest).update(
dict([
v.split('=') for v in values.replace(';', ',').split(',')
if len(v.split('=')) == 2
])))),
default={},
metavar='KEY1=VAL1,KEY2=VAL2;KEY3=VAL3...',
)
print(arg_parser.parse_args())
Upvotes: 3
Reputation: 9
There is a simple solution in Python 3.6 if you're simply trying to convert argparse input to a dictionary. An example is as follows:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-i', '--input', help='the path to the input file')
parser.add_argument('-o', '--output', help='the path to the output file')
args = parser.parse_args()
arguments = dict(args._get_kwargs())
for k, v in arguments.items():
print(k, v)
Given command line input such as python3 script_name.py --input 'input.txt' --output 'output.txt'
the code would output to terminal:
input input.txt
output output.txt
Upvotes: 0
Reputation: 2509
Here's another solution using a custom action, if you want to specify dict key pairs together comma-separated --
import argparse
import sys
parser = argparse.ArgumentParser(description='parse key pairs into a dictionary')
class StoreDictKeyPair(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
my_dict = {}
for kv in values.split(","):
k,v = kv.split("=")
my_dict[k] = v
setattr(namespace, self.dest, my_dict)
parser.add_argument("--key_pairs", dest="my_dict", action=StoreDictKeyPair, metavar="KEY1=VAL1,KEY2=VAL2...")
args = parser.parse_args(sys.argv[1:])
print args
Running:
python parse_kv.py --key_pairs 1=2,a=bbb,c=4 --key_pairs test=7,foo=bar
Output:
Namespace(my_dict={'1': '2', 'a': 'bbb', 'c': '4', 'test': '7', 'foo': 'bar'})
If you want to use nargs instead of comma-separated values in string:
class StoreDictKeyPair(argparse.Action):
def __init__(self, option_strings, dest, nargs=None, **kwargs):
self._nargs = nargs
super(StoreDictKeyPair, self).__init__(option_strings, dest, nargs=nargs, **kwargs)
def __call__(self, parser, namespace, values, option_string=None):
my_dict = {}
print "values: {}".format(values)
for kv in values:
k,v = kv.split("=")
my_dict[k] = v
setattr(namespace, self.dest, my_dict)
parser.add_argument("--key_pairs", dest="my_dict", action=StoreDictKeyPair, nargs="+", metavar="KEY=VAL")
args = parser.parse_args(sys.argv[1:])
print args
Running
python arg_test4.py --key_pairs 1=2 a=bbb c=4 test=7 foo=bar
Outputs:
values: ['1=2', 'a=bbb', 'c=4', 'test=7', 'foo=bar']
Namespace(my_dict={'1': '2', 'a': 'bbb', 'c': '4', 'test': '7', 'foo': 'bar'})
Upvotes: 50
Reputation: 135
just another easy way:
parser = argparse.ArgumentParser()
parser.add_argument('--key1')
parser.add_argument('--key2')
args = parser.parse_args()
my_dict = args.__dict__
Upvotes: 11
Reputation: 231385
A straight forward way of parsing an input like:
program.py --dict d --key key1 --value val1 --key key2 --value val2
is:
parser=argparse.ArgumentParser()
parser.add_argument('--dict')
parser.add_argument('--key', action='append')
parser.add_argument('--value', action='append')
args = parser.parse_args()
which should produce (if my mental parser is correct)
args = Namespace(dict='d', key=['key1','key2'], value=['value1','value2'])
You should be able construct a dictionary from that with:
adict = {k:v for k, v in zip(args.key, args.value)}
Using args.dict
to assign this to a variable with that name requires some un-python trickery. The best would be to create a element in another dictionary with this name.
another_dict = {args.dict: adict}
This solution doesn't perform much error checking. For example, it doesn't make sure that there are the same number of keys and values. It also wouldn't let you create multiple dictionaries (i.e. repeated --dict
arguments). It doesn't require any special order. --dict
could occur after a --key key1
pair. Several --value
arguments could be together.
Tying the key=value
together as chepner
does gets around a number of those problems.
Upvotes: 0
Reputation: 531125
I would use something like this:
p = argparse.ArgumentParser()
p.add_argument("--keyvalue", action='append',
type=lambda kv: kv.split("="), dest='keyvalues')
args = p.parse_args("--keyvalue foo=6 --keyvalue bar=baz".split())
d = dict(args.keyvalues)
You could create a custom action which would "append" a parsed key-value pair directly into a dictionary, rather than simply accumulating a list of (key, value)
tuples. (Which I see is what skyline75489 did; my answer differs in using a single --keyvalue
option with a custom type instead of separate --key
and --value
options to specify pairs.)
Upvotes: 23
Reputation: 16770
As for the current libraries like argparse, docopt and click, none of them support using dict
args. The best solution I can think of is to make a custom argparse.Action
to support it youself:
import argparse
class MyAction(argparse.Action):
def __init__(self, option_strings, dest, nargs=None, **kwargs):
super(MyAction, self).__init__(option_strings, dest, nargs, **kwargs)
def __call__(self, parser, namespace, values, option_string=None):
print '%r %r %r' % (namespace, values, option_string)
value_dict = {}
values.reverse()
while len(values) > 0:
v = eval(values.pop()).lstrip('--') # This is like crazy hack, I know.
k = eval(values.pop())
value_dict[k] = v
setattr(namespace, self.dest, value_dict)
parser = argparse.ArgumentParser()
parser.add_argument('-d', action=MyAction, nargs='*')
args = parser.parse_args('-d "--key" "key1" "--value" "val1" "--key" "key2" "--value" "val2"'.split())
print(args)
Upvotes: -1
Reputation: 1316
Python receives arguments in the form of an array argv
. You can use this to create the dictionary in the program itself.
import sys
my_dict = {}
for arg in sys.argv[1:]:
key, val=arg.split(':')[0], arg.split(':')[1]
my_dict[key]=val
print my_dict
For command line:
python program.py key1:val1 key2:val2 key3:val3
Output:
my_dict = {'key3': 'val3', 'key2': 'val2', 'key1': 'val1'}
Note: args will be in string, so you will have to convert them to store numeric values.
I hope it helps.
Upvotes: 3