Click.command: примеры (PYTHON)
click.command: decoratorОсновы функции click.command
Декоратор @click.command является центральным элементом библиотеки Click для создания интерфейсов командной строки (CLI) в Python. Он преобразует обычную функцию Python в команду, которую можно вызывать из терминала.
Использование функции актуально при необходимости быстро добавить аргументы, опции и флаги к скрипту, организовать набор команд или создать профессиональный CLI-инструмент.
Аргументы декоратора:
- context_settings - словарь с настройками контекста, например, для изменения поведения помощи или обработки символов Юникода.
- help - строка с текстом справки для команды.
- epilog - текст, выводимый после справки команды.
- short_help - краткое описание команды для отображения в списках.
- options_metavar - строка, заменяющая стандартное отображение опций в справке.
- add_help_option - булево значение, определяющее добавление опции --help по умолчанию.
Декорированная функция возвращает объект Command, который можно использовать для вызова или объединения в группы. Сама функция после декорирования обычно возвращает результат выполнения логики команды или ничего.
Базовые примеры использования
Простейшая команда:
import click
@click.command()
def hello():
click.echo('Привет, мир!')
if __name__ == '__main__':
hello()$ python hello.py Привет, мир!
Команда с аргументом и опцией:
@click.command()
@click.argument('name')
@click.option('--count', default=1, help='Количество повторений.')
def greet(name, count):
for _ in range(count):
click.echo(f'Здравствуй, {name}!')
if __name__ == '__main__':
greet()$ python greet.py Вася Здравствуй, Вася! $ python greet.py Петя --count 3 Здравствуй, Петя! Здравствуй, Петя! Здравствуй, Петя!
Использование флага:
@click.command()
@click.option('--verbose', '-v', is_flag=True, help='Подробный вывод.')
def log(verbose):
if verbose:
click.echo('Детальный режим активирован.')
click.echo('Выполняется основная операция.')
if __name__ == '__main__':
log()$ python log.py Выполняется основная операция. $ python log.py -v Детальный режим активирован. Выполняется основная операция.
Альтернативные инструменты в Python
Библиотека argparse входит в стандартную библиотеку Python. Её выбирают для простых скриптов без внешних зависимостей. Click предлагает более декларативный и компактный синтаксис.
Модуль sys.argv позволяет обрабатывать аргументы вручную. Он подходит для элементарных случаев, но лишён автоматической проверки типов и генерации справки.
Библиотека Typer построена на основе Click и использует аннотации типов Python для объявления параметров. Она может быть удобнее для проектов, где типизация является приоритетом.
Инструмент docopt создаёт интерфейс на основе строки документации. Его применение оправдано, когда нужно сгенерировать CLI из уже существующей документации.
Аналоги в других языках программирования
В JavaScript/Node.js популярна библиотека yargs.
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');
const argv = yargs(hideBin(process.argv))
.command('serve', 'Запуск сервера', (yargs) => {
return yargs.option('port', {
describe: 'Порт сервера',
default: 3000
})
})
.parse();
console.log(argv);$ node script.js serve --port 8080
{ _: [ 'serve' ], port: 8080, '$0': 'script.js' }В Go используется пакет flag из стандартной библиотеки или сторонние решения, такие как cobra.
package main
import (
"flag"
"fmt"
)
func main() {
name := flag.String("name", "Гость", "Имя для приветствия")
flag.Parse()
fmt.Printf("Привет, %s!\n", *name)
}$ go run main.go -name Иван Привет, Иван!
В PHP можно использовать глобальный массив $argv или библиотеку symfony/console.
#!/usr/bin/env php
<?php
$input = getopt("n:", ["name:"]);
echo "Привет, " . ($input['n'] ?? $input['name'] ?? "гость") . "!\n";
$ php script.php -n Мария Привет, Мария!
В Java распространены библиотеки picocli и Apache Commons CLI. Они требуют большего объёма кода по сравнению с Click.
Распространённые ошибки
Вызов функции без декорирования, когда ожидается запуск из командной строки.
import click
@click.command()
def cmd():
click.echo('OK')
# Ошибка: функция вызывается как обычная Python-функция,
# а не через CLI. Аргументы не будут переданы корректно.
cmd()$ python script.py OK # Но аргументы командной строки игнорируются.
Неправильный порядок декораторов.
@click.option('--name')
@click.command() # Декоратор @click.command должен быть верхним.
def hello(name):
passAttributeError: 'Option' object has no attribute 'command'
Использование print вместо click.echo может привести к проблемам с кодировкой и буферизацией в некоторых средах.
@click.command()
def bad():
print('Текст') # Не рекомендуется для CLI.
Изменения в последних версиях
В версии Click 8.0 появилась поддержка неявного добавления опции --help через параметр add_help_option=True по умолчанию. Также улучшена обработка ошибок для подсказок при вводе.
В Click 7.0 была введена возможность использовать context_settings для более гибкой настройки поведения команды. Добавлена лучшая поддержка обработки файлов и потоков.
Начиная с версии 6.0, Click по умолчанию использует кодировку UTF-8 для вывода, что устранило многие проблемы с отображением Unicode в Windows.
Расширенные примеры применения
Создание группы команд:
import click
@click.group()
def cli():
pass
@cli.command()
def init():
click.echo('Инициализация репозитория')
@cli.command()
@click.argument('name')
def add(name):
click.echo(f'Добавление {name}')
if __name__ == '__main__':
cli()$ python repo.py init Инициализация репозитория $ python repo.py add файл.txt Добавление файл.txt
Использование callback-функций для валидации:
def validate_count(ctx, param, value):
if value < 1:
raise click.BadParameter('Количество должно быть положительным.')
return value
@click.command()
@click.option('--count', callback=validate_count, default=1)
def repeat(count):
click.echo(f'Число: {count}')
if __name__ == '__main__':
repeat()$ python script.py --count 5 Число: 5 $ python script.py --count 0 Error: Количество должно быть положительным.
Команда с контекстом и вложенными группами:
@click.group()
@click.option('--debug/--no-debug', default=False)
@click.pass_context
def cli(ctx, debug):
ctx.ensure_object(dict)
ctx.obj['DEBUG'] = debug
@cli.group()
def db():
pass
@db.command()
@click.pass_context
def migrate(ctx):
if ctx.obj['DEBUG']:
click.echo('Отладка миграции...')
click.echo('Миграция выполнена.')
if __name__ == '__main__':
cli(obj={})$ python app.py --debug db migrate Отладка миграции... Миграция выполнена.
Чтение аргументов из переменных окружения:
@click.command()
@click.option('--host', envvar='APP_HOST', default='localhost')
def connect(host):
click.echo(f'Подключение к {host}')
if __name__ == '__main__':
connect()$ export APP_HOST=example.com $ python script.py Подключение к example.com