42

I've read this http://docs.python.org/release/2.6.2/library/optparse.html

But I'm not so clear how to make an option to be required in optparse?

I've tried to set "required=1" but I got an error:

invalid keyword arguments: required

I want to make my script require --file option to be input by users. I know that the action keyword gives you error when you don't supply value to --file whose action="store_true".

Rashwan L
  • 38,237
  • 7
  • 103
  • 107
jack
  • 1,415
  • 4
  • 15
  • 22
  • 2
    in any browser press control+F and type "required": http://www.koders.com/python/fidDA675C6BA2AB578095C3FCB8215FFB6B60B34E45.aspx?s=cdef:parser#L3, http://www.koders.com/python/fid27A3EC36EE5D1DBA190DA19F6428F12B97BA1768.aspx?s=cdef:parser#L20 – Ruggero Turra Dec 10 '10 at 09:54
  • 6
    Maybe you should consider using the [`argparse`](http://docs.python.org/library/argparse.html#module-argparse) module instead. – martineau Dec 10 '10 at 21:14
  • 5
    I enjoy the snarky quote `the phrase “required option” is self-contradictory in English` from [OptParse's manual page](http://docs.python.org/2/library/optparse.html#terminology). – dbn Feb 02 '13 at 08:22

9 Answers9

70

You can implement a required option easily.

parser = OptionParser(usage='usage: %prog [options] arguments')
parser.add_option('-f', '--file', 
                        dest='filename',
                        help='foo help')
(options, args) = parser.parse_args()
if not options.filename:   # if filename is not given
    parser.error('Filename not given')
user225312
  • 126,773
  • 69
  • 172
  • 181
  • 5
    @Ant: Yeah I know but the brackets signify that `parser.parse_args()` returns a `tuple`, so I let them stay! – user225312 Dec 10 '10 at 10:31
  • 1
    Does this mean "required" option is only with argparse, but not optparse? The answer is good though, I don't see why this cannto be accepted? – ha9u63a7 Jan 07 '15 at 20:11
  • 1
    The optparse module is deprecated since version 2.7. Example with argparse here: http://stackoverflow.com/questions/7427101/dead-simple-argparse-example-wanted-1-argument-3-results – PatriceG Nov 23 '15 at 15:28
  • So If Im understanding this properly, is optparse just older than argparse? – Tom Nov 23 '16 at 18:53
  • For option group, you can use the following: `for group in parser.option_groups:...` – Pankaj Garg Jun 14 '17 at 06:46
16

Since if not x doesn't work for some(negative,zero) parameters,

and to prevent lots of if tests, i preferr something like this:

required="host username password".split()

parser = OptionParser()
parser.add_option("-H", '--host', dest='host')
parser.add_option("-U", '--user', dest='username')
parser.add_option("-P", '--pass', dest='password')
parser.add_option("-s", '--ssl',  dest='ssl',help="optional usage of ssl")

(options, args) = parser.parse_args()

for r in required:
    if options.__dict__[r] is None:
        parser.error("parameter %s required"%r)
Serge M.
  • 253
  • 3
  • 8
10

On the help message of each required variable Im writting a '[REQUIRED]' string at the beggining, to tag it to be parsed later, then I can simply use this function to wrap it around:

def checkRequiredArguments(opts, parser):
    missing_options = []
    for option in parser.option_list:
        if re.match(r'^\[REQUIRED\]', option.help) and eval('opts.' + option.dest) == None:
            missing_options.extend(option._long_opts)
    if len(missing_options) > 0:
        parser.error('Missing REQUIRED parameters: ' + str(missing_options))

parser = OptionParser()
parser.add_option("-s", "--start-date", help="[REQUIRED] Start date")
parser.add_option("-e", "--end-date", dest="endDate", help="[REQUIRED] End date")
(opts, args) = parser.parse_args(['-s', 'some-date'])
checkRequiredArguments(opts, parser)
  • 2
    Nice - thank you. But to speed it up and avoid the need to `import re`, use the string `startwith` method like this: `if option.help.startswith('[REQUIRED]')`... – nealmcb Dec 04 '16 at 21:29
5

The current answer with the most votes would not work if, for example, the argument were an integer or float for which zero is a valid input. In these cases it would say that there is an error. An alternative (to add to the several others here) would be to do e.g.

parser = OptionParser(usage='usage: %prog [options] arguments')
parser.add_option('-f', '--file', dest='filename')
(options, args) = parser.parse_args()
if 'filename' not in options.__dict__:
  parser.error('Filename not given')
Community
  • 1
  • 1
Matt Pitkin
  • 3,989
  • 1
  • 18
  • 32
3

I'm forced to use python 2.6 for our solution so I'm stick to optparse module. Here is solution I found to check for required options that works without specifying second time list of required options. Thus when you add new option you don't have to add it's name into the list of options to check.

My criteria for required option - option value should be not None and this options doesn't have default (user didn't specified add_option(default="...",...).

def parse_cli():
    """parse and check command line options, shows help message
    @return: dict - options key/value
    """
    import __main__
    parser = OptionParser(description=__main__.__doc__)
    parser.add_option("-d", "--days", dest="days",
                      help="Number of days to process")
    parser.add_option("-p", "--period", dest="period_length",default="2",
              help="number or hours per iteration, default value=%default hours")    
    (options, args) = parser.parse_args()

    """get dictionary of options' default values. 
       in this example: { 'period_length': '2','days': None}"""
    defaults = vars(parser.get_default_values())
    optionsdict = vars(options)

    all_none = False        
    for k,v in optionsdict.items():
        if v is None and defaults.get(k) is None:
            all_none = True


    if all_none:
        parser.print_help()
        sys.exit()
    return optionsdict
vvladymyrov
  • 5,715
  • 2
  • 32
  • 50
1

There are at least two methods of implementing required options with optparse. As mentioned in the docs page, optparse doesn’t prevent you from implementing required options, but doesn’t give you much help at it either. Find below the examples found in files distributed with the source.

Although please note that optparse module is deprecated since version 2.7 and will not be developed further. You should use argparse module instead.


Version 1: Add a method to OptionParser which applications must call after parsing arguments:

import optparse

class OptionParser (optparse.OptionParser):

    def check_required (self, opt):
      option = self.get_option(opt)

      # Assumes the option's 'default' is set to None!
      if getattr(self.values, option.dest) is None:
          self.error("%s option not supplied" % option)


parser = OptionParser()
parser.add_option("-v", action="count", dest="verbose")
parser.add_option("-f", "--file", default=None)
(options, args) = parser.parse_args()

print "verbose:", options.verbose
print "file:", options.file
parser.check_required("-f")

Source: docs/lib/required_1.txt


Version 2: Extend Option and add a required attribute; extend OptionParser to ensure that required options are present after parsing:

import optparse

class Option (optparse.Option):
    ATTRS = optparse.Option.ATTRS + ['required']

    def _check_required (self):
        if self.required and not self.takes_value():
            raise OptionError(
                "required flag set for option that doesn't take a value",
                 self)

    # Make sure _check_required() is called from the constructor!
    CHECK_METHODS = optparse.Option.CHECK_METHODS + [_check_required]

    def process (self, opt, value, values, parser):
        optparse.Option.process(self, opt, value, values, parser)
        parser.option_seen[self] = 1


class OptionParser (optparse.OptionParser):

    def _init_parsing_state (self):
        optparse.OptionParser._init_parsing_state(self)
        self.option_seen = {}

    def check_values (self, values, args):
        for option in self.option_list:
            if (isinstance(option, Option) and
                option.required and
                not self.option_seen.has_key(option)):
                self.error("%s not supplied" % option)
        return (values, args)


parser = OptionParser(option_list=[
    Option("-v", action="count", dest="verbose"),
    Option("-f", "--file", required=1)])
(options, args) = parser.parse_args()

print "verbose:", options.verbose
print "file:", options.file

Source: docs/lib/required_2.txt

kenorb
  • 155,785
  • 88
  • 678
  • 743
0

I'm also stuck on python 2.6 (pining for python2.7 and argparse, which not only has required arguments, but lets me specify that one of a set must be supplied); my approach requires a second pass, but lets me prompt for missing arguments unless running in batch mode:

# from myscript
import helpers
import globalconfig 
parser = optparse.OptionParser(usage=myheader,epilog=myfooter)
parser.add_option("-L","--last",
                  action="store",dest="last_name",default="",
                  help="User's last (family) name; prompted for if not supplied"
                 )
parser.add_option("-y","--yes",
                  action="store_true",dest="batch_flag",default=False,
                  help="don't prompt to confirm actions (batch mode)"
                  )
[...]
(options, args) = parser.parse_args()
globalconfig.batchmode = options.batch_flag
[...]
last = prompt_if_empty(options.last_name,
        "Last name (can supply with \"-L\" or \"--last\" option):")


# from helpers.py
def prompt_if_empty(variable,promptstring):
    if not variable:
        if globalconfig.batchmode:
            raise Exception('Required variable missing.')
        print "%s" %promptstring
        variable = raw_input(globalconfig.prompt)
    return variable

(I'm thinking of making my own parser class that has common options for global configs baked in.)

Another answer to this question cited parser.error, which I was unfamiliar with when I wrote the code, but might have been a better choice.

arp
  • 299
  • 3
  • 7
0

As the optparse module is deprecated since version 2.7, you will probably find some more up to date examples here: Dead simple argparse example wanted: 1 argument, 3 results

Community
  • 1
  • 1
PatriceG
  • 3,851
  • 5
  • 28
  • 43
-4

I would use argparse library that has this functionality embedded:

PARSER.add_argument("-n", "--namespace", dest="namespace", required=True,
              help="The path within the repo to the data base")

argparse reference

Zioalex
  • 3,441
  • 2
  • 33
  • 30