Mari
Mari

Reputation: 23

Parsing command line arguments containing dictionaries

I want to pass command line arguments to a python that contain dictionaries like so:

python server.py --keys '{"0x11": "f1.bin", "0x21": "f2.bin"}' --binaries '{"0x11": "dog.jpg", "0x21": "apple.jpg"}' -d '100' -p '1234'

I want to be able to convert these string representations of dictionaries to actual python dictionaries.

When I print out the argv parameter in my main function, I get a list that looks like this:

['--keys', "'{0x11:", 'f1.bin,', '0x21:', "f2.bin}'", '--binaries', "'{0x11:", 'cat.jpg,', '0x21:', "kitten.jpg}'", '-d', "'100'", '-p', "'1234'"]

This is not the desired output. For example, notice the dictionaries' keys no longer have quotation marks around them. Because of this, I can't use the json or ast packages to convert the string representations of the dictionaries to actual dictionaries. I would like if the entire string representation of the dictionaries were a single element in the list and for their structure to be preserved.

I've tried using the optparse package, however, this does not help either. Here is how I tried to do it:

def main(argv):

    parser = optparse.OptionParser()
    parser.add_option('--keys')
    parser.add_option('--binaries')
    parser.add_option('-d')
    parser.add_option('-p')

    options, args = parser.parse_args()
    print(argv)
    print(options)
    print(args)

Which gives the following output:

['--keys', "'{0x11:", 'f1.bin,', '0x21:', "f2.bin}'", '--binaries', "'{0x11:", 'cat.jpg,', '0x21:', "kitten.jpg}'", '-d', "'100'", '-p', "'1234'"]
{'keys': "'{0x11:", 'binaries': "'{0x11:", 'd': "'100'", 'p': "'1234'"}
['f1.bin,', '0x21:', "f2.bin}'", 'cat.jpg,', '0x21:', "kitten.jpg}'"]

Is there a simple way to achieve my desired output? Or do I need to write my own code to alter the elements of argv to look like how I want before using json or ast?


NOTE Maurice's solution is perfect. It caused a little bit of trouble at first, until he noticed my problem was actually only occurring on Windows. On Windows, We must surround the dictionaries by double quotes, and escape the inner double quotes like this:

python server.py --keys "{\"0x11\": \"f1.bin\", \"0x21\": \"f2.bin\"}" --binaries"{\"0x11\": \"dog.jpg\", \"0x21\": \"apple.jpg\"}" -d '100' -p '1234'
Huge thanks to him, because I never would have figured this issue out on my own.

Upvotes: 0

Views: 446

Answers (1)

Maurice Meyer
Maurice Meyer

Reputation: 18106

Using argparse (optparse is deprecated), options can have a types (int, str, ...). But you can use json.loads or ast.literal_eval as type to parse the JSON string:

import ast
import json
import argparse

parser = argparse.ArgumentParser(description='JSON TEST')
parser.add_argument('--keys', type=ast.literal_eval)
parser.add_argument('--binaries', type=json.loads)
parser.add_argument('-d', type=str)
parser.add_argument('-p', type=str)

args = parser.parse_args()
print(args)

Calling from CLI:

python server.py --keys '{"0x11": "f1.bin", "0x21": "f2.bin"}' --binaries '{"0x11": "dog.jpg", "0x21": "apple.jpg"}' -d '100' -p '1234'   

Out:

Namespace(binaries={'0x11': 'dog.jpg', '0x21': 'apple.jpg'}, d='100', keys={'0x11': 'f1.bin', '0x21': 'f2.bin'}, p='1234')

Note:
On Windows you need to escape the quotes within the JSON string:

python server.py --keys "{\"0x11\": \"f1.bin\", \"0x21\": \"f2.bin\"}" --binaries "{\"0x11\": \"dog.jpg\", \"0x21\": \"apple.jpg\"}" -d '100' -p '1234'

Out:

enter image description here

Upvotes: 1

Related Questions