Python 如何将我的 Click 命令(每个命令都有一组子命令)拆分为多个文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34643620/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I split my Click commands, each with a set of sub-commands, into multiple files?
提问by Brad T
I have one large click application that I've developed, but navigating through the different commands/subcommands is getting rough. How do I organize my commands into separate files? Is it possible to organize commands and their subcommands into separate classes?
我开发了一个大型单击应用程序,但是浏览不同的命令/子命令变得越来越困难。如何将我的命令组织到单独的文件中?是否可以将命令及其子命令组织到单独的类中?
Here's an example of how I would like to separate it:
这是我想如何分离它的一个例子:
init
在里面
import click
@click.group()
@click.version_option()
def cli():
pass #Entry Point
command_cloudflare.py
command_cloudflare.py
@cli.group()
@click.pass_context
def cloudflare(ctx):
pass
@cloudflare.group('zone')
def cloudflare_zone():
pass
@cloudflare_zone.command('add')
@click.option('--jumpstart', '-j', default=True)
@click.option('--organization', '-o', default='')
@click.argument('url')
@click.pass_obj
@__cf_error_handler
def cloudflare_zone_add(ctx, url, jumpstart, organization):
pass
@cloudflare.group('record')
def cloudflare_record():
pass
@cloudflare_record.command('add')
@click.option('--ttl', '-t')
@click.argument('domain')
@click.argument('name')
@click.argument('type')
@click.argument('content')
@click.pass_obj
@__cf_error_handler
def cloudflare_record_add(ctx, domain, name, type, content, ttl):
pass
@cloudflare_record.command('edit')
@click.option('--ttl', '-t')
@click.argument('domain')
@click.argument('name')
@click.argument('type')
@click.argument('content')
@click.pass_obj
@__cf_error_handler
def cloudflare_record_edit(ctx, domain):
pass
command_uptimerobot.py
command_uptimerobot.py
@cli.group()
@click.pass_context
def uptimerobot(ctx):
pass
@uptimerobot.command('add')
@click.option('--alert', '-a', default=True)
@click.argument('name')
@click.argument('url')
@click.pass_obj
def uptimerobot_add(ctx, name, url, alert):
pass
@uptimerobot.command('delete')
@click.argument('names', nargs=-1, required=True)
@click.pass_obj
def uptimerobot_delete(ctx, names):
pass
采纳答案by jdno
The downside of using CommandCollection
for this is that it merges your commands and works only with command groups. The imho better alternative is to use add_command
to achieve the same result.
使用CommandCollection
它的缺点是它合并了您的命令并且仅适用于命令组。imho 更好的选择是使用add_command
来达到相同的结果。
I have a project with the following tree:
我有一个带有以下树的项目:
cli/
├── __init__.py
├── cli.py
├── group1
│?? ├── __init__.py
│?? ├── commands.py
└── group2
├── __init__.py
└── commands.py
Each subcommand has its own module, what makes it incredibly easy to manage even complex implementations with many more helper classes and files. In each module, the commands.py
file contains the @click
annotations. Example group2/commands.py
:
每个子命令都有自己的模块,这使得管理具有更多帮助程序类和文件的复杂实现变得非常容易。在每个模块中,该commands.py
文件都包含@click
注释。示例group2/commands.py
:
import click
@click.command()
def version():
"""Display the current version."""
click.echo(_read_version())
If necessary, you could easily create more classes in the module, and import
and use them here, thus giving your CLI the full power of Python's classes and modules.
如有必要,您可以轻松地在模块中创建更多类,并import
在此处使用它们,从而为您的 CLI 提供 Python 类和模块的全部功能。
My cli.py
is the entry point for the whole CLI:
Mycli.py
是整个 CLI 的入口点:
import click
from .group1 import commands as group1
from .group2 import commands as group2
@click.group()
def entry_point():
pass
entry_point.add_command(group1.command_group)
entry_point.add_command(group2.version)
With this setup, it is very easy to separate your commands by concerns, and also build additional functionality around them that they might need. It has served me very well so far...
通过这种设置,可以很容易地按关注点分离您的命令,并围绕它们构建他们可能需要的附加功能。到目前为止,它对我很有帮助......
Reference: http://click.pocoo.org/6/quickstart/#nesting-commands
回答by Achim
I'm not an click expert, but it should work by just importing your files into the main one. I would move all commands in separate files and have one main file importing the other ones. That way it is easier to control the exact order, in case it is important for you. So your main file would just look like:
我不是点击专家,但只需将您的文件导入主文件即可。我会将所有命令移动到单独的文件中,并让一个主文件导入其他文件。这样可以更容易地控制确切的顺序,以防它对您很重要。所以你的主文件看起来像:
import commands_main
import commands_cloudflare
import commands_uptimerobot
回答by Oscar David Arbeláez
I'm looking for something like this at the moment, in your case is simple because you have groups in each of the files, you can solve this problem as explained in the documentation:
我目前正在寻找类似的东西,在您的情况下很简单,因为您在每个文件中都有组,您可以按照文档中的说明解决这个问题:
In the init.py
file:
在init.py
文件中:
import click
from command_cloudflare import cloudflare
from command_uptimerobot import uptimerobot
cli = click.CommandCollection(sources=[cloudflare, uptimerobot])
if __name__ == '__main__':
cli()
The best part of this solution is that is totally compliant with pep8 and other linters because you don't need to import something you wouldn't use and you don't need to import * from anywhere.
这个解决方案最好的部分是完全符合 pep8 和其他 linter,因为你不需要导入你不会使用的东西,也不需要从任何地方导入 *。
回答by Diego Castro
Suppose your project have the following structure:
假设您的项目具有以下结构:
project/
├── __init__.py
├── init.py
└── commands
├── __init__.py
└── cloudflare.py
Groups are nothing more than multiple commands and groups can be nested. You can separate your groups into modules and import them on you init.py
file and add them to the cli
group using the add_command.
组只不过是多个命令,组可以嵌套。您可以将您的组分成模块并将它们导入到您的init.py
文件中,然后cli
使用 add_command将它们添加到组中。
Here is a init.py
example:
下面是一个init.py
例子:
import click
from .commands.cloudflare import cloudflare
@click.group()
def cli():
pass
cli.add_command(cloudflare)
You have to import the cloudflare group which lives inside the cloudflare.py file. Your commands/cloudflare.py
would look like this:
您必须导入位于 cloudflare.py 文件中的 cloudflare 组。你commands/cloudflare.py
会是这样的:
import click
@click.group()
def cloudflare():
pass
@cloudflare.command()
def zone():
click.echo('This is the zone subcommand of the cloudflare command')
Then you can run the cloudflare command like this:
然后你可以像这样运行 cloudflare 命令:
$ python init.py cloudflare zone
This information is not very explicit on the documentation but if you look at the source code, which is very well commented, you can see how groups can be nested.
该信息在文档中不是很明确,但是如果您查看注释非常好的源代码,您可以看到如何嵌套组。
回答by garlicbread
It took me a while to figure this out but I figured I'd put this here to remind myself when I forget how to do i again I think part of the problem is that the add_command function is mentioned on click's github page but not the main examples page
我花了一段时间才弄清楚这一点,但我想我会把它放在这里是为了提醒自己,当我再次忘记该怎么做时,我认为问题的一部分是在 click 的 github 页面上提到了 add_command 函数,但不是主要的示例页面
first lets create an initial python file called root.py
首先让我们创建一个名为 root.py 的初始 python 文件
import click
from cli_compile import cli_compile
from cli_tools import cli_tools
@click.group()
def main():
"""Demo"""
if __name__ == '__main__':
main.add_command(cli_tools)
main.add_command(cli_compile)
main()
Next lets put some tools commands in a file called cli_tools.py
接下来让我们将一些工具命令放在一个名为 cli_tools.py 的文件中
import click
# Command Group
@click.group(name='tools')
def cli_tools():
"""Tool related commands"""
pass
@cli_tools.command(name='install', help='test install')
@click.option('--test1', default='1', help='test option')
def install_cmd(test1):
click.echo('Hello world')
@cli_tools.command(name='search', help='test search')
@click.option('--test1', default='1', help='test option')
def search_cmd(test1):
click.echo('Hello world')
if __name__ == '__main__':
cli_tools()
Next lets put some compile commands in a file called cli_compile.py
接下来让我们将一些编译命令放在一个名为 cli_compile.py 的文件中
import click
@click.group(name='compile')
def cli_compile():
"""Commands related to compiling"""
pass
@cli_compile.command(name='install2', help='test install')
def install2_cmd():
click.echo('Hello world')
@cli_compile.command(name='search2', help='test search')
def search2_cmd():
click.echo('Hello world')
if __name__ == '__main__':
cli_compile()
running root.py should now give us
运行 root.py 现在应该给我们
Usage: root.py [OPTIONS] COMMAND [ARGS]...
Demo
Options:
--help Show this message and exit.
Commands:
compile Commands related to compiling
tools Tool related commands
running "root.py compile" should give us
运行“root.py compile”应该给我们
Usage: root.py compile [OPTIONS] COMMAND [ARGS]...
Commands related to compiling
Options:
--help Show this message and exit.
Commands:
install2 test install
search2 test search
You'll also notice you can run the cli_tools.py or cli_compile.py directly as well as I included a main statement in there
您还会注意到您可以直接运行 cli_tools.py 或 cli_compile.py 并且我在其中包含了一个主要语句