Библиотека обработки исключений для Python-проектов, расширяющая стандартный
модуль logging. Предоставляет декораторы и утилиты для структурированного
логирования ошибок с полным контекстом.
- Универсальные декораторы для синхронного и асинхронного кода
- Гибкое логирование с добавлением контекста выполнения
- Минимальные зависимости — только стандартная библиотека Python
- Поддержка Django и других веб-фреймворков
- Типизированные аннотации для улучшенной поддержки IDE
pip install git+https://github.com/Shindler7/edhandlers.git poetry add git+https://github.com/Shindler7/ehandlers.gitimport logging
from ehandlers.decorators import err_interceptor
logger = logging.getLogger(__name__)
@err_interceptor(log_obj=logger,
err_annotated='Обработка пользовательских данных')
def process_user_data(user_id: int) -> dict:
# Код функции...
if user_id < 0:
raise ValueError('ID пользователя не может быть отрицательным')
return {'id': user_id, 'status': 'active'}| Что нужно? | Какой декоратор? |
|---|---|
| Ошибка должна быть залогирована, но программа должна упасть | @err_interceptor |
| Ошибка допустима, нужно вернуть значение по умолчанию и записать в лог | @err_log_and_return |
| Возврат определённого значения должен вызвать исключение (валидаторы) | @raise_if_return |
Базовый декоратор для перехвата и логирования исключений с возможностью их повторного возбуждения.
import logging
from ehandlers.decorators import err_interceptor
logger = logging.getLogger(__name__)
@err_interceptor(
log_obj=logger,
err_annotated='Деление чисел',
args_to_annotate=True,
log_level=logging.ERROR)
def divide(a: float, b: float) -> float:
"""Выполняет деление a на b."""
return a / blog_obj— экземпляр логгера (обязательный)err_annotated— дополнительное описание ошибкиargs_to_annotate— логировать аргументы функции (по умолчаниюFalse)log_level— уровень логирования (по умолчаниюlogging.ERROR)err_raise— исключение для повторного возбуждения (опционально)from_err— сохранять оригинальный traceback (по умолчаниюTrue)
Логирует исключение и возвращает заданное значение вместо его возбуждения.
import logging
from ehandlers.decorators import err_log_and_return
logger = logging.getLogger(__name__)
@err_log_and_return(
log_obj=logger,
err_output={'status': 'error', 'message': 'Ошибка обработки'},
args_to_annotate=True)
def get_config_value(key: str) -> Any:
"""Получает значение из конфигурации."""
return CONFIG[key] # Может вызвать KeyErrorerr_output— значение, возвращаемое при ошибке (по умолчаниюNone)- Другие параметры аналогичны
@err_interceptor
Возбуждает исключение при возврате функцией определённых значений.
import logging
from ehandlers.decorators import raise_if_return
logger = logging.getLogger(__name__)
@raise_if_return(
exception=ValidationError,
log_obj=logger,
raise_by_type=(str,),
err_msg_annotate='Валидация данных')
def validate_email(email: str) -> bool:
"""Валидирует email адрес."""
if '@' not in email:
return 'Некорректный email адрес'
return Trueexception— исключение для возбуждения (обязательный)raise_by_type— кортеж значений, вызывающих исключение (по умолчаниюstr)- raise_by_none — возбуждать исключение при возврате
None(по умолчаниюFalse) err_msg_annotate— дополнительное описание в логе
Для использования внутри try...except блоков.
Логирует исключение и возбуждает его повторно.
import logging
from ehandlers.except_handlers.handlers import intercept_err_and_log
logger = logging.getLogger(__name__)
try:
data = json.loads(invalid_json)
except json.JSONDecodeError as err:
intercept_err_and_log(
err,
log_obj=logger,
err_annotated='Парсинг JSON'
)Создаёт и логирует новое исключение.
import logging
from ehandlers.except_handlers.handlers import raise_err_and_log
logger = logging.getLogger(__name__)
if not user.is_authenticated:
raise_err_and_log(
PermissionError,
err_message='Пользователь не аутентифицирован',
log_obj=logger,
log_level=logging.WARNING
)Логирует исключение без его повторного возбуждения.
import logging
from ehandlers.except_handlers.handlers import log_err
logger = logging.getLogger(__name__)
try:
db_record.save()
except DatabaseError as err:
log_err(err, log_obj=logger)
# Продолжаем выполнение...Все декораторы полностью поддерживают асинхронные функции и методы.
@err_interceptor(log_obj=logger)
async def fetch_data(url: str) -> dict:
"""Асинхронное получение данных."""
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.json()async def news_to_file(news: dict):
"""Сохранить новости в файл."""
try:
await files.write_json_async(configurate.NEWS_JSON_FULLPATH, news)
except OSError as err:
intercept_err_and_log(err, log_obj=logger)from fastapi import FastAPI, HTTPException
from ehandlers.decorators import err_interceptor
app = FastAPI()
@app.get("/items/{item_id}")
@err_interceptor(
log_obj=logger,
err_raise=HTTPException(status_code=500, detail="Внутренняя ошибка")
)
async def read_item(item_id: int):
# Логика обработки...При поддержке pytest собраны тесты для проверки функциональности.
python -m pytest- Добавлен аргумент
exclude_argsдля аргументаargs_to_annotate, что позволяет исключить отдельные аргументы функций из выдачи в логи. - Улучшена обработка типов данных.
- Исправлены ошибки при обработке асинхронных методов.
- Улучшена поддержка типизации для IDE.
- Оптимизирована производительность декораторов.
- Добавлена поддержка асинхронных функций.
- Расширена документация с примерами использования.
- Улучшена обработка контекста исключений.
- Обновлена структура пакета.
- Добавлены тесты для основных сценариев.
- Улучшена совместимость с Python 3.11+.
- Первый публичный релиз.
- Базовые декораторы и обработчики.
- Поддержка синхронного кода.
Приветствуется проактивная поддержка и участие в развитии.
Распространяется под лицензией MIT. См. файл LICENSE для подробностей.