OptionParser:显示额外信息并允许未指定的操作

时间:2013-11-17 21:00:45

标签: python command-line-arguments optparse

(标题应为OptionParser: show extra help,但标题中不允许使用help字样

我有OptionParser

parser = OptionParser(
    usage='usage: %s [options]' % (args[0]),
    version='%s Version %s' % (args[0], version))

parser.add_option('-a', '--action', choices=['menu'] , help='Allowed actions are: menu, and any menu action', default='menu')
parser.add_option('-1', '--file1',  type='string', help='First file')
parser.add_option('-2', '--file2',  type='string', help='Second file')
parser.add_option('--debug', action='store_true', help='run in debug mode')

使用--help致电给我:

Usage: /home/gonvaled/projects/bin/process_json.py [options]

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -a ACTION, --action=ACTION
                        Allowed actions are: menu, and any menu action
  -1 FILE1, --file1=FILE1
                        First file
  -2 FILE2, --file2=FILE2
                        Second file
  --debug               run in debug mode

这很好,但缺少动作。问题是某些操作是在Menu对象(我的实现)中定义的,只能通过执行以下操作来显示:

menu.showCommands()

也就是说,这些操作没有为OptionParser定义,但仍然可以通过命令行访问,因为menu以外的任何操作都将透明地传递给Menu对象被处理。因此,OptionParser提供的帮助并不了解这些行为。

如何告诉OptionParser对象在显示帮助文本时,必须添加一些外部信息?追加到最后就足够了。我看了docs,但似乎没有这样的选择。

修改

实际上运行我的程序表明不仅缺少帮助。更糟糕的是:optparse抱怨未知行为:

gonvaled@pegasus ~ » process_json.py -a prettyfy-from-obj
Usage: /home/gonvaled/projects/bin/process_json.py [options]

process_json.py: error: option -a: invalid choice: 'prettyfy-from-obj' (choose from 'menu')

如何告诉optparse接受action的未指定值?

1 个答案:

答案 0 :(得分:0)

您发送到choices参数的列表必须是该选项允许的所有可能参数的详尽列表。如果列表为['menu'],则唯一允许的值为menu。这解释了你得到的错误。

注意the optparse module is deprecated,您应该使用argparse

更简单的解决方案

不要使用choices并在之后验证参数。

parser.add_option('-a', '--action', help='Allowed actions are: menu, and any menu action', default='menu')
#...
options, args = parser.parse_args()

if options.action not in menu.showCommands():
    parser.error('Invalid action specified: %s' % options.action)

或者,如果您不能这样做,如果您使用调用menu.call(action, params)的操作并引发UnavailableAction例外:

parser.add_option('-a', '--action', help='Allowed actions are: menu, and any menu action', default='menu')
#...
options, args = parser.parse_args()
# do something as normal
try:
    menu.call(options.action, params)
except UnavailableAction:
    print "Incorrect option" # (1)
    # crash appropriately

如果解析器对象可用,您可以更改(1)以获取以下内容:

parser.error('Invalid action specified: %s' % options.action)

注意:这完全违背了使用choices的目的,但如果您无法在解析CLI的函数/方法/模块的范围内进行验证,则可以适用选项。


此问题的任何其他解决方案取决于您是否能够内省menu对象以获取可用操作列表。


使用选项

假设menu.showCommands只提供可用命令的字符串列表,我的第一个猜测是做类似的事情:

menu_choices = menu.showCommands().split()
menu_choices.append('menu')
parser.add_option('-a', '--action', choices=menu_choices , help='Allowed actions are: menu, and any menu action', default='menu')

如果无法获取该格式的操作列表,您可能需要“解析”menu.showCommands的输出

使用回调

您还可以将其实现为-a选项的回调:

def menu_option(option, opt_str, value, parser):
    if not value not in menu.showCommands().split():
        raise OptionValueError('Invalid action for menu')

parser.add_option('-a', '--action', action='callback', callback=menu_option, help='Allowed actions are: menu, and any menu action', default='menu')

此选项更灵活一些。例如,如果您使用名为has_action(menu, string)的函数来检查menu对象是否有可用的string操作,则可以执行以下操作:

def menu_option(option, opt_str, value, parser):
    if not has_action(menu, value):
        raise OptionValueError('Invalid action specified for menu: %s' % value)

更复杂的解决方案

可能有更复杂的解决方案。一些想法(可能或者 - 更可能 - 不起作用)是:

  • 继承OptionParser并创建您自己的所需内容(以便选择无效)
  • 如果menu有自己的OptionParser,请使用回调对其进行链式加载
  • 如果menu有自己的子解析器,have argparse use it directly