Skip to main content

Decorators, validators, logging and debugging helpers for async HTTP requests

Project description

request-decorator-handlers

Набор декораторов и утилит для асинхронных HTTP-запросов. Библиотека помогает логировать запросы, повторять их при ошибках, валидировать ответы и извлекать нужные данные, не усложняя приложение бизнес-логикой.

  • 🧪 Валидаторы с наглядным журналом ошибок (Validator и ResponseHandler)
  • 📦 Парсеры (Parser.JSON, Parser.HTML, JSONPath/HTML helpers)
  • 🪵 Цветное логирование (RequestLogger) с управлением через loguru
  • 🧾 Отладчик (RequestDebugger) — коллекция невалидных ответов и уникальных JSON
  • 🔁 Повторы запросов (ResponseHandler.retry)

Установка

pip install request-decorator-handlers

Основные импорты

from request_decorator_handlers import (
    RequestLogger, RequestDebugger,
    ResponseHandler, Validator, Parser,
)

Быстрый старт

import asyncio

from request_decorator_handlers import (
    RequestLogger, RequestDebugger,
    ResponseHandler, Validator, Parser,
)
from curl_cffi import AsyncSession

# @RequestDebugger.debug(save_errors=True)
@ResponseHandler.retry(error_key="STATUS_CODE", quantity=3, interval=2.0)
@RequestLogger.log(action="GET_IP", log_level="success_error", show_body=True)
@ResponseHandler.handlers(
    Validator.status([312]),
    Validator.content_type("json"),
    Validator.JSON("$.query", exists=True, error_key="QUERY_EXISTS"),
)
async def fetch_ip(client: AsyncSession):
    return await client.get("http://ip-api.com/json")

async def main():
    async with AsyncSession() as client:
        result = await fetch_ip(client)
        print(result.valid.ERRORS, result.valid.PARSED)

asyncio.run(main())

Требования к функциям

  1. Декораторы ожидают асинхронные функции, возвращающие HTTP-ответ (любой тип с полями status_code, headers, text/content и т.п.) — например, curl_cffi.AsyncResponse, httpx.Response.

  2. Декораторы ResponseHandler.handlers(...) и ResponseHandler.retry(...) оборачивают результат в WithValid[Response]. Если нужна строгая типизация:

    from typing import Annotated
    from request_decorator_handlers import WithValid
    
    @ResponseHandler.handlers(...)
    async def fetch_user(...) -> WithValid[Response]:
        ...
    
  3. Для интеграции со сторонними клиентов необходимо:

    • использовать их сессию/класс ответа;
    • возвращать исходный объект ответа (его обёртка WithValid создаётся сама).

Быстрый пример

import asyncio
from curl_cffi import AsyncSession
from request_decorator_handlers import (
    RequestLogger, RequestDebugger,
    ResponseHandler, Validator,
)

# Настраиваем loguru, потом включаем вывод библиотеки
from loguru import logger
logger.add(sys.stderr, format="{time} {level} {message}", colorize=True)
RequestLogger.enable()

@RequestDebugger.debug(save_errors=True)
@RequestLogger.log(action="GET_IP", log_level="success_error", show_body=True)
@ResponseHandler.handlers(
    Validator.status([200]),
    Validator.content_type("json"),
    Validator.JSON("$.query", exists=True, error_key="QUERY_EXISTS"),
)
@ResponseHandler.retry(error_key="STATUS_CODE", quantity=3, interval=2.0)
async def fetch_ip(client: AsyncSession):
    return await client.get("http://ip-api.com/json")

async def main():
    async with AsyncSession() as client:
        result = await fetch_ip(client)
        print(result.valid.ERRORS, result.valid.PARSED)

asyncio.run(main())

RequestLogger — цветное логирование

Логгер работает через loguru. По умолчанию его вывод выключен, чтобы библиотека не засоряла консоль. Включите его один раз после своей настройки loguru:

from request_decorator_handlers import RequestLogger
RequestLogger.enable()

Декоратор RequestLogger.log

@RequestLogger.log(
    action: str,
    log_level: Literal["full", "success_error", "error_only"] = "full",
    show_body: bool = False,
    len_text: int | None = None,
    show_response_headers: bool = False,
    show_request_body: bool = False,
    show_request_headers: bool = False,
    enabled: bool = True,
)
  • action — подпись (отображается в логе).
  • log_level — объём сообщений:
    • full — старт, успехи, ошибки;
    • success_error — только финальные успехи + ошибки;
    • error_only — только ошибки.
  • show_body — добавить блок с телом ответа (JSON/текст/байты).
  • show_request_body / show_request_headers — показать исходные данные.
  • show_response_headers — вывести заголовки из ответа.
  • len_text — ограничение длины строковых значений.
  • enabled — быстро отключить логирование для конкретной функции.

Дополнительно:

  • RequestLogger.disable() — навсегда убрать вывод.
  • RequestLogger.muted() — контекстный менеджер для временной тишины.

ResponseHandler — валидация и ретраи

Декоратор ResponseHandler.handlers

@ResponseHandler.handlers(
    Validator.status([200]),
    Validator.headers(["content-type"]),
    ...
)

Каждый валидатор получает оригинальный ответ и объект ValidationData. Если валидатор находит несоответствие, он добавляет запись об ошибке.

