如何在“ --help”中定义单击子命令的顺序

Mar*_*oma 3 python command-line-interface python-3.x python-click

我有这样的代码:

import click

@click.group()
def entry_point():
    pass

entry_point.add_command(lidtk.data.download_documents.main)
entry_point.add_command(lidtk.data.create_ml_dataset.main)
entry_point.add_command(lidtk.classifiers.text_cat.textcat_ngram.cli)
Run Code Online (Sandbox Code Playgroud)

给出帮助文本:

import click

@click.group()
def entry_point():
    pass

entry_point.add_command(lidtk.data.download_documents.main)
entry_point.add_command(lidtk.data.create_ml_dataset.main)
entry_point.add_command(lidtk.classifiers.text_cat.textcat_ngram.cli)
Run Code Online (Sandbox Code Playgroud)

这是在所有非常接近我想要的东西。但我想将顺序更改为:

lidtk --help
Usage: lidtk [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  create-dataset  Create sharable dataset from downloaded...
  download        Download 1000 documents of each language.
  textcat
Run Code Online (Sandbox Code Playgroud)

如何使用点击完成操作?

Ste*_*uch 7

help列出的命令顺序由类的list_commands()方法设置click.Group。因此,一种满足改变帮助列表顺序的愿望的方法是继承click.Group并重写list_commands以给出所需的顺序。

自定义类

此类重写click.Group.command()用于装饰命令功能的方法。它增加了指定的功能help_priority,该功能允许根据需要修改排序顺序:

class SpecialHelpOrder(click.Group):

    def __init__(self, *args, **kwargs):
        self.help_priorities = {}
        super(SpecialHelpOrder, self).__init__(*args, **kwargs)

    def get_help(self, ctx):
        self.list_commands = self.list_commands_for_help
        return super(SpecialHelpOrder, self).get_help(ctx)

    def list_commands_for_help(self, ctx):
        """reorder the list of commands when listing the help"""
        commands = super(SpecialHelpOrder, self).list_commands(ctx)
        return (c[1] for c in sorted(
            (self.help_priorities.get(command, 1), command)
            for command in commands))

    def command(self, *args, **kwargs):
        """Behaves the same as `click.Group.command()` except capture
        a priority for listing command names in help.
        """
        help_priority = kwargs.pop('help_priority', 1)
        help_priorities = self.help_priorities

        def decorator(f):
            cmd = super(SpecialHelpOrder, self).command(*args, **kwargs)(f)
            help_priorities[cmd.name] = help_priority
            return cmd

        return decorator
Run Code Online (Sandbox Code Playgroud)

使用自定义类

通过将cls参数传递给click.group()装饰器,group.command()可以将通过传递到组的任何命令传递给help_priority。优先级默认为1,并且较低的数字首先打印。

@click.group(cls=SpecialHelpOrder)
def cli():
    """My Excellent CLI"""

@cli.command(help_priority=5)
def my_command():
    ....
Run Code Online (Sandbox Code Playgroud)

这是如何运作的?

之所以可行,是因为click是一个设计良好的OO框架。该@click.group()装饰通常实例化一个click.Group对象,但允许与被骑过这种行为cls的参数。因此,click.Group在我们自己的类中继承并超越所需的方法是相对容易的事情。

步骤如下:

  1. 重写,Group.command()以便可以将修饰的命令传递给help_priority。在重写的装饰器中,捕获所需的优先级以备后用
  2. 覆盖Group.get_help()。在过深重方法,代替Group.list_commands具有list_commands如所期望,其将命令的命令。

测试代码:

import click

@click.group(cls=SpecialHelpOrder)
def cli():
    pass

@cli.command()
def command1():
    '''Command #1'''

@cli.command(help_priority=5)
def command2():
    '''Command #2'''

@cli.command()
def command3():
    '''Command #3'''

if __name__ == '__main__':
    cli('--help'.split())
Run Code Online (Sandbox Code Playgroud)

检测结果:

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

Options:
  --help  Show this message and exit.

Commands:
  command1  Command #1
  command3  Command #3
  command2  Command #2
Run Code Online (Sandbox Code Playgroud)


小智 7

这是顶部的一个很好的描述,但我们可以更轻松地实现它

import click
import collections


from .aws import aws_group
from .db import db_group
from .front import front_group
from .celery import celery_group
from .i18n import i18n_group
from .deprecated import add_deprecated


class OrderedGroup(click.Group):
    def __init__(self, name=None, commands=None, **attrs):
        super(OrderedGroup, self).__init__(name, commands, **attrs)
        #: the registered subcommands by their exported names.
        self.commands = commands or collections.OrderedDict()

    def list_commands(self, ctx):
        return self.commands


@click.group(cls=OrderedGroup)
def entire_group():
    """Entire Group"""


entire_group.add_command(aws_group)
entire_group.add_command(db_group)
entire_group.add_command(front_group)
entire_group.add_command(celery_group)
entire_group.add_command(i18n_group)
add_deprecated(entire_group)

Run Code Online (Sandbox Code Playgroud)

只需self.commands从更改DictOrderedDict。因此,我已弃用的​​命令位于列表底部。