In Python, how can I parse the command line, edit the resulting parsed arguments object and generate a valid command line back with the updated values?
For instance, I would like python cmd.py --foo=bar --step=0
call python cmd.py --foo=bar --step=1
with all the original --foo=bar
arguments, potentially without extra arguments added when default value is used.
Is it possible with argparse
?
Later, calling parse_args() will return an object with two attributes, integers and accumulate . The integers attribute will be a list of one or more integers, and the accumulate attribute will be either the sum() function, if --sum was specified at the command line, or the max() function if it was not.
The store_true option automatically creates a default value of False. Likewise, store_false will default to True when the command-line argument is not present. The source for this behavior is succinct and clear: http://hg.python.org/cpython/file/2.7/Lib/argparse.py#l861.
You can use argparse
to parse the command-line arguments, and then modify those as desired. At the moment however, argparse
lacks the functionality to work in reverse and convert those values back into a command-line string. There is however a package for doing precisely that, called argunparse
. For example, the following code in cmd.py
import sys
import argparse
import argunparse
parser = argparse.ArgumentParser()
unparser = argunparse.ArgumentUnparser()
parser.add_argument('--foo')
parser.add_argument('--step', type=int)
kwargs = vars(parser.parse_args())
kwargs['step'] += 1
prefix = f'python {sys.argv[0]} '
arg_string = unparser.unparse(**kwargs)
print(prefix + arg_string)
will print the desired command line:
python cmd.py --foo=bar --step=1
argparse
is clearly designed to go one way, from sys.argv
to the args
namespace. No thought has been given to preserving information that would let you map things back the other way, much less do the mapping itself.
In general, multiple sys.argv
could produce the same args
. You could, for example, have several arguments that have the same dest
. Or you can repeat 'optionals'. But for a restricted 'parser' setup there may be enough information to recreate a usable argv
.
Try something like:
parser = argparser.ArgumentParser()
arg1 = parser.add_argument('--foo', default='default')
arg2 = parser.add_argument('bar', nargs=2)
and then examine the arg1
and arg2
objects. They contain all the information that you supplied to the add_argument
method. Of course you could have defined those values in your own data structures before hand, e.g.
{'option_string':'--foo', 'default':'default'}
{'dest':'bar', 'nargs':2}
and used those as input to add_argument
.
While the parser may have enough information to recreate a useable sys.argv
, you have to figure out how to do that yourself.
default=argparse.SUPPRESS
may be handy. It keeps the parser from adding a default entry to the namespace. So if the option isn't used, it won't appear in the namespace.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With