Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在单击时包含子模块_Python_Python 3.x_Command Line Interface_Python Click - Fatal编程技术网

Python 在单击时包含子模块

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

我正在尝试对我的第一个Click CLI应用程序进行一种递归调用。 主要的一点是将子命令与第一个命令关联,因此,我试图将其全部分离到不同的文件/模块中,以提高其可维护性

我有当前的
目录

根目录
|-命令
|-计划
|---__初始化__
|---命令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
    文件添加到相应子命令/子模块文件夹中的命令中(显然!)

  • 将它的
    导入
    语句添加到它的
    初始化
    文件中

  • 将此新命令与其父级(本例中为项目/数据库)关联

  • 是否有任何方法进行循环/动态加载以避免第2步和第3步


    编辑

    尝试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