如何在类方法中使用 Python @click 命令装饰器?

shu*_*sal 5 python-3.x python-click python-3.7

我的 Python 脚本有一个名为Command. 我想将我的类的方法作为 CLI 命令调用(类似于python cli-comand.py net get-public-ip)。

我使用了Pythonclick库,但是当我尝试执行它时,它抛出了错误TypeError: get_public_ip() missing 1 required positional argument: 'self'

果然,我没能通过self。有什么方法可以将参数传递到类方法中,或者任何其他方法吗? click主要与函数一起使用。

我的Python脚本如下:

cli命令.py

import click
import urllib.request
from typing import List, AnyStr
from urllib.error import URLError

from ttn_cli.utils.constants import FETCH_PUBLIC_IP_URL


@click.group()
def cli():
    """
    This is the root function of cli module.
    """
    pass


@cli.group()
def net():
    """
    function act as a group which is linked to root cli function.
    """
    pass


class Command:

    def __init__(self):
        pass

    @net.command()  #  <-- click command
    def get_public_ip(self, *args) -> AnyStr:  # I want to use this method as a cli command
        """
        Function used to get public ip of your host.
        args: List of arguments provided
        """
        try:
            ip = urllib.request.urlopen(FETCH_PUBLIC_IP_URL).read().decode(
                "utf-8")
            return ip
        except URLError:
            return "Please check your internet connectivity"


cmd_network = Command()


def main() -> None:
    """
    This is the main function which returns a shell to user as well
    as can run cli commands directly.
    """
    cli()


if __name__ == "__main__":
    main()
Run Code Online (Sandbox Code Playgroud)

tmt*_*tmt 0

这是对一个老问题的迟到答案,但我希望将来有人会发现它有用......

您可以使用两个装饰器来帮助您实现这一目标:

  • click.pass_context应用于一个组,该组将为其提供一个上下文,您可以在该Command上下文上创建类的实例。
  • click.pass_obj应用于类的方法,该方法将该实例作为第一个参数传递。

在你的例子中它会像这样:

import click

@click.group()
def cli():
    pass

@cli.group()
@click.pass_context
def net(ctx):
    ctx.obj = Command()

class Command:
    @net.command()
    @click.pass_obj
    def get_public_ip(self, *args):
        ...

def main() -> None:
    cli()

if __name__ == "__main__":
    main()
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 它假设您有某种理由拥有main函数,否则您可以cli()直接在if __name__ == "__main__"块中调用。
  • 这在 click 8.1.3 中进行了测试。我不知道装饰器是在哪个版本中引入的。