From 55489ac505ed3787e0a65d1efec17eb789eef551 Mon Sep 17 00:00:00 2001 From: Miwory Date: Fri, 16 Jan 2026 09:44:46 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B5=D0=B1=D0=BE=D0=BB=D1=8C=D1=88?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20=D0=B8=20?= =?UTF-8?q?=D1=83=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD=D0=B8=D0=B5=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pre-commit-config.yaml | 6 +- README.md | 186 +++++++++--------- pyproject.toml | 14 +- src/aiohttpx/__init__.py | 1 - .../{responses/__init__.py => responses.py} | 0 5 files changed, 104 insertions(+), 103 deletions(-) rename src/aiohttpx/{responses/__init__.py => responses.py} (100%) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a42ca3c..cc364d5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,18 +1,18 @@ repos: - repo: https://github.com/crate-ci/typos - rev: v1.36.3 + rev: v1.42.0 hooks: - id: typos - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.13.2 + rev: v0.14.13 hooks: - id: ruff args: [ --fix ] - id: ruff-format - repo: https://github.com/RobertCraigie/pyright-python - rev: v1.1.405 + rev: v1.1.408 hooks: - id: pyright diff --git a/README.md b/README.md index f1b3670..b0c742c 100644 --- a/README.md +++ b/README.md @@ -1,117 +1,121 @@ -# aiohttpx +# AioHTTPX -## Description +**AioHTTPX** is an internal async HTTP client built on top of **httpx.AsyncClient**, using **aiohttp** as the transport layer for improved async performance. +It also adds **Redis-backed rate limiting and response caching** at the transport level. -**aiohttpx** is an asynchronous HTTP client that merges the ergonomics and powerful API of [httpx](https://github.com/encode/httpx) with the high-performance transport layer of [aiohttp](https://github.com/aio-libs/aiohttp). -It also provides optional Redis-powered caching and rate-limiting to enable efficient, production-grade request handling with minimal setup. +--- -## Features +## What it provides -* Fully asynchronous HTTP client using **aiohttp** as the transport. -* Optional **Redis-based caching** to reduce redundant API calls. -* Optional **Redis-based rate limiting** to control request throughput. -* Familiar API interface inspired by **httpx**. +* `AioHTTPXClient` — a drop-in replacement for `httpx.AsyncClient` +* `aiohttp`-based async transport +* Optional **rate limiting** (Redis) +* Optional **response caching** (Redis, TTL via headers) -## Requirements +--- -* Python 3.13 or higher -* Redis server (if using caching or rate limiting) +## Installation (internal) -## Installation +Configure pip with your private index: -### Using `uv` Tool - -This project supports dependency management via the [uv tool](https://github.com/astral-sh/uv). -To set up the project: - -1. **Install uv** - - ```bash - curl -LsSf https://astral.sh/uv/install.sh | sh - ``` - -2. **Add to the repository** - - ```bash - uv add https://git.meowly.ru/Miwory/aiohttpx.git - ``` - -## Configuration - -aiohttpx supports several optional parameters for caching and rate limiting: - -### `key` — Redis prefix - -A string used as the **Redis key namespace** for all cache and rate-limit entries. -This allows multiple clients or services to share the same Redis instance without collisions. - -### `limit` — Rate limit - -The maximum number of requests allowed **per second** for this client. -This value is enforced using Redis, making it safe to use across distributed systems. - -### `X-Cache-TTL` — Enable caching for a request - -To enable caching for a specific request, include the header: - -```text -X-Cache-TTL: +```ini +[global] +index-url = https://git.miwory.dev/api/packages/Miwory/pypi/simple +username = +password = ``` -Example: +Then install: -```python -response = await client.get( - "/users", - headers={"X-Cache-TTL": "60"}, # cache this endpoint for 60 seconds -) +```bash +pip install aiohttpx ``` -If this header is present and Redis is configured, the response will be cached for the specified duration. +--- ## Usage -### Basic Example +### Basic client (no Redis) ```python -from aiohttpx.client import AioHTTPXClient +from aiohttpx import AioHTTPXClient -class TwitchAPIClient(AioHTTPXClient): - def __init__( - self, - redis_url: str, - client_id: str, - client_secret: str, - redirect_uri: str, - ): - self.base_uri = 'https://api.twitch.tv/helix' - self.client_id = client_id - self.client_secret = client_secret - self.redirect_uri = redirect_uri - - super().__init__( - base_url=self.base_uri, - headers={'Client-Id': self.client_id}, - redis_url=redis_url, - key='twitch', # Redis prefix - limit=10, # 10 requests per second - logger='Twitch API', - ) - - async def test_endpoint(self): - ... +async with AioHTTPXClient() as client: + r = await client.get("https://example.com") + print(r.text) ``` -## Linting and Pre-commit Checks +This uses: -This project uses `pre-commit` and `ruff` for linting and formatting. -Run the linting process with: +* `aiohttp.ClientSession` under the hood +* httpx-compatible request / response API -```bash -poe lint +--- + +## Rate limiting + +Rate limiting is **optional** and requires Redis. + +```python +client = AioHTTPXClient( + redis_url="redis://localhost:6379", + key="my-rate-limit-key", + limit=60, # requests per minute +) ``` -## License +How it works: -This project is licensed under the MIT License. -See `LICENSE` for details. +* Token-based limiting using Redis time +* Requests exceeding the limit are delayed and retried +* Implemented in `AsyncRateLimit` + +--- + +## Response caching + +Caching is also **optional** and Redis-backed. + +```python +client = AioHTTPXClient( + redis_url="redis://localhost:6379", +) +``` + +To enable caching for a request, set a TTL header: + +```python +await client.get( + "https://example.com/data", + headers={"X-Cache-TTL": "30"}, +) +``` + +Notes: + +* Cache key = method + URL +* TTL is read from `X-Cache-TTL` header +* Cached responses are fully reconstructed `Response` objects + +--- + +## Configuration parameters + +`AioHTTPXClient(...)` supports all standard `httpx.AsyncClient` arguments **plus**: + +| Parameter | Type | Description | +| ----------- | ------------- | -------------------- | +| `redis_url` | `str \| None` | Redis connection URL | +| `key` | `str \| None` | Rate limit Redis key | +| `limit` | `int \| None` | Requests per minute | +| `logger` | `str \| None` | Logger name | + +--- + +## Notes & limitations + +* ❌ Sync client is not supported +* ❌ HTTP/2 disabled (`http1=True`, `http2=False`) +* ✅ Automatic retry on network/connect errors + +--- diff --git a/pyproject.toml b/pyproject.toml index 588d30d..e5b659e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,11 +1,9 @@ [project] name = "aiohttpx" -version = "1.3.1" +version = "1.4.0" description = "Custom HTTPX client with aiohttp transport, rate limiter and caching" readme = "README.md" -authors = [ - { name = "Miwory", email = "miwory.uwu@gmail.com" } -] +authors = [{ name = "Miwory", email = "miwory.uwu@gmail.com" }] requires-python = ">=3.13" dependencies = [ "aiohttp[speedups]>=3.13,<=3.14", @@ -16,10 +14,10 @@ dependencies = [ [project.optional-dependencies] dev = [ - "ruff==0.14.2", - "pyright==1.1.407", - "poethepoet==0.37.0", - "pre-commit==4.3.0", + "ruff==0.14.13", + "pyright==1.1.408", + "poethepoet==0.40.0", + "pre-commit==4.5.1", "types-redis==4.6.0.20241004", ] diff --git a/src/aiohttpx/__init__.py b/src/aiohttpx/__init__.py index 2bdaa81..e69de29 100644 --- a/src/aiohttpx/__init__.py +++ b/src/aiohttpx/__init__.py @@ -1 +0,0 @@ -__version__: str = '1.1.0' diff --git a/src/aiohttpx/responses/__init__.py b/src/aiohttpx/responses.py similarity index 100% rename from src/aiohttpx/responses/__init__.py rename to src/aiohttpx/responses.py