在点击CLI中缺少1个必需的位置参数

时间:2018-10-25 07:02:30

标签: python python-3.x

我最初使用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()

在没有所有selfclass CLI:的情况下,CLI可以按预期运行,但是作为一个类,它会遇到错误:TypeError: cli() missing 1 required positional argument: 'ctx'我不明白为什么会这样。据我所知,调用self.cli()应该自动传递self,因此obj={}应该作为ctx.obj传递,因此,如果cliTraceback (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传递给上下文实例。但是由于我将点击组包装到了一个类中,所以第一个位置是由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调用会遇到time_vector = ['06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '00', '01', '02', '03', '04', '05', '06'] doublezeroes = "00" timelist=list(map(lambda x:x+doublezeroes, time_vector)) print(timelist)

1 个答案:

答案 0 :(得分:2)

恐怕点击库的设计目的不是作为一个类。 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"