Skip to main content

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

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

import asyncio

from request_decorator_handlers import (
    RequestLogger, RequestDebugger,
    ResponseHandler, Validator, ParserUtil,
)
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")

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

Metadata

Release files for request-decorator-handlers 0.1.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for request-decorator-handlers 0.1.6
File Size Uploaded
request_decorator_handlers-0.1.6.tar.gz 48.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for request-decorator-handlers 0.1.6
File Interpreter ABI Platform
request_decorator_handlers-0.1.6-py3-none-any.whl Python 3 none any Details

Total release size: 79.4 kB

Release files / request_decorator_handlers-0.1.6.tar.gz

Download URL request_decorator_handlers-0.1.6.tar.gz
Size 48.3 kB
Tags Source
SHA-256 checksum
How to use checksums
ca088a50dd875843cae2cc44148e8a80074a2449e233cbe4686227bcebff1ba8
BLAKE2b-256 checksum
How to use checksums
9d97e29656dde33b6e1496702b5ff5213163ff9c722a022ce1a30afd0fc1ff3c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.11

Release files / request_decorator_handlers-0.1.6-py3-none-any.whl

Download URL request_decorator_handlers-0.1.6-py3-none-any.whl
Size 31.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c2efb5b4695d2cf336eb702bdd7da79b59b6f172adf9e03e0ea4f38dcd00841d
BLAKE2b-256 checksum
How to use checksums
ac6dea81d3dcb2726da72dcf5e0b52bfb1806c0201025d2d229281b112253759
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.11

Release history Release notifications | RSS feed

This release

0.1.6 This release

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page