npit
npit

Reputation: 2359

Pass keyword arguments to argparse preserving defaults

Let's say you have an argument parser like below, with a usual workflow that parses CLI args via parser.parse_args().

from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument("-arg1")
parser.add_argument("-arg2", default="some default value")

However, I also may want to bypass argument parsing and supply args directly via a dictonary, which may not contain optional arguments. All missing arguments should be supplied by the parser defaults. I.e., desirable scenario:

mydict={"arg1": "Supplied value"} # only supplied non-optional args

args = somehow_resolve_this(parser, mydict) 

# this should now work
args.arg1
# Supplied value
print(args.arg2)
# Some default value

An equivalent question would be: How can I obtain all optional argument names and default values from the parser?

Upvotes: 0

Views: 198

Answers (2)

hpaulj
hpaulj

Reputation: 231605

As long as none of the arguments is required (positional or flagged), we can get the default values with:

In [3]: args = parser.parse_args([])
In [4]: args
Out[4]: Namespace(arg1=None, arg2='some default value')
In [5]: vars(args)
Out[5]: {'arg1': None, 'arg2': 'some default value'}

And we can 'update' that with your dict:

In [6]: mydict = {"arg1": "Supplied value"}
In [7]: vars(args).update(mydict)
In [8]: args
Out[8]: Namespace(arg1='Supplied value', arg2='some default value')

Using the idea of creating a namespace and passing that to the parser:

In [17]: ns = argparse.Namespace(**mydict)
In [18]: ns
Out[18]: Namespace(arg1='Supplied value')
In [19]: parser.parse_args([], namespace=ns)
Out[19]: Namespace(arg1='Supplied value', arg2='some default value')

Here I supplied the [] argv. That could be omitted if you still want to read the users input. This use of a namespace parameter in effect sets/replaces all the defaults. (this could fail, though, if you are using subparsers).

What if there are required arguments? Defaults don't matter with required arguments.

Another way to get the defaults, is to extract them from the actions list:

In [20]: parser._actions
Out[20]: 
[_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None),
 _StoreAction(option_strings=['-arg1'], dest='arg1', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None),
 _StoreAction(option_strings=['-arg2'], dest='arg2', nargs=None, const=None, default='some default value', type=None, choices=None, help=None, metavar=None)]
In [21]: {a.dest: a.default for a in parser._actions}
Out[21]: {'help': '==SUPPRESS==', 'arg1': None, 'arg2': 'some default value'}

Upvotes: 1

Daweo
Daweo

Reputation: 36680

You might convert your dict into argparse.Namespace and then feed it into .parse_args as follows

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-arg1")
parser.add_argument("-arg2", default="some default value")
namespace = argparse.Namespace(**{"arg1":"value"})
parsed = parser.parse_args(namespace=namespace)
print(parsed.arg1) # value
print(parsed.arg2) # some default value

Explanation: convert dict into kwargs for argparse.Namespace using unpacking ** then feed it into parser.parse_args

Upvotes: 1

Related Questions