Инструменты Python для написания скриптов с CLI: argparse, Click и Fire
Библиотеки для создания интерфейсов командной строки в Python
Как быстро и гибко реализовать многофункциональное CLI с подкомандами и валидацией?
Библиотека Click предоставляет декораторы и контекстные объекты, позволяя создавать сложные интерфейсы командной строки с минимальным кодом. Она поддерживает автоматическую обработку аргументов, опций, подкоманд (группы), а также встроенную справку.
import click
@click.group()
def cli(): pass
@cli.command()
@click.argument('filename')
@click.option('--verbose', '-v', is_flag=True, help='Вывод подробной информации')
def process(filename, verbose):
"""Обработка файла"""
if verbose:
click.echo(f'Обработка {filename} с подробным выводом')
else:
click.echo(f'Обработка {filename}')
if __name__ == '__main__':
cli()Python библиотеки словари (библиотеки для работы со словарями в python)
После запуска python script.py --help будет сгенерирована справка. Для установки Click используется pip install click.
Типичные ошибки: Неправильная вложенность декораторов (группа должна быть объявлена первой), пропуск декоратора @click.group() для создания группы. Решение: всегда определять группу перед её командами.
Как обойтись стандартной библиотекой Python без установки сторонних пакетов?
Модуль argparse встроен в Python и предлагает декларативное описание аргументов. Подходит для простых и средних по сложности утилит.
import argparse
parser = argparse.ArgumentParser(description='Обработка файла')
parser.add_argument('filename', help='Имя файла для обработки')
parser.add_argument('-v', '--verbose', action='store_true', help='Подробный вывод')
args = parser.parse_args()
if args.verbose:
print(f'Обработка {args.filename} с подробным выводом')
else:
print(f'Обработка {args.filename}')библиотека python user (пользовательские библиотеки python)
Для работы с подкомандами используется subparsers.
Проблема: Код становится громоздким при множестве подкоманд. Решение: Разделять парсеры на отдельные функции и использовать set_defaults для вызова обработчиков.
Как превратить любой объект Python в CLI без ручного описания аргументов?
Библиотека Fire автоматически анализирует сигнатуры функций или классов и генерирует команды. Подходит для быстрого прототипирования.
import fire
class Calculator:
def add(self, a, b):
return a + b
def multiply(self, a, b):
return a * b
if __name__ == '__main__':
fire.Fire(Calculator)
Запуск python script.py add 3 4 вернёт 7.
Сложности: Ограниченный контроль над справкой и типизацией. Для сложной валидации лучше использовать Click.
Расширенные примеры использования библиотек для CLI
Click: контекст и обратные вызовы
import click
@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.command()
@click.argument('name')
@click.pass_context
def hello(ctx, name):
debug = ctx.obj['DEBUG']
if debug:
click.echo(f'Debug mode ON, name={name}')
click.echo(f'Hello, {name}!')
if __name__ == '__main__':
cli()
Результат при запуске python script.py --debug hello World:
Debug mode ON, name=World Hello, World!
argparse: подкоманды (subparsers)
import argparse
def cmd_copy(args):
print(f'Copy from {args.source} to {args.dest}')
def cmd_move(args):
print(f'Move from {args.source} to {args.dest}')
parser = argparse.ArgumentParser(description='File operations')
subparsers = parser.add_subparsers(dest='command')
copy_parser = subparsers.add_parser('copy', help='Copy file')
copy_parser.add_argument('source')
copy_parser.add_argument('dest')
copy_parser.set_defaults(func=cmd_copy)
move_parser = subparsers.add_parser('move', help='Move file')
move_parser.add_argument('source')
move_parser.add_argument('dest')
move_parser.set_defaults(func=cmd_move)
args = parser.parse_args()
if hasattr(args, 'func'):
args.func(args)
else:
parser.print_help()
Запуск python script.py copy in.txt out.txt выведет:
Copy from in.txt to out.txt
Fire: работа с несколькими функциями
import fire
def greet(greeting='Hello', name='World'):
print(f'{greeting}, {name}!')
def add(x, y):
return x + y
if __name__ == '__main__':
fire.Fire({'greet': greet, 'add': add})
Вызов python script.py greet --greeting=Hi --name=Pythonista даст:
Hi, Pythonista!
Click: дополнительные проверки через Callback
import click
def validate_positive(ctx, param, value):
if value <= 0:
raise click.BadParameter('Число должно быть положительным')
return value
@click.command()
@click.option('--count', type=int, callback=validate_positive, help='Количество')
def process(count):
click.echo(f'Count = {count}')
if __name__ == '__main__':
process()
При попытке python script.py --count -5 возникнет ошибка:
Error: Invalid value for '--count': Число должно быть положительным