Skip to main content

philiprehberger-rate-limiter

Tests PyPI version Last updated

In-memory rate limiter with sliding window, token bucket, and leaky bucket algorithms.

Installation

pip install philiprehberger-rate-limiter

Usage

from philiprehberger_rate_limiter import RateLimiter, Algorithm

limiter = RateLimiter(
    requests=100,
    window_seconds=60,
    algorithm=Algorithm.SLIDING_WINDOW,
)

if limiter.allow("user-123"):
    handle_request()

Check Status

from philiprehberger_rate_limiter import RateLimiter

limiter = RateLimiter(100, 60)
status = limiter.status("user-123")
print(f"Allowed: {status.allowed}")
print(f"Remaining: {status.remaining}/{status.limit}")
print(f"Resets at: {status.reset_at}")

Usage Statistics

from philiprehberger_rate_limiter import RateLimiter

limiter = RateLimiter(100, 60)
limiter.allow("user-123")

stats = limiter.get_stats("user-123")
print(f"Current usage: {stats.current_usage}")
print(f"Remaining: {stats.remaining}")
print(f"Reset at: {stats.reset_at}")

Querying budget without consuming

from philiprehberger_rate_limiter import RateLimiter, Algorithm
import time

limiter = RateLimiter(100, 60, Algorithm.SLIDING_WINDOW)
for _ in range(15):
    limiter.allow("user-123")

# How many requests still allowed (does not consume a request)
print(limiter.remaining("user-123"))  # 85

# Monotonic timestamp when capacity for one more request is available
reset = limiter.reset_at("user-123")
print(f"Available in {max(0.0, reset - time.monotonic()):.1f}s")

Format status

from philiprehberger_rate_limiter import RateLimiter

limiter = RateLimiter(100, 60)
for _ in range(15):
    limiter.allow("user:123")

print(limiter.format_status("user:123"))
# "15/100 requests used (85 remaining); resets in 23.5s"

Blocking Wait

from philiprehberger_rate_limiter import RateLimiter

limiter = RateLimiter(100, 60)

# Synchronous — blocks until quota is available or timeout expires
status = limiter.wait("user-123", timeout=5.0)

# Async — awaits until quota is available
status = await limiter.async_acquire("user-123")

Async Context Manager

from philiprehberger_rate_limiter import RateLimiter

limiter = RateLimiter(100, 60)

async with limiter:
    status = await limiter.async_acquire("user-123")
    if status.allowed:
        await handle_request()

Decorator

from philiprehberger_rate_limiter import RateLimiter, rate_limit

# Standalone decorator
@rate_limit(calls=10, period=60)
def api_endpoint():
    return {"data": "ok"}

# Instance-based decorator
limiter = RateLimiter(10, 60)

@limiter.limit("10/minute")
def another_endpoint():
    return {"data": "ok"}

# Async function decorator
@rate_limit(calls=10, period=60)
async def async_endpoint():
    return {"data": "ok"}

Rate Limiter Groups

from philiprehberger_rate_limiter import RateLimiter, RateLimiterGroup

limiter = RateLimiter(100, 60)
group = RateLimiterGroup(limiter, ["api-key-1", "api-key-2", "api-key-3"])

# All keys in the group share one rate limit pool
group.allow("api-key-1")  # consumes from shared pool
group.allow("api-key-2")  # consumes from same pool

stats = group.get_stats()
print(f"Group usage: {stats.current_usage}/{stats.limit}")

Algorithms

from philiprehberger_rate_limiter import RateLimiter, Algorithm

# Fixed window — resets at interval boundaries
RateLimiter(100, 60, Algorithm.FIXED_WINDOW)

# Sliding window (default) — rolling time window
RateLimiter(100, 60, Algorithm.SLIDING_WINDOW)

# Token bucket — smooth rate with burst capacity
RateLimiter(100, 60, Algorithm.TOKEN_BUCKET)

# Leaky bucket — constant drain rate, smooths bursts
RateLimiter(100, 60, Algorithm.LEAKY_BUCKET)

API

Function / Class Description
RateLimiter(requests, window_seconds, algorithm) Create a rate limiter
limiter.allow(key) Check if request is allowed
limiter.status(key) Get detailed LimitStatus
limiter.get_stats(key) Get RateLimiterStats without consuming a request
limiter.remaining(key) Get the number of requests still allowed for key without consuming
limiter.reset_at(key) Monotonic timestamp when capacity for one more request is available
limiter.format_status(key) Get a human-readable single-line summary (e.g. "15/100 requests used (85 remaining); resets in 23.5s")
limiter.wait(key, timeout) Block until quota available or raise RateLimitExceeded
limiter.async_acquire(key) Async wait until quota is available
limiter.reset(key) Reset state for a key
limiter.reset_all() Reset state for all keys
limiter.active_keys() List all keys with active state
limiter.limit(rate) Decorator with rate string (e.g., "10/minute")
RateLimiterGroup(limiter, keys) Create a shared rate limit group
group.allow(key) Check if request is allowed against shared pool
group.status(key) Get shared LimitStatus
group.get_stats() Get shared RateLimiterStats
group.reset() Reset shared group state
rate_limit(calls, period, algorithm) Standalone decorator for rate limiting
format_status(status) Format a LimitStatus as a human-readable summary string
Algorithm Enum: FIXED_WINDOW, SLIDING_WINDOW, TOKEN_BUCKET, LEAKY_BUCKET
LimitStatus Dataclass: allowed, remaining, reset_at, limit
RateLimiterStats Dataclass: current_usage, remaining, reset_at, limit
RateLimitExceeded Exception raised when rate limit is exceeded

Development

pip install -e .
python -m pytest tests/ -v

Support

If you find this project useful:

⭐ Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT

Metadata

Release files for philiprehberger-rate-limiter 0.6.0

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

Source distribution (sdist)

Source distribution for philiprehberger-rate-limiter 0.6.0
File Size Uploaded Provenance
philiprehberger_rate_limiter-0.6.0.tar.gz 195.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for philiprehberger-rate-limiter 0.6.0
File Interpreter ABI Platform
philiprehberger_rate_limiter-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 204.8 kB

Release files / philiprehberger_rate_limiter-0.6.0.tar.gz

Download URL philiprehberger_rate_limiter-0.6.0.tar.gz
Size 195.5 kB
Tags Source
SHA-256 checksum
How to use checksums
6f43e1af13abc8db9a037bff0002c62ce589576fb3b9c29bd495a63a5dcf1088
BLAKE2b-256 checksum
How to use checksums
a6dad4d7492cea2d16d41dd62ba772b85b9bab36522f8973a72f4c2e26483b52
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.13

Release files / philiprehberger_rate_limiter-0.6.0-py3-none-any.whl

Download URL philiprehberger_rate_limiter-0.6.0-py3-none-any.whl
Size 9.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2c709229b994bfe0c8c74006894a0dbba9e659b87441257e527b8c458b719317
BLAKE2b-256 checksum
How to use checksums
5af3fd211e985e258b6cb3db0ae010c7301bc26287913b157ab6a2946a1dcd73
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.13

Security for philiprehberger-rate-limiter 0.6.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

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