Parsing empty options in Python

I have an application that allows me to send event data to a user script. You simply set the command line arguments and specify what event data is passed with which argument. The problem is that there is no real flexibility. Each option you type will be used, but not every option will necessarily have data. Therefore, when the application builds a string to be sent to the script, some of the arguments are empty and Python OptionParser errors with "error: --someargument option argument is required"

Since there are more than 200 data points, I do not like to write separate scripts to process each combination of possible arguments (this will require 2 ^ 200 scripts). Is there a way to handle empty arguments in python optionparser?

+4
source share
6 answers

Sorry, misunderstood question with my first answer. You can make it possible to have optional arguments for command line flags using the callback action type when defining a parameter. Use the following function as a callback (you most likely wish to adapt to your needs) and configure it for each of the flags, which may receive an argument if necessary:

import optparse def optional_arg(arg_default): def func(option,opt_str,value,parser): if parser.rargs and not parser.rargs[0].startswith('-'): val=parser.rargs[0] parser.rargs.pop(0) else: val=arg_default setattr(parser.values,option.dest,val) return func def main(args): parser=optparse.OptionParser() parser.add_option('--foo',action='callback',callback=optional_arg('empty'),dest='foo') parser.add_option('--file',action='store_true',default=False) return parser.parse_args(args) if __name__=='__main__': import sys print main(sys.argv) 



Running from the command line, you will see the following:

 # python parser.py (<Values at 0x8e42d8: {'foo': None, 'file': False}>, []) # python parser.py --foo (<Values at 0x8e42d8: {'foo': 'empty', 'file': False}>, []) # python parser.py --foo bar (<Values at 0x8e42d8: {'foo': 'bar', 'file': False}>, []) 
+8
source

I do not think optparse can do this. argparse is another (non-standard) module that can handle situations where parameters have optional values.

With optparse you need to either specify a parameter, including its value, or leave both.

+1
source

Yes, this is an argument when you add this option:

 from optparse import OptionParser parser = OptionParser() parser.add_option("--SomeData",action="store", dest="TheData", default='') 

Give the default argument the value that you want this parameter to be specified, but does not necessarily have an argument.

0
source

Optparse already allows you to pass an empty string as an argument to an option. Therefore, if possible, treat the empty string as "no value". For long parameters, any of the following works:

 my_script --opt= --anotheroption my_script --opt='' --anotheroption my_script --opt="" --anotheroption my_script --opt '' --anotheroption my_script --opt "" --anotheroption 

For short styles, you can use any of the following options:

 my_script -o '' --anotheroption my_script -o "" --anotheroption 

Caution: this has been tested under Linux and should work the same on other Unix-like systems; Windows processes the command line quoting differently, and may not accept all of the options listed above.

0
source

Mark Roddy's solution will work, but it requires modification of the attribute of the parser object at runtime and does not support alternative formatting options other than - or -. A less attractive solution is to modify the sys.argv array before running optparse and insert an empty string ("") after the switch, for which there is no need to have arguments. The only limitation of this method is that you have your own default options for a predicted value other than the one you insert in sys.argv (I chose None for the example below, but it really doesn't matter).

The following code creates an example parser and a set of parameters, extracts an array of allowed keys from the parser (using a little instance of the magic variable), and then iterates through sys.argv and each time it finds an allowed switch, it checks if it is not specified any arguments. If there is no argument after the switch, an empty line will be inserted into the line command. After changing sys.argv, the parser is called, and you can check the parameters whose values ​​are "" and act accordingly.

 #Instantiate the parser, and add some options; set the options' default values to None, or something predictable that #can be checked later. PARSER_DEFAULTVAL = None parser = OptionParser(usage="%prog -[MODE] INPUT [options]") #This method doesn't work if interspersed switches and arguments are allowed. parser.allow_interspersed_args = False parser.add_option("-d", "--delete", action="store", type="string", dest="to_delete", default=PARSER_DEFAULTVAL) parser.add_option("-a", "--add", action="store", type="string", dest="to_add", default=PARSER_DEFAULTVAL) #Build a list of allowed switches, in this case ['-d', '--delete', '-a', '--add'] so that you can check if something #found on sys.argv is indeed a valid switch. This is trivial to make by hand in a short example, but if a program has #a lot of options, or if you want an idiot-proof way of getting all added options without modifying a list yourself, #this way is durable. If you are using OptionGroups, simply run the loop below with each group option_list field. allowed_switches = [] for opt in parser.option_list: #Add the short (-a) and long (--add) form of each switch to the list. allowed_switches.extend(opt._short_opts + opt._long_opts) #Insert empty-string values into sys.argv whenever a switch without arguments is found. for a in range(len(sys.argv)): arg = sys.argv[a] #Check if the sys.argv value is a switch if arg in allowed_switches: #Check if it doesn't have an accompanying argument (ie if it is followed by another switch, or if it is last #on the command line) if a == len(sys.argv) - 1 or argv[a + 1] in allowed_switches: sys.argv.insert(a + 1, "") options, args = parser.parse_args() #If the option is present (ie wasn't set to the default value) if not (options.to_delete == PARSER_DEFAULTVAL): if options.droptables_ids_csv == "": #The switch was not used with any arguments. ... else: #The switch had arguments. ... 
0
source

After verifying that the cp command understands, for example. --backup=simple , but not --backup simple , I answered this problem as follows:

 import sys from optparse import OptionParser def add_optval_option(pog, *args, **kwargs): if 'empty' in kwargs: empty_val = kwargs.pop('empty') for i in range(1, len(sys.argv)): a = sys.argv[i] if a in args: sys.argv.insert(i+1, empty_val) break pog.add_option(*args, **kwargs) def main(args): parser = OptionParser() add_optval_option(parser, '--foo', '-f', default='MISSING', empty='EMPTY', help='"EMPTY" if given without a value. Note: ' '--foo=VALUE will work; --foo VALUE will *not*!') o, a = parser.parse_args(args) print 'Options:' print ' --foo/-f:', o.foo if a[1:]: print 'Positional arguments:' for arg in a[1:]: print ' ', arg else: print 'No positional arguments' if __name__=='__main__': import sys main(sys.argv) 

Self-promotion: this is part of the opo module of my thebops package ...; -)

0
source

All Articles