有没有办法使用argparse
挂钩的模块作为接口中每个提示的解释器继承自cmd
?
我希望我的 cmd 接口以与解释line
在运行时在 bash shell 上传递的选项和参数相同的方式解释典型参数,使用可选参数-
以及位置参数。
有没有办法使用argparse
挂钩的模块作为接口中每个提示的解释器继承自cmd
?
我希望我的 cmd 接口以与解释line
在运行时在 bash shell 上传递的选项和参数相同的方式解释典型参数,使用可选参数-
以及位置参数。
好吧,一种方法是重写cmd
的default
方法并使用它来解析带有 的行,因为cmd.Cmd 子类中argparse
没有方法的所有命令都将无法使用该方法。请注意之前的附加内容,以避免将其用作' 命令。do_
default
_
do_test
cmd
import argparse
import cmd
import shlex
class TestCLI(cmd.Cmd):
def __init__(self, **kwargs):
cmd.Cmd.__init__(self, **kwargs)
self.parser = argparse.ArgumentParser()
subparsers = self.parser.add_subparsers()
test_parser = subparsers.add_parser("test")
test_parser.add_argument("--foo", default="Hello")
test_parser.add_argument("--bar", default="World")
test_parser.set_defaults(func=self._do_test)
def _do_test(self, args):
print args.foo, args.bar
def default(self, line):
args = self.parser.parse_args(shlex.split(line))
if hasattr(args, 'func'):
args.func(args)
else:
cmd.Cmd.default(self, line)
test = TestCLI()
test.cmdloop()
argparse
如果遇到未知命令,则执行 a sys.exit
,因此您需要覆盖或修改您ArgumentParser
的 'error
方法以引发异常,而不是退出并在default
方法中处理该异常,以便留在cmd
' 的命令循环中。
我建议你研究一下悬崖,它允许你编写可以自动用作 asargparse
和cmd
commands 的命令,这非常简洁。它还支持从setuptools
入口点加载命令,这允许您将命令作为插件分发到您的应用程序。但是请注意,cliff
使用cmd2
,它是cmd
更强大的表亲,但您可以替换它cmd
,因为它cmd2
是作为cmd
.
直接的方法是创建一个argparse
解析器,并在您的函数中解析,line.split()
以防提供无效参数(在找到无效参数时调用)。expect
SystemExit
parse_args()
sys.exit()
class TestInterface(cmd.Cmd):
__test1_parser = argparse.ArgumentParser(prog="test1")
__test1_parser.add_argument('--bar', help="bar help")
def help_test1(self): self.__test1_parser.print_help()
def do_test1(self, line):
try:
parsed = self.__test1_parser.parse_args(line.split())
except SystemExit:
return
print("Test1...")
print(parsed)
如果传递了无效的参数,parse_args()
将打印错误,程序将返回界面而不退出。
(Cmd) test1 --unk
usage: test1 [-h] [--bar BAR]
test1: error: unrecognized arguments: --unk
(Cmd)
其他一切都应该与常规argparse
用例一样工作,同时维护所有cmd
的功能(帮助消息、功能列表等)
来源:https ://groups.google.com/forum/#!topic/argparse-users/7QRPlG97cak
另一种简化上述设置的方法是使用下面的装饰器:
class ArgparseCmdWrapper:
def __init__(self, parser):
"""Init decorator with an argparse parser to be used in parsing cmd-line options"""
self.parser = parser
self.help_msg = ""
def __call__(self, f):
"""Decorate 'f' to parse 'line' and pass options to decorated function"""
if not self.parser: # If no parser was passed to the decorator, get it from 'f'
self.parser = f(None, None, None, True)
def wrapped_f(*args):
line = args[1].split()
try:
parsed = self.parser.parse_args(line)
except SystemExit:
return
f(*args, parsed=parsed)
wrapped_f.__doc__ = self.__get_help(self.parser)
return wrapped_f
@staticmethod
def __get_help(parser):
"""Get and return help message from 'parser.print_help()'"""
f = tempfile.SpooledTemporaryFile(max_size=2048)
parser.print_help(file=f)
f.seek(0)
return f.read().rstrip()
它使定义附加命令变得更简单,它们采用parsed
包含成功结果的额外参数parse_args()
。如果有任何无效参数,则永远不会进入该函数,所有内容都由装饰器处理。
__test2_parser = argparse.ArgumentParser(prog="test2")
__test2_parser.add_argument('--foo', help="foo help")
@WrapperCmdLineArgParser(parser=__test2_parser)
def do_test2(self, line, parsed):
print("Test2...")
print(parsed)
一切都像原始示例一样工作,包括argparse
生成的帮助消息 - 无需定义help_command()
函数。
来源:https ://codereview.stackexchange.com/questions/134333/using-argparse-module-within-cmd-interface