Python 在单击时包含子模块
我正在尝试对我的第一个Click CLI应用程序进行一种递归调用。 主要的一点是将子命令与第一个命令关联,因此,我试图将其全部分离到不同的文件/模块中,以提高其可维护性 我有当前的Python 在单击时包含子模块,python,python-3.x,command-line-interface,python-click,Python,Python 3.x,Command Line Interface,Python Click,我正在尝试对我的第一个Click CLI应用程序进行一种递归调用。 主要的一点是将子命令与第一个命令关联,因此,我试图将其全部分离到不同的文件/模块中,以提高其可维护性 我有当前的目录: 根目录 |-命令 |-计划 |---__初始化__ |---命令1 |---命令2 |-数据库 |---__初始化__ |---命令1 |---命令2 这是我的主文件: import click from commands.project import project from commands.databa
目录
:
根目录
|-命令
|-计划
|---__初始化__
|---命令1
|---命令2
|-数据库
|---__初始化__
|---命令1
|---命令2
这是我的主文件:
import click
from commands.project import project
from commands.database import database
@click.group(help="Main command")
def main():
pass
main.add_command(project)
main.add_command(database)
我的项目\uuuu init\uuuu
文件:
from commands.project.command1 import *
from commands.project.command2 import *
import click
@click.group(help="Projects")
def project():
pass
project.add_command(command1)
project.add_command(command2)
import click
@click.command()
def command1():
"""
Execute all the steps required to update the project.
"""
pass
我的commands.project.command1
文件:
from commands.project.command1 import *
from commands.project.command2 import *
import click
@click.group(help="Projects")
def project():
pass
project.add_command(command1)
project.add_command(command2)
import click
@click.command()
def command1():
"""
Execute all the steps required to update the project.
"""
pass
这里的要点是,每当我想添加一个新的子命令时,我需要:
.py
文件添加到相应子命令/子模块文件夹中的命令中(显然!)导入
语句添加到它的初始化
文件中编辑 尝试Stephen Rauch way后,它成功地包含了所有提供的文件,但没有一个命令仅与函数名一起使用
-
(例如:updateproject
->update\u project
)
main.py
# main command ----------------------------------------------------------- ###
@click.group(help="CLI tool!", context_settings=dict(max_content_width=120))
def main():
pass
# PROJECT command group -------------------------------------------------------- ###
@main.group(cls=group_from_folder("commands/project"),
short_help="Project installation and upgrade utils.",
help="Project installation and upgrade.")
def project():
pass
import click
@click.command(name="install-project",
help="This options allows you to easily install project",
short_help="Install a brand new project")
@click.pass_context
def install_project(ctx):
命令/project/install\u project.py
# main command ----------------------------------------------------------- ###
@click.group(help="CLI tool!", context_settings=dict(max_content_width=120))
def main():
pass
# PROJECT command group -------------------------------------------------------- ###
@main.group(cls=group_from_folder("commands/project"),
short_help="Project installation and upgrade utils.",
help="Project installation and upgrade.")
def project():
pass
import click
@click.command(name="install-project",
help="This options allows you to easily install project",
short_help="Install a brand new project")
@click.pass_context
def install_project(ctx):
CLI结果main项目--help
(请注意install\u project
而不是install project
子命令)
修改示例后,可以删除步骤2和步骤3。我建议通过闭包为每个文件夹创建一个自定义类。这样就完全不需要commands文件夹中的\uuuu init\uuuu.py
。此外,无需导入文件夹(模块)或文件夹中的命令
自定义组类创建者:
使用自定义类:
要使用自定义类,首先将命令(如问题中的结构)放入文件夹中。然后使用cls
参数修饰group命令,并传递一个自定义类,该类已初始化,指向包含命令的文件夹
@cli.group(cls=group_from_folder('project'))
def group():
"command for grouping"
测试代码:
文件组/command-test.py
结果:
点击版本:6.7
Python版本:3.6.3(v3.6.3:2c5fed8,2017年10月3日,18:11:49)[MSC v.1900 64位(AMD64)]
-----------
>组命令测试
命令测试
-----------
>团体
用法:test.py组[OPTIONS]命令[ARGS]。。。
分组命令
选项:
--帮助显示此消息并退出。
命令:
命令测试执行更新。。。
-----------
>小组--帮助
用法:test.py组[OPTIONS]命令[ARGS]。。。
分组命令
选项:
--帮助显示此消息并退出。
命令:
命令测试执行更新。。。
-----------
>
用法:test.py[OPTIONS]命令[ARGS]。。。
我的精彩剧本
选项:
--帮助显示此消息并退出。
命令:
分组命令
我建议您阅读特定Python包中的命令,然后添加到您的条目组中
假设我们有这样的结构:
|--app
|--commands
|--__init__.py
|--group1
|--__init__.py
|--command1.py
|--group2
|--__init__.py
|--command2.py
|--__init__.py
|--cli.py
然后,您的命令文件需要包含一次单击。具有指定名称的命令和名称为“Command”的函数:
import click
@click.command(name="your-first-command")
def command():
pass
每个组中的Init文件都需要包含文档字符串,才能为click.group提供适当的“帮助”值
最有趣的是cli.py:
import click
import importlib
import pkgutil
import os.path
def get_commands_from_pkg(pkg) -> dict:
pkg_obj = importlib.import_module(pkg)
pkg_path = os.path.dirname(pkg_obj.__file__)
commands = {}
for module in pkgutil.iter_modules([pkg_path]):
module_obj = importlib.import_module(f"{pkg}.{module.name}")
if not module.ispkg:
commands[module_obj.command.name] = module_obj.command
else:
commands[module.name.replace('_', '-')] = click.Group(
context_settings={'help_option_names': ['-h', '--help']},
help=module_obj.__doc__,
commands=get_commands_from_pkg(f"{pkg}.{module.name}")
)
return commands
@click.group(context_settings={'help_option_names': ['-h', '--help']}, help="Your CLI",
commands=get_commands_from_pkg('app.commands'))
def cli():
pass
正如您所见,我们递归地创建单击组,并将单击命令添加到特定组。这有一个小问题,例如,我使用与
命令测试
函数关联的@click.command(“command test”)
设置了一个子命令,命令名将具有command\u test
子命令,而不是command test
(在@click.command()
的name参数上指定的命令名。这是解决此问题的一种方法吗?问题仍然存在。所有子命令的参数都具有
(入口点函数名),而不是-
。替换()
不起作用。您希望文件名与命令函数名匹配,而不是与命令名匹配?这就是我们缺少的吗?@stephernauch我正在寻找一种方法来添加与函数名不同的命令名(例如:command:command one
,command文件上的函数:command\u one
(python不允许使用连字符函数->-
).@Stephernauch更改文件名结果,是的,但无法从该文件导入函数。因为我使用多命令调用,这不适用于此问题。@Stephernauch我有一些子命令调用另一个子命令。因此,一旦文件名具有-
,我将无法导入这些文件或其定义是的。
import click
import importlib
import pkgutil
import os.path
def get_commands_from_pkg(pkg) -> dict:
pkg_obj = importlib.import_module(pkg)
pkg_path = os.path.dirname(pkg_obj.__file__)
commands = {}
for module in pkgutil.iter_modules([pkg_path]):
module_obj = importlib.import_module(f"{pkg}.{module.name}")
if not module.ispkg:
commands[module_obj.command.name] = module_obj.command
else:
commands[module.name.replace('_', '-')] = click.Group(
context_settings={'help_option_names': ['-h', '--help']},
help=module_obj.__doc__,
commands=get_commands_from_pkg(f"{pkg}.{module.name}")
)
return commands
@click.group(context_settings={'help_option_names': ['-h', '--help']}, help="Your CLI",
commands=get_commands_from_pkg('app.commands'))
def cli():
pass