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

у меня есть одно большое приложение 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

4 ответов


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

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

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

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

import click


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

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

мой 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


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

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

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


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

на :

import click

from command_cloudflare import cloudflare
from command_uptimerobot import uptimerobot

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

if __name__ == '__main__':
    cli()

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

Я надеюсь, что это помощь и хороший взгляд с вашим cli.


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

import commands_main
import commands_cloudflare
import commands_uptimerobot