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,
)

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

  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).

JSONPathParser и HTMLParser

Дополнительные декораторы для извлечения данных без ручной работы с ValidationData.

from request_decorator_handlers import JSONPathParser, HTMLParser

@JSONPathParser.parse_field("$.user.email", "email")
@HTMLParser.parse("div.status", save_to="status")
async def call(session):
    return await session.get("https://example.com")

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

JSON нормализация

Библиотека включает JSONValidator (используется автоматически):

  • декодирует строки/байты;
  • обрабатывает вложенные JSON-строки, множественные объекты, комментарии, trailing comma;
  • возвращает dict/list или None.

Прямой импорт JSONValidator доступен через from utils.json_validator import JSONValidator.

Работа с результатом

WithValid — универсальная обёртка:

result = await fetch_user()
if result.valid.has_errors():
    ...
print(result.valid.ERRORS)     # список ValidationError
print(result.valid.PARSED)     # извлечённые значений
original_response = result.response

ValidationError содержит key, expected, actual, message.

Управление логами

  • Настройку loguru делайте сами, библиотека лишь добавляет свои сообщения.
  • Не забудьте RequestLogger.enable() (или logger.enable("request_decorator_handlers")).
  • Для полной тишины в рантайме используйте:
    RequestLogger.disable()
    # или вручную
    logger.disable("request_decorator_handlers")
    

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

@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")

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

  • RetryContext — contextvar для передачи информации о ретраях между вызовами.
  • LOG_ACTION — перечисление действий (удобно для консистентных логов).
  • Каталог examples/ содержит рабочие сценарии.
  • docs/ — текстовые инструкции и подробные примеры.

Если необходима интеграция со своей инфраструктурой логирования или кастомными валидаторами, достаточно реализовать функцию Callable[[Response, ValidationData], None] и передать её в ResponseHandler.handlers(...).

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

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.2.tar.gz (54.4 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.2-py3-none-any.whl (32.3 kB view details)

Uploaded Python 3

File details

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

File metadata

File hashes

Hashes for request_decorator_handlers-0.1.2.tar.gz
Algorithm Hash digest
SHA256 277b62dbad4168272fe01e91d63487cfe1c2248148601b62ee86ed71ec75c3d5
MD5 933d4509e87b4c0324482acc76fe8b72
BLAKE2b-256 162b29b5abd372dfd32918f070bc3bf2d4d0dd085e06986a724602abe1e7efae

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for request_decorator_handlers-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 2cdd8122517ecf0a2c79be9ac90140586ae53210339114f3c0caf6004fcf2e72
MD5 461b61229ddddaac288fe6971c347742
BLAKE2b-256 5183272728685851f0ca8f3267a969fdea2cf633627913c7373b35554a702867

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