python - 单击 CLI 中缺少 1 个必需的位置参数
问题描述
我已经编写了一个带有 click 的 CLI,最初是作为一个模块,它工作得很好。但是由于我的项目变得更大,我现在需要具有 CLI 可以使用的属性,所以我试图将它变成一个类,但我遇到了一个错误。我的代码如下:
import click
import click_repl
import os
from prompt_toolkit.history import FileHistory
class CLI:
def __init__(self):
pass
@click.group(invoke_without_command=True)
@click.pass_context
def cli(self, ctx):
if ctx.invoked_subcommand is None:
ctx.invoke(self.repl)
@cli.command()
def foo(self):
print("foo")
@cli.command()
def repl(self):
prompt_kwargs = {
'history': FileHistory(os.path.expanduser('~/.repl_history'))
}
click_repl.repl(click.get_current_context(), prompt_kwargs)
def main(self):
while True:
try:
self.cli(obj={})
except SystemExit:
pass
if __name__ == "__main__":
foo = CLI()
foo.main()
没有所有的self
s 和class CLI:
CLI 按预期工作,但作为一个类它会遇到错误:TypeError: cli() missing 1 required positional argument: 'ctx'
我不明白为什么会发生这种情况。据我所知,调用self.cli()
应该self
自动传递,因此obj={}
应该作为 ctx.obj 传递,所以它不应该cli
对它是否包含在一个类中产生任何影响。
有人可以向我解释,为什么会发生这种情况,更重要的是,我该如何解决?
如果这里相关的是完整的错误堆栈跟踪:
Traceback (most recent call last):
File "C:/Users/user/.PyCharmCE2018.2/config/scratches/exec.py", line
37, in <module>
foo.main()
File "C:/Users/user/.PyCharmCE2018.2/config/scratches/exec.py", line
30, in main
self.cli(obj={})
File "C:\Users\user\AppData\Local\Programs\Python\Python37\lib\site- packages\click\core.py", line 764, in __call__
return self.main(*args, **kwargs)
File "C:\Users\user\AppData\Local\Programs\Python\Python37\lib\site-packages\click\core.py", line 717, in main
rv = self.invoke(ctx)
File "C:\Users\user\AppData\Local\Programs\Python\Python37\lib\site-packages\click\core.py", line 1114, in invoke
return Command.invoke(self, ctx)
File "C:\Users\user\AppData\Local\Programs\Python\Python37\lib\site-packages\click\core.py", line 956, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "C:\Users\user\AppData\Local\Programs\Python\Python37\lib\site-packages\click\core.py", line 555, in invoke
return callback(*args, **kwargs)
File "C:\Users\user\AppData\Local\Programs\Python\Python37\lib\site-packages\click\decorators.py", line 17, in new_func
return f(get_current_context(), *args, **kwargs)
TypeError: cli() missing 1 required positional argument: 'ctx'
编辑:问题似乎是pass_context
电话。通常pass_context
会将当前上下文作为函数的第一个参数提供,以便obj={}
将其传递给上下文实例。但由于我将点击组包装到一个类中,第一个位置由self
-reference 占据,因此当前上下文无法传递给函数。关于如何解决这个问题的任何想法?
我尝试更改def cli()
以下方式:
@click.group(invoke_without_command=True)
def cli(self):
ctx = click.get_current_context()
ctx.obj = {}
if ctx.invoked_subcommand is None:
ctx.invoke(self.repl)
所以我不会通过调用来传递上下文,以避免与 冲突self
,但是如果我尝试运行它,则会发生self.cli()
错误TypeError: cli() missing 1 required positional argument: 'self'
。调用它时self.cli(self)
遇到TypeError: 'CLI' object is not iterable
解决方案
恐怕 click 库不是为类而设计的。Click 使用了装饰器。不要太轻视装饰器。装饰器实际上将您的函数作为参数并返回不同的函数。
例如:
@cli.command()
def foo(self):
是否符合
foo = cli.command()(foo)
所以,恐怕click已经不支持修饰类绑定的函数了,只能修饰未绑定的函数。所以,基本上你的答案的解决方案是,不要使用类。
您现在可能想知道如何组织您的代码。大多数语言将班级作为一个组织单位呈现给您。
然而,Python 更进了一步,也为您提供了模块。基本上,一个文件就是一个模块,在这个文件中,你放入的所有内容都会作为一个模块自动与该文件相关联。
因此,只需命名一个文件cli.py
并将您的属性创建为全局变量。这可能会给您带来其他问题,因为您无法在函数范围内更改全局变量,但您可以使用类来包含您的变量。
class Variables:
pass
variables = Variables()
variables.something = "Something"
def f():
variables.something = "Nothing"
推荐阅读
- java - 有没有办法在 JSoup 的搜索栏中搜索多个关键字?
- javascript - 与服务器通信
- python - 如何在没有明确定义的字段值的情况下初始化字典
- c++ - 如果将其用作 Map 中的键,为什么使用不是 const 的操作数 < 函数定义结构会破坏事情?
- typescript - 从 node_modules 导入时,如果没有“new”,就不能调用类构造函数 Rectangle
- css - 不能在另一个图像上重叠多个图像?
- yarnpkg - 如何在同一台机器上安装 Yarn v1 和 Yarn v2 以便它们可以在项目之间互换使用?
- java - 如何覆盖 Spring Security 中特定端点的角色?
- python - 使用 Python 请求与 suiteCRM API V7.9 交互
- java - 使用简单的 for 循环将列表中的搜索转换为流方法