Использование click.CommandCollection удаляет параметры группы

import click

@click.group()
@click.option('--username')
def cli1(username):
    click.echo(username)

@cli1.command()
def something():
    click.echo('howdy')

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

@cli2.command()
def somethingelse():
    click.echo('doody')

cli = click.CommandCollection(sources=[cli1, cli2])

if __name__ == '__main__':
    cli()

Я ожидаю, что это позволит мне пройти --username в something, но когда я запускаю этот скрипт:

python script.py something --username hi

Я получил:

Ошибка: нет такой опции: --username

Кажется, с помощью CommandCollection ломает мои варианты. Кто-нибудь еще имел дело с этим раньше? В репо кликов есть открытый тикет, который не затрагивался с 2015 года и не имеет решения.

1 ответ

С небольшим количеством новой сантехники это может быть сделано.

Как??

Вы можете унаследовать от click.Group а затем передать созданный класс click.group() лайк:

@click.group(cls=GroupWithCommandOptions)

В новом классе параметры группы могут быть применены к команде для разбора, а затем во время вызова команды можно вызывать групповую функцию с соответствующими параметрами.

Новый групповой класс:

import click

class GroupWithCommandOptions(click.Group):
    """ Allow application of options to group with multi command """

    def add_command(self, cmd, name=None):
        """ Hook the added command and put the group options on the command """
        click.Group.add_command(self, cmd, name=name)

        # add the group parameters to the command
        for param in self.params:
            cmd.params.append(param)

        # hook the command's invoke with our own
        cmd.invoke = self.build_command_invoke(cmd.invoke)
        self.invoke_without_command = True

    def build_command_invoke(self, original_invoke):

        def command_invoke(ctx):
            """ insert invocation of group function """

            # separate the group parameters
            ctx.obj = dict(_params=dict())
            for param in self.params:
                name = param.name
                ctx.obj['_params'][name] = ctx.params[name]
                del ctx.params[name]

            # call the group function with its parameters
            params = ctx.params
            ctx.params = ctx.obj['_params']
            self.invoke(ctx)
            ctx.params = params

            # now call (invoke) the original command
            original_invoke(ctx)

        return command_invoke

Тестовый код:

# Pass new group class to our group which needs options
@click.group(cls=GroupWithCommandOptions)
@click.option('--username')
def cli1(username):
    click.echo(username)


@cli1.command()
def something():
    click.echo('howdy')


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


@cli2.command()
def somethingelse():
    click.echo('doody')


cli = click.CommandCollection(sources=[cli1, cli2])

if __name__ == '__main__':
    cli('something --username hi'.split())

Результаты:

hi
howdy
Другие вопросы по тегам