Click интерфейс командной строки
pip install click
Базовая концепция
Клик базируется на декларации команд через декораторы. Функция становится инструментом командной строки, когда снабжена декоратором @click.command()
import click
@click.command()
def hello():
    click.echo('Hello World!')
if __name__ == '__main__':
    hello()
@click.eshoe() используется вместо стандартного print() для поддержки разных окружений, чтобы не сломать реализацию, если конфигурация нарушена.
Поддерживаются вложенные команды через декоратор @click.group()
@click.group()
def cli():
    pass
@click.command()
def initdb():
    click.echo('Initialized the database')
@click.command()
def dropdb():
    click.echo('Dropped the database')
cli.add_command(initdb)
cli.add_command(dropdb)
или для простых скриптов
@click.group()
def cli():
    pass
@cli.command()
def initdb():
    click.echo('Initialized the database')
@cli.command()
def dropdb():
    click.echo('Dropped the database')
if __name__ == '__main__':
    cli()
Так-же команды могут регистрироваться в группы позже
@click.command()
def greet():
    click.echo("Hello, World!")
@click.group()
def group():
    pass
group.add_command(greet)
Добавление аргументов и опций производится через @click.option() и @click.argument()
@click.command()
@click.option('--count', default=1, help='number of greetings')
@click.argument('name')
def hello(count, name):
    for x in range(count):
        click.echo(f"Hello {name}!")
$ python hello.py --help
Usage: hello.py [OPTIONS] NAME
Options:
  --count INTEGER  number of greetings
  --help           Show this message and exit.
Поддержка интеграции с [setuptools]
Параметры
Доступны два типа параметров - опции и аргументы. Рекомендуется использовать аргументы исключительно для таких вещей, как переход к подкомандам или ввод имен файлов/URL-адресов, а опции использовать для всего остального.
Для опций доступно:
- автоматическое дополнение для пропущенных опций
 - булевы значения
 - опции могут быть добавлены из переменных окружения (аругменты нет)
 - опции полностью задокументированы и будут отображены с вызовом 
--helpфлага 
Типы параметров определены в самом click. Смотри доки. Кроме того, можно задать кастомные типы параметров
Опции
Имена опций могут быть использованы как аргументы при вызове декорированной функции. Порядок выбора имен:
- если имя не имеет префикса, оно используется как имя аргумента и не используется как имя опции в командной строке
 - если хотя бы одно имя снабжено двойными черточками - первое из таких используется как имя опции
 - в остальных случаях используется первое имя с одинарной черточкой
 
При ээтом большие буквы конвертятся в маленькие, а избыточные черточки игнорируются:
- “-f”, “–foo-bar”, the name is 
foo_bar - “-x”, the name is 
x - “-f”, “–filename”, “dest”, the name is 
dest - ”–CamelCase”, the name is 
camelcase - “-f”, “-fb”, the name is 
f - ”–f”, “–foo-bar”, the name is 
f - ”—f”, the name is 
f 
@click.command()
@click.option('-s', '--string-to-echo')
def echo(string_to_echo):
    click.echo(string_to_echo)
@click.command()
@click.option('-s', '--string-to-echo', 'string')
def echo(string):
    click.echo(string)
Наиболее базовые опции - это опции значений
Можно определить тип, обязательность параметра, показ дефолтных значений при запросе через --help. Кроме того, можно определить в качестве имен параметров заррезервированные имена
@click.command()
@click.option('--from', '-f', 'from_')
@click.option('--to', '-t')
def reserved_param_name(from_, to):
    click.echo(f"from {from_} to {to}")
Можно передавать несколько значений опции
@click.command()
@click.option('--pos', nargs=2, type=float)
def findme(pos):
    a, b = pos
    click.echo(f"{a} / {b}")
Кроме того, можно использовать кортежи и множественные опции по одному имени
@click.command()
@click.option('-v', '--verbose', count=True)
def log(verbose):
    click.echo(f"Verbosity: {verbose}")
