Call another click command from a click command
我想使用一些有用的功能作为命令。 为此,我正在测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | import click import os, sys @click.command() @click.argument('content', required=False) @click.option('--to_stdout', default=True) def add_name(content, to_stdout=False): if not content: content = ''.join(sys.stdin.readlines()) result = content +"\ \\tadded name" if to_stdout is True: sys.stdout.writelines(result) return result @click.command() @click.argument('content', required=False) @click.option('--to_stdout', default=True) def add_surname(content, to_stdout=False): if not content: content = ''.join(sys.stdin.readlines()) result = content +"\ \\tadded surname" if to_stdout is True: sys.stdout.writelines(result) return result @click.command() @click.argument('content', required=False) @click.option('--to_stdout', default=False) def add_name_and_surname(content, to_stdout=False): result = add_surname(add_name(content)) if to_stdout is True: sys.stdout.writelines(result) return result |
这样,我可以使用
1 2 3 4 5 | $ echo"original content" | add_name | add_surname original content added name added surname |
但是,使用不同的单击命令作为函数时,我需要解决一个小问题:
1 2 3 4 5 | $echo"original content" | add_name_and_surname Usage: add_name_and_surname [OPTIONS] [CONTENT] Error: Got unexpected extra arguments (r i g i n a l c o n t e n t ) |
我不知道为什么它不起作用,我需要这个
当您直接从另一个函数调用
我建议修改您的实现,以使原始功能保持不变,并为它们创建特定于单击的瘦包装器,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def add_name(content, to_stdout=False): if not content: content = ''.join(sys.stdin.readlines()) result = content +"\ \\tadded name" if to_stdout is True: sys.stdout.writelines(result) return result @click.command() @click.argument('content', required=False) @click.option('--to_stdout', default=True) def add_name_command(content, to_stdout=False): return add_name(content, to_stdout) |
然后,您可以直接调用这些函数,也可以通过setup.py创建的CLI包装器脚本来调用它们。
这似乎是多余的,但实际上可能是正确的方法:一个功能代表您的业务逻辑,另一个功能(单击命令)是一个"控制器",可通过命令行公开此逻辑(出于某种原因,例如,也是通过Web服务公开相同逻辑的函数)。
实际上,我什至建议将它们放在单独的Python模块中-您的"核心"逻辑和特定于点击的实现,如果需要,可以将其替换为任何其他接口。
由于单击装饰器,不能仅通过指定参数来调用函数。
Context类是您的朋友,特别是:
因此,您的add_name_and_surname代码应如下所示:
1 2 3 4 5 6 7 8 9 | @click.command() @click.argument('content', required=False) @click.option('--to_stdout', default=False) @click.pass_context def add_name_and_surname(ctx, content, to_stdout=False): result = ctx.invoke(add_surname, content=ctx.forward(add_name)) if to_stdout is True: sys.stdout.writelines(result) return result |
参考:
http://click.pocoo.org/6/advanced/#invoking-other-commands
我发现这些解决方案更加复杂。我希望下面的这个函数可以从另一个包的另一个地方调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 | @click.command(help='Clean up') @click.argument('path', nargs=1, default='def') @click.option('--info', '-i', is_flag=True, help='some info1') @click.option('--total', '-t', is_flag=True, help='some info2') def clean(path, info, total): #some definition, some actions #this function will help us def get_function(function_name): if function_name == 'clean': return clean |
我有另一个软件包,所以,我想单击此软件包中的上面的命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import somepackage1 #here is clean up click command from click.testing import CliRunner @check.command(context_settings=dict( ignore_unknown_options=True, )) @click.argument('args', nargs=-1) @click.pass_context def check(ctx, args): runner = CliRunner() if len(args[0]) == 0: logger.error('Put name of a command') if len(args) > 0: result = runner.invoke(somepackage1.get_function(args[0]), args[1:]) logger.print(result.output) else: result = runner.invoke(somepackage1.get_function(args[0])) logger.print(result.output) |
因此,它有效。
1 | python somepackage2 check clean params1 --info |