Выполнять различные действия родительской команды, если вызывается определенная подкоманда? - PullRequest
1 голос
/ 06 мая 2019

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

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

Мой cli.py код:

import sys
import click
from ruamel.yaml import YAML
from pathlib import Path

from commands.config_cmds import configcmd

MYAPP = "AwesomeCLI"

@click.group()
@click.version_option()
@click.pass_context
def cli(ctx):
    """command line application"""
    ctx.ensure_object(dict)
    ctx.obj['APPLICATION_NAME'] = MYAPP

    config_file = Path(click.get_app_dir(ctx.obj[MYAPP])) / "config.yml"
    yaml = YAML(typ="safe")
    try:
        config_yml = yaml.load(config_file)
    except FileNotFoundError:
        click.secho("Run command: awesome-cli configcmd first-run", fg='red')
        raise click.FileError(config_file.name, "Missing configuration file.")

    ctx.obj['CONFIG'] = yaml.dump(config_yml)


cli.add_command(configcmd)

Мой configcmd код:

@click.group()
def configcmd():
    """Manage configuration of this tool
    \f
    The configuration file is saved in $HOME/.config/awesome-cli
    """

@config.command()
@click.pass_context
def first_run(ctx):
    """
    Set up CLI configuration. 
    """
    api_key = click.prompt("Your API Key")
    # More stuff here about saving this file...

Если я запускаю python awesome-cli configcmd, я получаю следующую ошибку (как и ожидалось):

Run command: awesome-cli configcmd first-run
Error: Could not open file config.yml: Missing configuration file.

Однако, если я запускаю этоКоманда python awesome-cli configcmd first-run Я получаю ту же ошибку, которая не моя цель.Очевидно, я должен получить эту ошибку с этим кодом, но это потому, что я не знаю, как добавить исключение на основе вызываемой команды / подкоманды.

Что мне нужно добавить в мой cliфункция в cli.py, чтобы я не пытался загрузить файл конфигурации, если (и только если), пользователь работает configcmd first-run?Любая другая команда / подкоманда потребует, чтобы этот файл конфигурации существовал, поэтому я хочу, чтобы проверка оставалась для них.

1 Ответ

1 голос
/ 06 мая 2019

Чтобы вызвать некоторый определенный код перед выполнением подкоманды, которая основана на конкретной вызванной подкоманде, вы можете посмотреть на ctx.invoked_subcommand как:

if ctx.invoked_subcommand != 'configcmd':

В вашем примере вам нужно будет изучить ctx.invoked_subcommand на каждом уровне, например:

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

import sys
import click
from ruamel.yaml import YAML
from pathlib import Path

MYAPP = "AwesomeCLI"

@click.group()
@click.pass_context
def cli(ctx):
    """command line application"""
    ctx.ensure_object(dict)
    ctx.obj['APPLICATION_NAME'] = MYAPP
    ctx.obj['CONFIG_FILEPATH'] = Path(click.get_app_dir(MYAPP), "config.yml")
    if ctx.invoked_subcommand != 'configcmd':
        load_config(ctx)

@cli.group()
@click.pass_context
def configcmd(ctx):
    """Configuration management for this CLI"""
    click.echo("In config")
    if ctx.invoked_subcommand != 'first-run':
        load_config(ctx)

def load_config(ctx):
    yaml = YAML(typ="safe")
    try:
        config_yml = yaml.load(ctx.obj['CONFIG_FILEPATH'])
    except FileNotFoundError:
        click.secho("Run command: awesome-cli configcmd first-run",
                    fg='red')
        raise click.FileError(str(ctx.obj['CONFIG_FILEPATH']),
                              "Missing configuration file.")

    ctx.obj['CONFIG'] = yaml.load(config_yml)


@configcmd.command('first-run')
@click.pass_context
def first_run(ctx):
    """Set up CLI configuration."""
    click.echo("In first-run")

@configcmd.command('test-cmd')
@click.pass_context
def test_cmd(ctx):
    """ This command will not be reachable without config file"""
    click.echo("In first-run")


if __name__ == "__main__":
    commands = (
        'configcmd first-run',
        'configcmd test-cmd',
        'configcmd --help',
        '--help',
        '',
    )

    import sys, time

    time.sleep(1)
    print('Click Version: {}'.format(click.__version__))
    print('Python Version: {}'.format(sys.version))
    for cmd in commands:
        try:
            time.sleep(0.1)
            print('-----------')
            print('> ' + cmd)
            time.sleep(0.1)
            cli(cmd.split())

        except BaseException as exc:
            if str(exc) != '0' and \
                    not isinstance(exc, (click.ClickException, SystemExit)):
                raise

Результаты:

Click Version: 6.7
Python Version: 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)]
-----------
> configcmd first-run
In config
In first-run
-----------
> configcmd test-cmd
In config
Run command: awesome-cli configcmd first-run
Error: Could not open file C:\Users\stephen\AppData\Roaming\AwesomeCLI\config.yml: Missing configuration file.
-----------
> configcmd --help
Usage: test.py configcmd [OPTIONS] COMMAND [ARGS]...

  Configuration management for this CLI

Options:
  --help  Show this message and exit.

Commands:
  first-run  Set up CLI configuration.
  test-cmd   This command will not be reachable without...
-----------
> --help
Usage: test.py [OPTIONS] COMMAND [ARGS]...

  command line application

Options:
  --help  Show this message and exit.

Commands:
  configcmd  Configuration management for this CLI
-----------
> 
Usage: test.py [OPTIONS] COMMAND [ARGS]...

  command line application

Options:
  --help  Show this message and exit.

Commands:
  configcmd  Configuration management for this CLI
...