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
我想让我的脚本要求用户输入
您可以轻松实现所需的选项。
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) |
因为
为了防止大量的中频测试,我更喜欢这样的东西:
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') |
使用
尽管请注意,
版本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") |
资料来源:
版本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 |
资料来源:
由于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引用