Skip to main content

httpx-frugal

An httpx client with persistent caching (hishel) and per-domain rate limiting (pyrate-limiter), designed for data pipelines that need to conserve API quota across process restarts.

Cache is checked before rate limiting, so cached responses do not consume rate-limit tokens.

Install

pip install httpx-frugal

Optional extras:

pip install httpx-frugal[http2]   # HTTP/2 inner transport

Quickstart (sync)

import pathlib

from pyrate_limiter import Duration, Rate

from httpx_frugal import RateLimitedCacheClient

rates = [Rate(5, Duration.MINUTE)]
cache_db = pathlib.Path("~/.cache/myapp/http-cache.sqlite").expanduser()
rate_db = pathlib.Path("~/.cache/myapp/rate-limiter.sqlite").expanduser()
cache_db.parent.mkdir(parents=True, exist_ok=True)
rate_db.parent.mkdir(parents=True, exist_ok=True)

client_wrapper = RateLimitedCacheClient(
    rates=rates,
    cache_db_path=cache_db,
    rate_limiter_db_path=rate_db,
)

if client_wrapper.would_hit_cache("https://api.example.com/data"):
    print("served from cache on next request")

with client_wrapper as client:
    response = client.get("https://api.example.com/data")
    print(response.extensions.get("hishel_from_cache"))

Async

from httpx_frugal import AsyncRateLimitedCacheClient

async with AsyncRateLimitedCacheClient(
    rates=rates,
    cache_db_path=cache_db,
    rate_limiter_db_path=rate_db,
) as client:
    response = await client.get("https://api.example.com/data")

Blocking mode

Wait for a rate-limit token instead of raising immediately:

client_wrapper = RateLimitedCacheClient(
    rates=rates,
    cache_db_path=cache_db,
    rate_limiter_db_path=rate_db,
    blocking=True,
    rate_limit_timeout_seconds=30.0,
)

Per-request cache TTL

Override TTL for a single request via httpx extensions:

with client_wrapper as client:
    client.get("https://api.example.com/short-lived", extensions={"hishel_ttl": 60})

Or use the helper:

from httpx_frugal import request_with_ttl

with client_wrapper as client:
    req = request_with_ttl(client, "GET", "https://api.example.com/x", ttl=120)
    client.send(req)

Rate limit introspection

remaining = client_wrapper.tokens_available("api.example.com")
# e.g. {"5/60000s": 3}

Cache invalidation

client_wrapper.clear_cache()                    # all entries
client_wrapper.clear_cache_for("https://...")  # one URL
client_wrapper.clear_rate_limiter()            # reset tokens

Multi-process pipelines

Enable SQLite file locking on the rate limiter bucket:

RateLimitedCacheClient(..., use_file_lock=True)

would_hit_cache caveat

would_hit_cache() uses hishel internal APIs and may break if hishel changes them. Prefer checking response.extensions["hishel_from_cache"] after requests when possible. httpx-frugal pins hishel>=1.2,<2.

Development

uv sync
uv run ruff check .
uv run pytest

License

MIT

Release files for httpx-frugal 0.2.1

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

Source distribution (sdist)

Source distribution for httpx-frugal 0.2.1
File Size Uploaded
httpx_frugal-0.2.1.tar.gz 49.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for httpx-frugal 0.2.1
File Interpreter ABI Platform
httpx_frugal-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size:61.3 kB

Release files / httpx_frugal-0.2.1.tar.gz

Download URL httpx_frugal-0.2.1.tar.gz
Size 49.8 kB
Tags Source
SHA-256 checksum
How to use checksums
ea9d8e04b399ac237f10616ec4f6afb2612735afae6ab5cb20107c034b2c9e99
BLAKE2b-256 checksum
How to use checksums
3c339ee63e8dc3bd8e03ce4b1b5281557fa9b8dd0c3e3b62fe66071c6952588f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.4

Release files / httpx_frugal-0.2.1-py3-none-any.whl

Download URL httpx_frugal-0.2.1-py3-none-any.whl
Size 11.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1851e437bf471fc23df336a048757a0033c15a57c362e72b04d2b163e3b12e06
BLAKE2b-256 checksum
How to use checksums
658cabd2d99e899e7b94168c1f3e5c5f63fe94f33fb47a69ddabaa36193f4ef1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.4

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files

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