Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

HTTPX Wrapper with Rate Limiting and Caching Transports.

PyPI Version Python Versions

BuildRelease Tests Coverage badge

Installation

httpxthrottlecache does not depend on an HTTP client directly. Install it with one of two extras, which selects the client:

pip install 'httpxthrottlecache[httpx2]'  # recommended

or

pip install 'httpxthrottlecache[httpx]'

httpx2 is a maintained fork of httpx and is the recommended option. The httpx extra pins httpx 0.28.1, the final release of the original, no-longer-maintained package.

Upgrading from an earlier version: httpx2 is no longer installed automatically, so install one of the extras above.

If both libraries are installed, httpx2 is used. httpxthrottlecache.HTTPX_IMPL reports which one is active.

For development, set up the environment with uv sync --extra httpx2.

Introduction

The goal of this project is a combination of convenience and as a demonstration of how to assemble HTTPX Transports in different combinations.

HTTP request libraries, rate limiting and caching are topics with deep rabbit holes: the technical implementation details & the decisions an end user has to make. The convenience part of this package is abstracting away certain decisions and making certain opinionated decisions as to how caching & rate limiting should be controlled.

This came about while implementing caching & rate limiting for edgartools: reducing network requests and improving overall performance led to a myriad of decisions. The SEC's Edgar site has a strict 10 request per second limit, while providing not-very-helpful caching headers. Overriding these caching headers with custom rules is necessary in certain cases.

Caching

This project provides four cache_mode options:

  • Disabled: Rate Limiting only
  • Hishel-File: Cache using Hishel using FileStorage
  • Hishel-S3: Cache using Hishel using S3Storage
  • FileCache: Use a simpler filecache backend that uses file modified and created time and only revalidates using last-modified. For sites where last-modified is provided.

Cache Rules are defined as a dictionary of site regular expressions to path regular expressions.

{
    "site_regex": {
        "url_regex": duration,
        "url_regex2": duration,
        ".*": 3600,  # cache all paths for this site for an hour
    }
}

Misc Settings:

  • HTTPS_PROXY: HTTPS_PROXY environment variable is propagated to the HTTPX Transport

Usage: Synchronous Requests

Note that the Manager object is intended to be long lived, doesn't need to be used as a context manager.

from httpxthrottlecache import HttpxThrottleCache

url = "https://httpbingo.org/get"

with HttpxThrottleCache(
    cache_mode="Hishel-File",
    cache_dir="_cache",
    rate_limiter_enabled=True,
    request_per_sec_limit=10,
    user_agent="your user agent",
) as manager:
    # Single synchronous request
    with manager.http_client() as client:
        response = client.get(url)
        print(response.status_code)

Usage: Batch Requests

from httpxthrottlecache import HttpxThrottleCache

url = "https://httpbingo.org/get"

with HttpxThrottleCache(cache_mode="Hishel-File", 
    cache_dir = "_cache", 
    rate_limiter_enabled=True, 
    request_per_sec_limit=10, 
    user_agent="your user agent") as manager:

# Batch request
responses = manager.get_batch([url,url])
print([r[0] for r in responses])

Usage: Retrieve many files and write to files

from pathlib import Path
from httpxthrottlecache import HttpxThrottleCache

with HttpxThrottleCache(cache_mode="Disabled") as mgr:
    urls = {f"https://httpbingo.org/get?{i}": Path(f"file{i}") for i in range(10)}
    results = mgr.get_batch(urls=urls)

Usage: Asynchronous

from httpxthrottlecache import HttpxThrottleCache
import asynciosends

url = "https://httpbingo.org/get"
with HttpxThrottleCache(
    cache_mode="Hishel-File", cache_dir="_cache", rate_limiter_enabled=True, request_per_sec_limit=10
) as manager:
    # Async request
    async with manager.async_http_client() as client:
        tasks = [client.get(url) for _ in range(2)]
        responses = await asyncio.gather(*tasks)
        print(responses)

Usage: primp backend

For simulating web clients with browser TLS and HTTP/2 fingerprints, there's an optional backend: primp

pip install 'httpxthrottlecache[httpx2,primp]'
from httpxthrottlecache import HttpxThrottleCache

mgr = HttpxThrottleCache(
    cache_dir="_primp_cache",
    backend="primp",
    primp_params={"impersonate": "firefox", "impersonate_os": "windows"},
)
with mgr.http_client() as client:
    response = client.get("https://httpbingo.org/get")

primp_params is passed to primp.Client / primp.AsyncClient and defaults to {"impersonate": "firefox"}. It is ignored unless backend="primp".

FileCache

The FileCache implementation ignores response caching headers. Instead, it treats data as "fresh" for a client-provided max age. The max age is defined in a cacherule, as defined above.

Once the max age is expired, the FileCache Transport will revalidate the data using the Last-Modified date. TODO: Revalidate using ETAG as well.

The FileCache implementation stores files as the raw bytes plus a .meta sidecar. The .meta provides headers, such as Last-Modified, which are used for revalidation. The raw bytes are in the native format - binary files are in their native format, compressed gzip streams are stored as compressed gzip data, etc.

FileCache uses FileLock to ensure only one writer to a cached object. This means that (currently) multiple simultaneous cache misses will stack up waiting to write to file. This locking is intended mainly to allow multiple processes to share the same cache.

FileCache initially stages data to a .tmp file, then upon completion, copies to the final file.

No cache cleanup is done - that's your problem.

Rate Limiting

Rate limiting is implemented via pyrate_limiter. This is a leaky bucket implementation that allows a configurable number of requests per time interval.

pyrate_limiter supports a variable of backends. The default backend is in-memory, and a single Limiter can be used for both sync and asyncio requests, across multiple threads. Alternative limiters can be used for multiprocess and distributed rate limiting, see examples for more.

Metadata

Release files for httpxthrottlecache 0.7.0a1

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

Source distribution (sdist)

Source distribution for httpxthrottlecache 0.7.0a1
File Size Uploaded
httpxthrottlecache-0.7.0a1.tar.gz 17.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for httpxthrottlecache 0.7.0a1
File Interpreter ABI Platform
httpxthrottlecache-0.7.0a1-py3-none-any.whl Python 3 none any Details

Total release size: 34.7 kB

Release files / httpxthrottlecache-0.7.0a1.tar.gz

Download URL httpxthrottlecache-0.7.0a1.tar.gz
Size 17.7 kB
Tags Source
SHA-256 checksum
How to use checksums
92acec7a7d4c46aa025dbb919d84d314c020addd7bfcdf0cb685a9fe24efcd84
BLAKE2b-256 checksum
How to use checksums
95315351473af781f24334da3f7f0e21ee6577641c37c480374fe3f33ce79f29
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release files / httpxthrottlecache-0.7.0a1-py3-none-any.whl

Download URL httpxthrottlecache-0.7.0a1-py3-none-any.whl
Size 17.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9ec89005f6315d714c836c5be732433fc73bd25eca4aee6d84e3df28e6d73519
BLAKE2b-256 checksum
How to use checksums
b38ee05df0ced3091878ca71bbf96f1c2139c01534777849c9e45f47a338cc4d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release history Release notifications | RSS feed

0.7.0

2 release files

This release

0.7.0a1 This release

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.3.5

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.4

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