关于命令行:Python:如何在optparse中提供选项?

Python: How to make an option to be required in optparse?

我读过这个http://docs.python.org/release/2.6.2/library/optparse.html

但我不太清楚如何做出一个在公共场合被要求的选择?

我试图设置"Required=1",但有一个错误:

invalid keyword arguments: required

我想让我的脚本要求用户输入--file选项。我知道,当你不向action="store_true"--file提供值时,action关键字会给你带来错误。


您可以轻松实现所需的选项。

1
2
3
4
5
6
7
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')


在每一个必需变量的帮助消息上,我在begining处编写了一个'[required]'字符串,标记它以便稍后解析,然后我可以简单地使用此函数将其包装起来:

1
2
3
4
5
6
7
8
9
10
11
12
13
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)


因为if not x不起作用对于某些(负、零)参数,

为了防止大量的中频测试,我更喜欢这样的东西:

1
2
3
4
5
6
7
8
9
10
11
12
13
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)

我不得不在我们的解决方案中使用python2.6,所以我坚持使用optparse模块。这里有一个解决方案,我发现它可以在不指定第二次必需选项列表的情况下检查所需选项。因此,当您添加新选项时,不必将其名称添加到要检查的选项列表中。

所需选项-选项值的条件不应为"无",并且此选项没有默认值(用户未指定"添加选项"(默认值"…",…)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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

例如,如果参数是一个整数或浮点数,零是有效输入,那么投票最多的当前答案将不起作用。在这些情况下,会说有一个错误。另一种选择(在这里加上其他几个)是这样做,例如:

1
2
3
4
5
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')

使用optparse至少有两种实现所需选项的方法。正如docs页面中提到的,optparse不会阻止您实现所需的选项,但也不会为您提供太多帮助。在下面的示例中可以找到与源文件一起分发的文件。

尽管请注意,optparse模块自2.7版起已被弃用,不会进一步开发。您应该改为使用argparse模块。

版本1:向OptionParser添加一个方法,应用程序在分析参数后必须调用该方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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")

资料来源:docs/lib/required_1.txt

版本2:扩展选项并添加一个必需的属性;扩展选项分析器以确保在分析后存在必需的选项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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

资料来源:docs/lib/required_2.txt


由于optparse模块自2.7版以来已被弃用,因此您可能会在此处找到更多最新的示例:dead simple argparse example wanted:1个参数,3个结果


我还停留在python2.6上(对python2.7和argparse很感兴趣,它不仅具有必需的参数,而且允许我指定必须提供一个集合);我的方法需要第二次传递,但允许我提示缺少的参数,除非以批处理模式运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 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

(我正在考虑创建自己的解析器类,该类具有内置全局配置的通用选项。)

这个问题的另一个答案是parser.error,我在编写代码时不熟悉它,但它可能是更好的选择。


我将使用嵌入此功能的argparse库:

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

argparse引用