Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

argparse - Build back command line

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?

like image 953
Lithy Avatar asked Nov 18 '15 08:11

Lithy


People also ask

What does Argparse return?

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.

What is Store_true in Python?

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.


2 Answers

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
like image 98
Ben Mares Avatar answered Oct 30 '22 22:10

Ben Mares


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.

like image 32
hpaulj Avatar answered Oct 30 '22 23:10

hpaulj