Есть ли способ автоматически обрабатывать исключения с помощью Python Click?
В документации по обработке исключений Click упоминается, что определенные виды исключений, такие как Abort
, EOFError
а также KeyboardInterrupt
автоматически изящно обрабатываются рамкой.
Для приложения, которое я пишу, есть много моментов, из которых можно генерировать исключения. Завершение приложения - правильный шаг, но печать трассировки стека - нет. Я всегда мог сделать это вручную:
@cli.command()
def somecommand:
try:
# ...
except Exception as e:
click.echo(e)
Однако есть ли способ, чтобы Click обрабатывал все исключения автоматически?
2 ответа
В нашем CLI все команды сгруппированы в одну группу команд. Это позволило нам реализовать некоторое поведение, которое необходимо было выполнить для каждой команды. Одна часть этого - обработка исключений.
Наша точка входа выглядит примерно так:
@click.group()
@click.pass_context
def entry_point(ctx):
ctx.obj = {"example": "This could be the configuration"}
Мы используем его для запуска глобального кода, например, для настройки context
, но вы также можете определить пустой метод, который ничего не делает. Другие команды могут быть добавлены в эту группу команд либо с помощью @entry_point.command()
декоратор или entry_point.add_command(cmd)
,
Для обработки исключений мы переносим entry_point
в другом методе, который обрабатывает исключения:
def safe_entry_point():
try:
entry_point()
except Exception as e:
click.echo(e)
В setup.py
Мы настраиваем точку входа для CLI и указываем ее на оболочку:
entry_points={
'console_scripts': [
'cli = my.package:safe_entry_point'
]
}
Команды CLI могут быть выполнены через его группу команд: например, cli command
,
Там могут быть более элегантные решения, но именно так мы и решили. Хотя он представляет группу команд как элемент самого высокого уровня в вашем CLI, но он позволяет нам обрабатывать все исключения в одном месте без необходимости дублировать нашу обработку ошибок в каждой команде.
Если вы хотите обрабатывать исключение только для определенных команд CLI. Вы можете использовать другой декоратор для обработки исключений.
Вот пример:
import click
from functools import wraps, partial
class NumberTooLarge(Exception):
pass
def catch_exception(func=None, *, handle):
if not func:
return partial(catch_exception, handle=handle)
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except handle as e:
raise click.ClickException(e)
return wrapper
@click.command()
@click.option("--count", default=1, help="Number of greetings.")
@catch_exception(handle=(NumberTooLarge, ValueError))
def hello(count):
"""Simple program that greets NAME for a total of COUNT times."""
if count > 100:
raise NumberTooLarge('count cannot be greater than 100')
if count < 0:
raise ValueError('count too small')
click.echo('Great choice!')
if __name__ == "__main__":
hello()