Могут ли клик-декораторы работать с неосновными функциями? - PullRequest
1 голос
/ 24 апреля 2020

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

from .shared import G

@click.command()
@click.option("--thing1", …)
@click.optoin("--thing2", …)
…
def main(**kwargs):
    g = G()
    g.do_your_thing()

Я хотел бы переместить все это в __init__ из G или в подкласс G.

class G:
    @click.command()
    @click.option("--thing1")
    def __init__(**kwargs):
        pass

class G6(G):
    @click.command()
    @click.option("--specific-flag")
    def __init__(**kwargs):
        super().__init__(**kwargs)
        if kwargs.get("--specific-flag"):
             do_something()
        self.seven = 7

Однако, когда я пытаюсь это сделать, я получаю следующую ошибку:

Usage: something.py [OPTIONS]
Try 'something.py --help' for help.

Error: no such option: --thing1

Моя основная цель с помощью этого рефакторинга состоит в устранении большого количества дублирующего кода, украшающего main Функция каждой программы путем перемещения общих декораторов в библиотеку.

Если это возможно, возможно ли также использовать опциональный декоратор подкласса для замены того же декоратора в базовом классе? Я предполагаю, что ответ - да.


Редактировать

Основываясь на ответе ниже, моя программа теперь работает со структурой, подобной следующему фрагменту:

_common_options = [
    click.option(…), click.option(…), …
]

def common_options(func):
    for option in _common_options:
        func = option(func)
    return func

class G:
    def __init__(**kwargs):
        print(kwargs)

@click.command()
@common_options
@click.option("--specific-option", …)
def main(**kwargs):
    f = G(**kwargs)

Проблема с моей первоначальной попыткой заключалась в том, чтобы поместить все элементы @click.whatever в качестве декоратора __init__ вместо того, чтобы украшать main и передать **kwargs в __init__.

1 Ответ

1 голос
/ 24 апреля 2020

То, что я сделал ранее, - это создание списка параметров, которые будут применены к команде или группе. Например:


_global_options = [
    click.option('-v', '--verbose', count=True, default=0, help='Verbose output.'),
    click.option('-n', '--dry-run', is_flag=True, default=False, help='Dry-run mode.')
]


def common_options(func):
    for option in reversed(_global_options):
        func = option(func)
    return func

Затем они будут применяться следующим образом:

click.group(name='my_group')
@common_options
def my_group(*args, **kwargs):
    pass

Кажется, что декораторы действительно хорошо работают с Click. Это помогает?

...