Подтвердить что ты не робот

Как я могу разделить мои команды Click, каждый с набором подкоманд, на несколько файлов?

У меня есть одно приложение с большим щелчком, которое я разработал, но перемещение по различным командам/подкомандам становится грубым. Как организовать мои команды в отдельных файлах? Возможно ли организовать команды и их подкоманды в отдельные классы?

Вот пример того, как я хотел бы его разделить:

INIT

import click

@click.group()
@click.version_option()
def cli():
    pass #Entry Point

command_cloudflare.py

@cli.group()
@click.pass_context
def cloudflare(ctx):
    pass

@cloudflare.group('zone')
def cloudflare_zone():
    pass

@cloudflare_zone.command('add')
@click.option('--jumpstart', '-j', default=True)
@click.option('--organization', '-o', default='')
@click.argument('url')
@click.pass_obj
@__cf_error_handler
def cloudflare_zone_add(ctx, url, jumpstart, organization):
    pass

@cloudflare.group('record')
def cloudflare_record():
    pass

@cloudflare_record.command('add')
@click.option('--ttl', '-t')
@click.argument('domain')
@click.argument('name')
@click.argument('type')
@click.argument('content')
@click.pass_obj
@__cf_error_handler
def cloudflare_record_add(ctx, domain, name, type, content, ttl):
    pass

@cloudflare_record.command('edit')
@click.option('--ttl', '-t')
@click.argument('domain')
@click.argument('name')
@click.argument('type')
@click.argument('content')
@click.pass_obj
@__cf_error_handler
def cloudflare_record_edit(ctx, domain):
    pass

command_uptimerobot.py

@cli.group()
@click.pass_context
def uptimerobot(ctx):
    pass

@uptimerobot.command('add')
@click.option('--alert', '-a', default=True)
@click.argument('name')
@click.argument('url')
@click.pass_obj
def uptimerobot_add(ctx, name, url, alert):
    pass

@uptimerobot.command('delete')
@click.argument('names', nargs=-1, required=True)
@click.pass_obj
def uptimerobot_delete(ctx, names):
    pass
4b9b3361

Ответ 1

Недостатком использования CommandCollection для этого является то, что он объединяет ваши команды и работает только с командами. Лучшей альтернативой imho является использование add_command для достижения того же результата.

У меня есть проект со следующим деревом:

cli/
├── __init__.py
├── cli.py
├── group1
│   ├── __init__.py
│   ├── commands.py
└── group2
    ├── __init__.py
    └── commands.py

Каждая подкоманда имеет свой собственный модуль, что делает его невероятно простым в управлении даже сложными реализациями со многими дополнительными вспомогательными классами и файлами. В каждом модуле файл commands.py содержит аннотации @click. Пример group2/commands.py:

import click


@click.command()
def version():
    """Display the current version."""
    click.echo(_read_version())

При необходимости вы можете легко создать больше классов в модуле и import и использовать их здесь, тем самым предоставляя CLI всю мощь классов и модулей Python.

My cli.py - это точка входа для всего CLI:

import click

from .group1 import commands as group1
from .group2 import commands as group2

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

entry_point.add_command(group1.command_group)
entry_point.add_command(group2.version)

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

Ссылка: http://click.pocoo.org/6/quickstart/#nesting-commands

Ответ 2

Предположим, ваш проект имеет следующую структуру:

project/
├── __init__.py
├── init.py
└── commands
    ├── __init__.py
    └── cloudflare.py

Группы - это не более чем несколько команд, и группы могут быть вложенными. Вы можете разделить свои группы в модули и импортировать их на вас init.py файл и добавить их к cli группе с использованием add_command.

Вот пример init.py:

import click
from .commands.cloudflare import cloudflare


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


cli.add_command(cloudflare)

Вы должны импортировать группу cloudflare, которая находится внутри файла cloudflare.py. Ваши commands/cloudflare.py будут выглядеть так:

import click


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


@cloudflare.command()
def zone():
    click.echo('This is the zone subcommand of the cloudflare command')

Затем вы можете запустить команду cloudflare следующим образом:

$ python init.py cloudflare zone

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

Ответ 3

Сейчас я ищу что-то подобное, в вашем случае все просто, поскольку у вас есть группы в каждом из файлов, вы можете решить эту проблему, как описано в документации:

В файле init.py:

import click

from command_cloudflare import cloudflare
from command_uptimerobot import uptimerobot

cli = click.CommandCollection(sources=[cloudflare, uptimerobot])

if __name__ == '__main__':
    cli()

Лучшая часть этого решения - это то, что он полностью совместим с pep8 и другими линтерами, потому что вам не нужно импортировать то, что вы не будете использовать, и вам не нужно импортировать * из любого места.

Ответ 4

Я не эксперт по щелчку, но он должен работать, просто импортируя ваши файлы в основной. Я бы переместил все команды в отдельные файлы и имел один основной файл, импортирующий другие. Таким образом, легче контролировать точный порядок, если это важно для вас. Таким образом, ваш основной файл будет выглядеть следующим образом:

import commands_main
import commands_cloudflare
import commands_uptimerobot