Как я могу разделить мои команды 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
Ответы
Ответ 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