Функция, обёрнутая в ResponseHandler.handlers, возвращает WithValid[Response]:

with_valid.valid.has_errors()  # bool
with_valid.valid.ERRORS        # список ValidationError
with_valid.valid.PARSED        # словарь с распарсенными значениями
with_valid.response            # оригинальный Response

Доступные валидаторы

Все валидаторы находятся в Validator (из request_decorator_handlers):

Валидатор Назначение Основные аргументы
Validator.status(allowed) Проверить HTTP-код allowed: Iterable[int]
Validator.headers(required) Обязательные заголовки список имён
Validator.cookies(session, domain, required) Проверка cookie сессия + домен + имена cookie
Validator.content_type(expected) Формат ответа expected: "json", "html", "text", "image", "bytes"
Validator.REGEX(pattern, target="text") Совпадение по regex target: "text", "json", "content"; expect_match; save_to
Validator.JSON(path, ...) JSONPath-проверка exists, value, is_type, range_value, regex, words, error_key
Validator.HTML(selector, ...) HTML/XPath-проверка selector_type, extract, attr_name, exists, фильтры
Validator.cloudflare_blocked() Детектор Cloudflare-страниц keywords (опционально), error_key

Фильтры для JSON/HTML валидаторов

  • words: список слов/фраз (хватает совпадения одного).
  • regex, regex_flags: дополнительное регулярное выражение.
  • value: точное совпадение.
  • is_type: проверка типа (int, str, bool и т.п.).
  • range_value=(min, max): числовой диапазон.

Хранение парсенных значений

У многих валидаторов есть save_to, чтобы сохранить найденные значения в valid.PARSED. Это касается Validator.REGEX и методов из Parser (см. ниже).

JSON / HTML / REGEX парсеры

Parser (из request_decorator_handlers.validation.response) удобен, если нужно извлечь данные и использовать их дальше:

@ResponseHandler.handlers(
    Validator.status([200]),
    Parser.JSON("$.user.email", save_to="email"),
    Parser.HTML("span.username", words=["admin"], save_to="role"),
    Validator.REGEX(r'"token"\\s*:\\s*"([^"]+)"', target="json", save_to="token"),
)

ResponseHandler.retry

@ResponseHandler.retry(
    error_key: str | Iterable[str],
    quantity: int = 3,
    interval: float = 0.5,
    enabled: bool = True,
)
  • error_key — одно имя или список имён ошибок из ValidationData.ERRORS.
  • quantity — максимум попыток (включая первую).
  • interval — задержка между повторами в секундах.
  • enabled — общий переключатель.

Контекст ретрая сохраняется в ValidationData.RETRY (экземпляр RetryInfo).

RequestDebugger — запись проблемных ответов

@RequestDebugger.debug(
    enabled: bool = True,
    save_errors: bool = True,
    save_unique_structures: bool = False,
    debug_dir: str = "debug_request",
)
  • save_errors — сохраняет JSON с ошибками и метаданными запроса.
  • save_unique_structures — сохраняет структуру успешного ответа (для документов по API).
  • debug_dir — корневая папка для записей.

Файлы структурируются по домену, пути и типу (errors_json, unique_json).

Результат будет обёрнут в WithValid, а извлечённые значения попадут в valid.PARSED.

Пример комплексной связки

@RequestDebugger.debug(save_errors=True, debug_dir="debug")
@RequestLogger.log("FETCH_PROFILE", log_level="success_error", show_body=True)
@ResponseHandler.retry(error_key=["STATUS_CODE", "API_STATUS"], quantity=3, interval=2)
@ResponseHandler.handlers(
    Validator.status([200]),
    Validator.content_type("json"),
    Parser.JSON("$.profile.id", save_to="profile_id"),
    Validator.JSON("$.profile.is_active", value=True, error_key="USER_INACTIVE"),
    Validator.REGEX(r"\"token\":\"([^\"]+)\"", target="json", save_to="token"),
)
async def fetch_profile(session):
    return await session.get("https://api.example.com/profile")

Приятной отладки и чистых логов! 💙

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

request_decorator_handlers-0.1.5.tar.gz (51.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

request_decorator_handlers-0.1.5-py3-none-any.whl (29.8 kB view details)

Uploaded Python 3

File details

Details for the file request_decorator_handlers-0.1.5.tar.gz.

File metadata

File hashes

Hashes for request_decorator_handlers-0.1.5.tar.gz
Algorithm Hash digest
SHA256 08f5fe9d287f75fe637e3f63ff5dfb4d1aa6bb5ccde88eeb66eccd5229ded784
MD5 06e643f8a586d02ac1c8ed39ad91bc84
BLAKE2b-256 28248df0f6cdcaee8bf5527d5c6eb75db2fe419e33671fe7c93c552e16c1205a

See more details on using hashes here.

File details

Details for the file request_decorator_handlers-0.1.5-py3-none-any.whl.

File metadata

File hashes

Hashes for request_decorator_handlers-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 3f2c80bb1f553ad7b4a01bda580d57fe28023aba34362332bf1c1dbd44dd141a
MD5 04200cec3cdcce94c8985b571b3e966f
BLAKE2b-256 cf69fac29c14d97819cd62786fe71d707a6858f6a8ded82eecfd45c646b0cf80

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page