在 cli 文档中将点击命令分成几个部分

Divide click commands into sections in cli documentation

此代码:

#!/usr/bin env python3

import click


def f(*a, **kw):
    print(a, kw)


commands = [click.Command("cmd1", callback=f), click.Command("cmd2", callback=f)]


cli = click.Group(commands={c.name: c for c in commands})

if __name__ == "__main__":
    cli()

生成此帮助:

# Usage: cli.py [OPTIONS] COMMAND [ARGS]...

# Options:
#   --help  Show this message and exit.

# Commands:
#   cmd1
#   cmd2

我有很多子命令,所以我想在帮助中将它们分成几个部分:

# Usage: cli.py [OPTIONS] COMMAND [ARGS]...

# Options:
#   --help  Show this message and exit.

# Commands:
#   cmd1
#   cmd2
# 
# Extra other commands:
#   cmd3
#   cmd4

如何在不影响功能的情况下将命令拆分成帮助中的部分?

如果您定义自己的组 class 您可以像这样覆盖帮助生成:

自定义 Class:

class SectionedHelpGroup(click.Group):
    """Sections commands into help groups"""

    def __init__(self, *args, **kwargs):
        self.grouped_commands = kwargs.pop('grouped_commands', {})
        commands = {}
        for group, command_list in self.grouped_commands.items():
            for cmd in command_list:
                cmd.help_group = group
                commands[cmd.name] = cmd

        super(SectionedHelpGroup, self).__init__(
            *args, commands=commands, **kwargs)

    def command(self, *args, **kwargs):
        help_group = kwargs.pop('help_group')
        decorator = super(SectionedHelpGroup, self).command(*args, **kwargs)

        def new_decorator(f):
            cmd = decorator(f)
            cmd.help_group = help_group
            self.grouped_commands.setdefault(help_group, []).append(cmd)
            return cmd

        return new_decorator

    def format_commands(self, ctx, formatter):
        for group, cmds in self.grouped_commands.items():
            rows = []
            for subcommand in self.list_commands(ctx):
                cmd = self.get_command(ctx, subcommand)
                if cmd is None or cmd.help_group != group:
                    continue
                rows.append((subcommand, cmd.short_help or ''))

            if rows:
                with formatter.section(group):
                    formatter.write_dl(rows)

使用自定义 Class:

使用 cls 参数将自定义 Class 传递给 click.group(),例如:

@click.group(cls=SectionedHelpGroup)
def cli():
    """"""

定义命令时,传递命令所属的帮助组,如:

@cli.command(help_group='my help group')
def a_command(*args, **kwargs):
    ....        

这是如何工作的?

之所以可行,是因为 click 是一个设计良好的 OO 框架。 @click.group() 装饰器通常会实例化一个 click.Group 对象,但允许此行为 over-ridden 带有 cls 参数。因此,在我们自己的 class 中继承 click.Group 并覆盖所需的方法是一件相对容易的事情。

在这种情况下,我们挂钩 command() 装饰器以允许 help_group 被识别。我们还覆盖了 format_commands() 方法以将命令帮助打印到组中。

测试代码:

import click

def f(*args, **kwargs):
    click.echo(args, kwargs)

commands = {
    'help group 1': [
        click.Command("cmd1", callback=f),
        click.Command("cmd2", callback=f)
    ],
    'help group 2': [
        click.Command("cmd3", callback=f),
        click.Command("cmd4", callback=f)
    ]
}

cli = SectionedHelpGroup(grouped_commands=commands)

@cli.command(help_group='help group 3')
def a_command(*args, **kwargs):
    """My command"""
    click.echo(args, kwargs)


if __name__ == "__main__":
    cli(['--help'])

结果:

Usage: test.py [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

help group 1:
  cmd1
  cmd2

help group 2:
  cmd3
  cmd4

help group 3:
  a_command  My command