我正在使用Python 3.7和水泥3.0.4
我有一个带控制器的基本应用程序,控制器有一个命令,该命令接受一个可选参数。我看到的是,如果我传递一个无效参数的命令,我会得到一个无效参数错误,正如我预期的那样,但我得到的是应用程序本身的“使用”输出,而不是控制器上的命令。以下是一个例子:
from cement import App, Controller, ex
class Base(Controller):
class Meta:
label = 'base'
@ex(help='example sub-command')
def cmd1(self):
print('Inside Base.cmd1()')
@ex(
arguments=[
(['-n', '--name'],
{'help': ''': The name you want printed out''',
'dest': 'name',
'required': False}),
],
help=' the help for cmd2.')
def cmd2(self):
print(self.app.pargs.name)
此应用程序有一个名为cmd2的命令,它接受一个可选参数-n
,如帮助所述,该参数将被打印出来。因此,如果我这样做:
with MyApp(argv=['cmd2', '-n', 'bob']) as app:
app.run()
我将提供以下输出:
bob
正如所料。但是,如果我将无效参数传递给cmd2:
with MyApp(argv=['cmd2', '-a', 'bob']) as app:
app.run()
我得到:
usage: myapp [-h] [-d] [-q] {cmd1,cmd2} ...
myapp: error: unrecognized arguments: -a bob
我希望看到的不是myapp的用法,而是cmd2命令的用法,类似于我对命令执行-h
:
with MyApp(argv=['cmd2', '-h']) as app:
app.run()
输出
usage: myapp cmd2 [-h] [-n NAME]
optional arguments:
-h, --help show this help message and exit
-n NAME, --name NAME : The name you want printed out
我意识到这大部分是委托给Argparse的,而不是由水泥处理的。我已经做了一些调试,我看到嵌套了多个ArgparseArgumentHandler
类。因此,在上面的例子中,有一个ArgparseArgumentHandler
for myapp
,它的动作中有一个SubParsersAction
,它有一个choices
字段,该字段有一个映射,其中包含控制器上的两个命令,cmd1
和cmd2
映射到它们自己的ArgparseArgumentHandler
当检测到无效参数时,它位于myapp
的ArgparseArgumentHandler中,因此它在myapp
上调用print_usage()
,而不是在被调用命令的ArgparseArgumentHandler
上调用cmd2
我对Argparse的了解有限,我确实觉得导航有点复杂。我现在能想到的唯一解决办法是对ArgparseArgumentHandler
进行子类化,重写error()
,并尝试确定错误是否是由已识别的参数引起的,如果是,请尝试找到它的解析器。。类似这样的伪代码:
class ArgparseArgumentOverride(ext_argparse.ArgparseArgumentHandler):
def error(self, message):
# determine if there are unknown args
args, argv = self.parse_known_args(self.original_arguments, self.original_namespace)
# we are in an error state and have unrecognized args
if argv:
controller_namespace = args.__controller_namespace__
for action in self._actions:
if action.choices is not None:
# we found an choice with our namespace
if action.choices[controller_namespace]:
command_parser= action.choices[controller_namespace]
# this should be the show_usage for the command
complete_command.print_usage(sys.stderr)
上面是伪代码,实际上这样做会让人感觉非常脆弱、容易出错和不可预测。我知道一定有更好的办法,我就是找不到。我已经在文档和资料中翻了好几个小时了,仍然没有找到我要找的东西。谁能告诉我我错过了什么?如果您能就如何在这里继续提供任何建议,我们将不胜感激。多谢
我对
cement
不熟悉,但您可以推断usage
是由argparse
生成的:如果错误与
sp2
参数关联,则用法反映了:但是
unknown
参数由主解析器处理。例如,如果我们改用parse_known_args
:未知参数作为
extras
列表返回parse_args
返回错误,而不是extras
在
_SubParsers_Action.__call__
中,相关代码为:理论上,您可以构造另一个
_SubParsersAction
类(或子类),以不同的方式处理arg_strings
。将parse_known_args
调用更改为parse_args
就足够了:请注意
parse_args
调用parse_known_args
,如果存在未知项,则引发错误:相关问题 更多 >
编程相关推荐