$ commit -m foo -m bar
foo
bar
Булевы флаги используют определение двух имен через слеш
import sys
@click.command()
@click.option('--shout/--no-shout', default=False)
def info(shout):
    rv = sys.platform
    if shout:
        rv = rv.upper() + '!!!!111'
    click.echo(rv)
$ info --shout
LINUX!!!!111
$ info --no-shout
linux
$ info
linux
Если требуется только одно состояние флага, то можно так:
import sys
@click.command()
@click.option('--shout', is_flag=True)
def info(shout):
    rv = sys.platform
    if shout:
        rv = rv.upper() + '!!!!111'
    click.echo(rv)
Переключатель опций
import sys
@click.command()
@click.option('--upper', 'transformation', flag_value='upper',
              default=True)
@click.option('--lower', 'transformation', flag_value='lower')
def info(transformation):
    click.echo(getattr(sys.platform, transformation)())
$ info --upper
LINUX
$ info --lower
linux
$ info
LINUX
Опция выбора опций
Можно передать список (или кортеж), из которого можно выбрать значение опции
@click.command()
@click.option('--hash-type',
              type=click.Choice(['MD5', 'SHA1'], case_sensitive=False))
def digest(hash_type):
    click.echo(hash_type)
Ввод
@click.command()
@click.option('--name', prompt=True)
def hello(name):
    click.echo(f"Hello {name}!")
Или так:
@click.command()
@click.option('--name', prompt='Your name please')
def hello(name):
    click.echo(f"Hello {name}!")
Ввод пародей тоже реализован
Колбеки
Запрос согласия для опасных операций
Значения из переменных окружения
Есть несколько способов. Во первых можно реализовать через auto_envvar_prefix= самой функции
@click.command()
@click.option('--username')
def greet(username):
    click.echo(f'Hello {username}!')
if __name__ == '__main__':
    greet(auto_envvar_prefix='GREETER')
Второй вариант - вручную добавить в декоратор черех envvar=
@click.command()
@click.option('--username', envvar='USERNAME')
def greet(username):
   click.echo(f"Hello {username}!")
if __name__ == '__main__':
    greet()
Можно использовать множественные переменные
Другие префиксы
Опция ренжа
Валидация
Опциональные значения
Аргументы
Работауют идентично опциям, но являются позиционными. поддерживают лишь часть функционала и не документируются.
@click.command()
@click.argument('filename')
def touch(filename):
    """Print FILENAME."""
    click.echo(filename)
$ touch foo.txt
foo.txt
Варианты использования:
- переменные
 - аргументы файлов
 - аргументы путей файлов
 - использование переменных окружения
 - аргументы-опции
 
Команды и группы
Это одна из главных фичей пакета - возможность собирать несколько аргументво в бандлы. Реализуется через command, group и multicommand
Что доступно:
- передача контекста между командами
 - создание собственных групп команд
 - мерж групп команд между собой
 - цепочки мультикоманд
 - пайплайны мультикоманд
 - переопределение дефолтных значений
 - дефолтные значения для разных контекстов
 
Документирование для –help
Дополнительные паттерны
- алиасы команд
 - модификация параметров
 - приведение токенов к правильному формату
 - вызов других команд из команд
 - определения порядка колбеков
 - передача неизвестных опций в следующий контекст
 - доступ к глобальному контексту
 - определение источника параметра (логирование)
 - управление ресурсами группы команд
 
Как все это тестировать
Дополнительные утилиты
- вывод в stdout
 - ANSI colors
 - пагинация
 - очистка страницы
 - получение отдельных знаков из терминала (к примеру y/n)
 - press any key
 - запуск редактора
 - запуск приложения
 - вывод названия файла
 - использование стандартного потока
 - открытие файла через контекстный менеджер
 - поиск папки приложения
 - прогресс-бар
 
Больше информации обо всем в документации проекта или на github
Смотри так-же:
- [argparsing]
 - Click-log: Simple and beautiful logging for click applications
 - asyncclick
 - [python-standart-library]
 - [poetry]
 - poethepoet энтрипоинт для [poetry]
 - [makefile]
 - [cl]