Search code examples
pythondictionaryargparsekeyword-argument

How to pass kwargs to argparse


I need to pass a dictionary to a python module via a command line. I have not found a way to get Python to cooperate. The following is a very simplified example of what I'd like to accomplish. This produces the following error TypeError: _get_positional_kwargs() missing 1 required positional argument: 'dest' . Adding a dest argument to the add_argument line results in TypeError: __init__() got an unexpected keyword argument 'kwargs', indicating the sad possibility that argparse simply may not take a dictionary as an argument. Is a pickle file truly the only option for passing dictionaries back and forth from command line calls?

def run(**kwargs):
for i in kwargs.items():
    print(f'{i}: {kwargs[i]}')
# ...some code to manipulate the dictionary
return kwargs


if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Test script")
parser.add_argument(kwargs='**', description='A dictionary to be manipulated and returned')
args = parser.parse_args()
x = run(args)
pass

Additional info - I know that I can pass a list to a *nargs argument with a command line that includes space-delimited arguments, but I need to do something similar with a dictionary.

UPDATE - WHAT WORKED: Based on the helpful input from @chepner, I was able to get it to work with the json solution he mentioned in his answer. On my Windows platform, I did have to remove all spaces from the dictionary string and escape characters are required in the final command line string.

{\"this\":1,\"is\":2,\"a\":5,\"dictionary\":7}


Solution

  • Arguments are strings, period. What you want to pass is a string that contains an encoded dict, for example using JSON.

    import argparse
    import json
    
    
    parser = argparse.ArgumentParser()
    parser.add_argument('data', type=json.loads)
    
    args = parser.parse_args()
    

    If you run your script with something like

    myscript '{"foo": 3, "bar": "hello"}'
    

    then args.data["foo"] == 3 and args.data["bar"] == "hello".