I am writing a Python wrapper script for another python function which takes command line options using optparse, say -p and -i. In my wrapper function I'd like to add some other command line options that are not defined in the external function, e.g. -x. I am looking for a way to combine the the options defined in the external function with the ones I define in the wrapper. The external scripts has a function like this:
def extparser():
from optparse import OptionParser
parser = OptionParser(
prog="external-prog",
usage="%prog [options]")
parser.add_option(
"-p", "--parameter", type="int", default=1,
help="algo parameter")
parser.add_option(
"-i", "--iterations", type="int",
help="number of iterations")
(opts, args) = parser.parse_args()
return opts
I can't change the code in the external function. In my wrapper script I have something like :
#!/usr/bin/env python
from extprog import extparser
def newparser():
from optparse import OptionParser
parser = OptionParser(
prog="newprog",
usage="%prog [options]")
parser.add_option(
"-x", "--extraparam", type="int",
help="another parameter")
return parser.parse_args()
if __name__=="__main__":
extparser()
newparser()
Now, of course this doesn't work as expected :
[myhost]>./sotest.py -x 1 -p 2 -i 3
Usage: external-prog [options] <action> <name>
external-prog: error: no such option: -x
Is there a way to ignore the error from the external program? The real list of options in the external program is pretty long and I want to avoid copying it into the wrapper script.
There is no way to avoid getting that error while the external scripts optparse code is being called. What you can do is use the subprocess module to control which variables you pass to the external script by invoking it manually.
E.g:
subprocess.call(["external-prog", "-p", "some p value", "-i", "10"])
Related
I have a function which requires command line arguments (with optparse), which looks something like this:
def foo():
parser = optparse.OptionParser()
parser.add_option("-i", dest="input")
parser.add_option("-o", dest="output")
(options, args) = parser.parse_args()
do_something(options.input, options.output)
return
I need to call this function from another Python script.
Does anyone know how to pass arguments to this without making use of os.system('foo -i input_path -o output_path')?
Is it possible to change your structure to incorporate function arguments? If you are calling it from another script it would make it easier.
def foo(input, output):
parser = optparse.OptionParser()
parser.add_option("-i", dest="input")
parser.add_option("-o", dest="output")
(options, args) = parser.parse_args()
if options.input:
input=options.input
if options.output:
output=options.output
do_something(input, output)
return
Otherwise you can try subprocess when calling from the other script, as that allows you to use args
I have a simple python (v2.7) script (test.py)
#!/usr/bin/python
import sys
from optparse import OptionParser
def main():
parser = OptionParser()
parser.add_option("--files", dest="files",
metavar="FILES", default=None,
help="A file pattern matching ottcall logs.")
(options, args) = parser.parse_args()
print "FILES_PATTERN %s" % options.files
if not options.files:
parser.error("Files_pattern option is mandatory - Abort execution.")
return 0
if __name__ == "__main__":
sys.exit(main())
User must provide a file pattern or a filename
Run script in command line if option is missing returns error:
python test.py
FILES_PATTERN None
Usage: test.py [options]
test.py: error: Files_pattern option is mandatory - Abort execution.
If option files is missing some letters (--fil instead of --files):
python test.py --fil "a_pattern_for_files"
FILES_PATTERN a_pattern_for_files
I think I should have an error like the following
python test.py --fl "a_pattern_for_files"
Usage: test.py [options]
test.py: error: no such option: --fl
Why don't I get an error from OptionParser when I use --fil instead of the correct argument --files ?
Not only I do not get an error but variable files stores the value: a_pattern_for_files (which is printed).
I am expecting argument files to have value: None (default) unless in command line --files exists
optparse allows abbreviated forms of long options. --fil is a prefix of --files and not a prefix of any other long options the program supports, so --fil is treated as equivalent to --files.
This is barely mentioned in the docs, and there is no option to turn it off. argparse has an option to turn it off, but only in Python 3.5+.
I am using optparse to get command line input.
Lets say that I am running a script demo.py and it creates some output. But unless I specify the command line input, the output is not written to a file.
I am trying to do the following:
python demo.py in command line should run the script, but not write the output anywhere.
python demo.py -o in command line should write the output to my default file name output.txt.
python demo.py -o demooutput.txt in command line should write the output to file demooutput.txt.
PS: I would not prefer to switch to argparse from optparse.
You can use optparse-callbacks to achieve this.
Here is how it wiill work for your use case.
parser.add_option("-o", action="callback", dest="output", callback=my_callback)
def my_callback(option, opt, value, parser):
if len(parser.rargs) > 0:
next_arg = parser.rargs[0]
if not next_arg.startswith("-"):
# Next argument is not another option
del parser.rargs[0]
setattr(parser.values, option.dest, next_arg)
return
# If not processed, set the default value
setattr(parser.values, option.dest, "output.txt")
I don't think there is unfortunately - the only way I can think of is hacking around the problem by adding your own logic statements. The following code should do the trick.
import re, sys
import optparse from OptionParser
usage = "usage: %prog [options] arg"
parser = OptionParser(usage)
if '-f' in argv:
a = argv.index('-f')
if (a != len(argv)-1) and re.search('[.]txt', argv[a+1]):
parser.add_option("-f", "--foo", dest="foo")
else:
parser.add_option("-f", dest="foo", action="store_true")
This doesn't answer the direct question, 'how to define an Action...', but it handles the inputs in a simple way.
Set '-o' to be 'store_true'. If True check the 'args' variable for a file name.
(options, args) = parser.parse_args()
if options.o:
if args:
dest = args[0]
else:
dest = 'output.txt'
else:
dest = ''
(In argparse the equivalent would be to define a positional argument with nargs='?'.)
If these are the only arguments, you could also get by with checking for the filename without requiring the `-o'.
Another possibility - 'store_const', with the positional 'filename' having priority:
parser = optparse.OptionParser()
parser.add_option('-o',dest='dest',action='store_const', const='output.txt', default='')
(options, args) = parser.parse_args()
if args:
options.dest = args[0]
print options
I've written a file crawler and I'm trying to expand it. I want to use argparse to handle settings for the script including passing the starting directory in at the command line.
Example: /var/some/directory/
I have gotten several other arguments to work but I'm unable to pass this directory in correctly. I don't care if it's preceded by a flag or not, (e.g -d /path/to/start/) but I need to make sure that at the very least, this is argument is used as it will be the only mandatory option for the script to run.
Code Sample:
parser = argparse.ArgumentParser(description='py pub crawler...')
parser.add_argument('-v', '--verbose', help='verbose output from crawler', action="store_true")
parser.add_argument('-d', '--dump', help='dumps and replaces existing dictionaries', action="store_true")
parser.add_argument('-f', '--fake', help='crawl only, nothing stored to DB', action="store_true")
args = parser.parse_args()
if args.verbose:
verbose = True
if args.dump:
dump = True
if args.fake:
fake = True
Simply add:
parser.add_argument('directory',help='directory to use',action='store')
before your args = parser.parse_args() line. A simple test from the commandline shows that it does the right thing (printing args at the end of the script):
$ python test.py /foo/bar/baz
Namespace(directory='/foo/bar/baz', dump=False, fake=False, verbose=False)
$ python test.py
usage: test.py [-h] [-v] [-d] [-f] directory
test.py: error: too few arguments
I would like use argparse to parse the arguments that it knows and then leave the rest untouched. For example I want to be able to run
performance -o output other_script.py -a opt1 -b opt2
Which uses the -o option and leaves the rest untouched.
The module profiler.py does a similar thing with optparse, but since I'm using argparse I'm doing:
def parse_arguments():
parser = new_argument_parser('show the performance of the given run script')
parser.add_argument('-o', '--output', default='profiled.prof')
return parser.parse_known_args()
def main():
progname = sys.argv[1]
ns, other_args = parse_arguments()
sys.argv[:] = other_args
Which also seems to work, but what happens if also other_script.py also has a -o flag?
Is there in general a better way to solve this problem?
You could also add a positional argument to your parser with nargs=argparse.REMAINDER, to capture the script and its options:
# In script 'performance'...
p = argparse.ArgumentParser()
p.add_argument("-o")
p.add_argument("command", nargs=argparse.REMAINDER)
args = p.parse_args()
print args
Running the above minimal script...
$ performance -o output other_script.py -a opt1 -b opt2
Namespace(command=['performance', '-a', 'opt1', '-b', 'opt2'], o='output')
argparse will stop to parse argument until EOF or --. If you want to have argument without beeing parsed by argparse, you can write::
python [PYTHONOPTS] yourfile.py [YOURFILEOPT] -- [ANYTHINGELSE]