Python 从代码中调用click命令

Python 从代码中调用click命令,python,command-line-interface,python-click,Python,Command Line Interface,Python Click,我有一个函数,它被包装成一个命令,使用。看起来是这样的: @click.command() @click.option('-w', '--width', type=int, help="Some helping message", default=0) [... some other options ...] def app(width, [... some other option arguments...]): [... function code...] call_click_c

我有一个函数,它被包装成一个命令,使用。看起来是这样的:

@click.command()
@click.option('-w', '--width', type=int, help="Some helping message", default=0)
[... some other options ...]
def app(width, [... some other option arguments...]):
    [... function code...]
call_click_command(app, width, [... other arguments ...])
我对这个函数有不同的用例。有时,通过命令行调用它是可以的,但有时我也希望直接调用该函数

from file_name import app
width = 45
app(45, [... other arguments ...]) 
我们怎么能做到呢?如何使用click调用已包装为命令的函数?我发现了这一点,但我不清楚如何使其适应我的情况(即,从头构建一个上下文类,并在click命令函数之外使用它)


编辑:我应该提到:我无法(轻松)修改包含要调用的函数的包。因此,我正在寻找的解决方案是如何从调用者端处理它。

您可以通过从参数重构命令行,从常规代码调用
click
命令函数。使用您的示例,它可能看起来像这样:

@click.command()
@click.option('-w', '--width', type=int, help="Some helping message", default=0)
[... some other options ...]
def app(width, [... some other option arguments...]):
    [... function code...]
call_click_command(app, width, [... other arguments ...])
代码: 这是怎么回事? 这是因为click是一个设计良好的OO框架。可以对
@click.Command
对象进行内省,以确定它所需的参数。然后可以构造一个命令行,该命令行看起来与click所期望的命令行类似

测试代码: 测试结果:
我尝试使用Python 3.7,并单击7以查看以下代码:

导入单击
@click.command()命令
@单击.option('-w','-width',type=int,默认值=0)
@单击.option(“--option2”)
@单击.argument('argument')
def应用程序(宽度、选项2、参数):
click.echo(“参数:{}{}}”。格式(宽度,选项2,参数))
断言宽度==3
断言选项2==“4”
断言参数=='arg'
应用程序([“arg”、“--option2”、“4”、“-w”、3])
应用程序([“arg”、“-w”、3、“--option2”、“4”])
应用程序([“-w”,3,“--option2”,“4”,“arg]”)
所有
应用程序
呼叫都正常工作

这个用例是

有时,从一个命令调用另一个命令可能会很有趣。这是一种通常不鼓励点击的模式,但仍然有可能。为此,可以使用Context.invoke()或Context.forward()方法

它们的工作原理类似,但区别在于Context.invoke()仅使用您作为调用方提供的参数调用另一个命令,而Context.forward()则填充当前命令的参数


如果只想调用底层函数,可以通过
click.Command.callback
直接访问它。单击将底层包装的Python函数存储为类成员。请注意,直接调用该函数将绕过所有单击验证,并且不会有任何单击上下文信息

下面是一个示例代码,它迭代当前Python模块中的所有
click.Command
对象,并从中生成可调用函数的字典

从functools导入部分
从检查导入getmembers
导入点击
单击命令的所有函数={}
定义调用单击命令(cmd:click.command,*args,**kwargs):
结果=cmd.callback(*args,**kwargs)
返回结果
#从当前模块中拉出所有单击命令
module=sys.modules[\u\u名称\u\u]
对于名称,getmembers(模块)中的obj:
如果isinstance(对象,单击.Command)而不是isinstance(对象,单击.Group):
#创建一个调用click命令的包装Python函数。
#Click在命令名中使用破折号,破折号不是有效的Python语法
名称=名称。替换(“-”和“”)
#我们还正确设置了该函数的docstring。
func=部分(\u调用\u单击\u命令,obj)
职能文件=目标文件__
单击命令的所有函数[name]=func

可以在源代码中找到完整的示例。

您在外部给出的内容(对我来说)不够清楚。我只收到一个调用:
params:3 4 arg
在py 3.6.8中,单击7.0。不方便,你不能再调用app(1,2,3)了…@jaromrax你的意思是在第一次调用app后程序会退出吗?我有这个问题,并通过在每个应用程序调用中使用try-except语句来修复它。特别是系统退出除外
Click Version: 6.7
Python Version: 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)]
-----------
> (3, 4, 'arg', {})
params: 3 4 arg
-----------
> (3, 4, {'argument': 'arg'})
params: 3 4 arg
-----------
> (3, {'option2': 4, 'argument': 'arg'})
params: 3 4 arg
-----------
> ({'width': 3, 'option2': 4, 'argument': 'arg'},)
params: 3 4 arg
cli = click.Group()

@cli.command()
@click.option('--count', default=1)
def test(count):
    click.echo('Count: %d' % count)

@cli.command()
@click.option('--count', default=1)
@click.pass_context
def dist(ctx, count):
    ctx.forward(test)
    ctx.invoke(test, count=42)