A powerful async library to fetch URLs with strict rate limiting (requests per second).
Project description
HTTP Wizz 🧙♂️
HTTP Wizz is a Python library designed for high-performance, asynchronous, rate-limited URL fetching. Whether you're scraping data, calling third-party APIs with strict limits, or building robust microservices, HTTP Wizz provides the tools to handle "requests per second" (RPS) constraints with ease.
Key Features
- ⏱️ Strict Rate Limiting: Precisely control your throughput with "requests per second" (RPS).
- 🌍 Domain-Specific Limits: Set different rate limits for different domains (e.g., fast for your API, slow for scraping).
- 💥 Burst Handling: Allow short bursts of traffic while maintaining long-term rate limits.
- 🔄 Automatic Retries: Built-in resilience for flaky networks and unstable APIs.
- ⏳ Smart Backoff: Respects standard
Retry-Afterheaders and supports exponential backoff. - 🎯 Custom Retry Logic: Force retries based on response content, even if the status code is
200 OK. - 📊 Progress Monitoring: Built-in integration with
tqdmfor progress bars. - 🪄 Versatile API: Choose between a simple sync function, a high-level async client, or a low-level
aiohttpwrapper.
Installation
pip install http-wizz
(Optional) For progress bar support:
pip install tqdm
Usage Guide
1. The Simple Way (Synchronous)
Perfect for quick scripts. Use fetch_urls to get results immediately without asyncio boilerplate.
from http_wizz import fetch_urls
urls = [f"https://api.example.com/data/{i}" for i in range(10)]
# Fetch at 5 requests per second with a progress bar
results = fetch_urls(urls, requests_per_second=5, show_progress=True)
2. The Wizard Way (Async Client)
Best for async applications. WizzClient handles rate limiting, retries, and JSON parsing automatically.
import asyncio
from http_wizz import WizzClient
async def main():
urls = ["https://api.example.com/item/1", "https://api.example.com/item/2"]
# Use as a context manager for proper cleanup
async with WizzClient(requests_per_second=10) as client:
results = await client.fetch_all(urls)
print(f"Fetched {len(results)} results")
asyncio.run(main())
3. The Power User Way (RateLimitedSession)
A drop-in replacement for aiohttp.ClientSession. Use this when you need full control over headers, cookies, or different HTTP methods (POST, PUT, etc.).
import asyncio
from http_wizz import RateLimitedSession
async def main():
async with RateLimitedSession(requests_per_second=2) as session:
for i in range(5):
# Supports .get, .post, .put, .delete, etc.
async with session.get(f"https://httpbin.org/get?id={i}") as resp:
data = await resp.json()
print(f"Status {resp.status}: {data.get('args')}")
asyncio.run(main())
Advanced Configuration
Domain-Specific Throttling
You can set a global rate limit and specific limits for certain domains.
from http_wizz import WizzClient
client = WizzClient(
requests_per_second=10, # Default limit for most domains
domain_limits={
"slow-api.com": 1, # Very strict limit for this domain
"fast-cdn.com": 50 # High throughput for this domain
}
)
Burst Handling
Allow small bursts of requests to go through instantly before throttling kicks in. This makes the client feel more responsive for small batches.
client = WizzClient(
requests_per_second=5,
burst_size=10 # Allow up to 10 requests immediately
)
Configuring Retries and Backoff
WizzClient automatically respects Retry-After headers (both seconds and dates). You can further customize the behavior:
client = WizzClient(
requests_per_second=5,
max_retries=5, # Number of retry attempts
initial_retry_delay=1.0, # Seconds to wait after first failure
exponential_backoff=True # Double the delay after each failure (1s, 2s, 4s...)
)
Custom Retry Conditions
Sometimes APIs return 200 OK but include an error message in the body. You can force a retry by providing a should_retry callback.
def check_for_api_errors(response, content):
# Retry if the API returned a 'try_again' flag in the JSON body
return isinstance(content, dict) and content.get("status") == "try_again"
results = fetch_urls(
["https://api.example.com/job"],
should_retry=check_for_api_errors,
max_retries=10
)
API Reference
fetch_urls(...)
urls: List of strings.requests_per_second: (float) Max requests/sec. Default10.burst_size: (int) Max concurrent burst. Default1.domain_limits: (dict) Map of domain string to RPS float.max_retries: (int) Default5.initial_retry_delay: (float) Default1.0.exponential_backoff: (bool) DefaultTrue.should_retry:callable(response, content) -> bool.show_progress: (bool) Show a tqdm progress bar. DefaultFalse.
WizzClient(...)
- High-level async client. Same arguments as
fetch_urls(excludingurlsandshow_progressin init). fetch_all(urls, show_progress=False): Asynchronously fetches all provided URLs.
RateLimitedSession(...)
requests_per_second: (float) Max requests/sec.burst_size: (int) Max concurrent burst.domain_limits: (dict) Map of domain string to RPS float.- All other arguments are passed to the underlying
aiohttp.ClientSession.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file http_wizz-1.0.0.tar.gz.
File metadata
- Download URL: http_wizz-1.0.0.tar.gz
- Upload date:
- Size: 11.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d4734445a91a89d11e47ccea5fca5a4246a1c2019ffcb8f370a7a0ab13fe04ce
|
|
| MD5 |
660faac52787501d49b4e70b1eed5a7d
|
|
| BLAKE2b-256 |
c3512ed58a201e89dea7ebfd51cd65c695498a88731a249d4b4ab9430286e841
|
Provenance
The following attestation bundles were made for http_wizz-1.0.0.tar.gz:
Publisher:
publish.yml on TomMcKenna1/http-wizz
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
http_wizz-1.0.0.tar.gz -
Subject digest:
d4734445a91a89d11e47ccea5fca5a4246a1c2019ffcb8f370a7a0ab13fe04ce - Sigstore transparency entry: 868493907
- Sigstore integration time:
-
Permalink:
TomMcKenna1/http-wizz@e01f6d21761c380986829f3f44372c2d6cdc5d0e -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/TomMcKenna1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e01f6d21761c380986829f3f44372c2d6cdc5d0e -
Trigger Event:
release
-
Statement type:
File details
Details for the file http_wizz-1.0.0-py3-none-any.whl.
File metadata
- Download URL: http_wizz-1.0.0-py3-none-any.whl
- Upload date:
- Size: 8.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2f358e3f86b947f65af505cdb16c66cb814759afc63193ab8ca416459a22cbe4
|
|
| MD5 |
ba167f028080f9069519ac2970b23b51
|
|
| BLAKE2b-256 |
785d5b628a0cc4d21de1d65e276f1766b073bf6db18c9cb3cb9c32cc0a3b20da
|
Provenance
The following attestation bundles were made for http_wizz-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on TomMcKenna1/http-wizz
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
http_wizz-1.0.0-py3-none-any.whl -
Subject digest:
2f358e3f86b947f65af505cdb16c66cb814759afc63193ab8ca416459a22cbe4 - Sigstore transparency entry: 868493909
- Sigstore integration time:
-
Permalink:
TomMcKenna1/http-wizz@e01f6d21761c380986829f3f44372c2d6cdc5d0e -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/TomMcKenna1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e01f6d21761c380986829f3f44372c2d6cdc5d0e -
Trigger Event:
release
-
Statement type: