Skip to main content

Decorator-based rate limiter with sliding window, burst allowance, per-key limits, and async support

Project description

ratelimiter

Decorator-based rate limiter for Python — sliding window algorithm, burst allowance, per-key limits, multiple windows, and full async support. Zero dependencies.

PyPI version Python License: MIT


Installation

pip install ratelimiter

No dependencies. Requires Python 3.8+.


Quick Start

from ratelimiter import rate_limit, RateLimitExceeded

@rate_limit(10, "second")
def call_api():
    return requests.get("https://api.example.com/data")

Usage

Basic Limiting

from ratelimiter import RateLimiter, rate_limit

# As a reusable limiter object
limiter = RateLimiter(limit=10, window="second")

@limiter
def fetch(): ...

# As a one-off decorator
@rate_limit(100, "minute")
def send_email(): ...

Windows

Window Value
"second" 1 second
"minute" 60 seconds
"hour" 3600 seconds
"day" 86400 seconds

Burst Allowance

Allow a temporary burst above the base limit:

@rate_limit(10, "second", burst=5)
def fn(): ...
# Allows up to 15 calls/second in bursts, then enforces 10/sec

Multiple Windows

Enforce multiple limits simultaneously:

limiter = RateLimiter(
    limit=10, window="second",
    additional_windows=[
        {"limit": 100, "window": "minute"},
        {"limit": 1000, "window": "day"},
    ]
)

@limiter
def api_call(): ...

Per-Key Rate Limiting (per user/IP)

limiter = RateLimiter(
    limit=10, window="minute",
    key_func=lambda args, kwargs: kwargs.get("user_id")
)

@limiter
def create_post(user_id, content): ...

create_post(user_id="alice", content="hello")  # alice's limit
create_post(user_id="bob", content="hi")       # bob's own limit

Async Support

Works transparently with async def:

@rate_limit(50, "second")
async def async_fetch(url):
    async with aiohttp.ClientSession() as s:
        return await s.get(url)

Wait Instead of Raise

limiter = RateLimiter(5, "second", raise_on_limit=False)

@limiter
def fn(): ...
# Automatically waits for a slot instead of raising

Handling Exceptions

from ratelimiter import RateLimitExceeded

try:
    call_api()
except RateLimitExceeded as e:
    print(f"Limited! Retry after {e.retry_after:.2f}s")
    time.sleep(e.retry_after)

Introspection

# Check status without consuming a slot
status = limiter.check()
# {"allowed": True, "remaining": 8, "retry_after": 0}

# Usage stats
stats = limiter.stats()
# {"total_calls": 42, "rejected_calls": 3, "current_count": 7, ...}

# Reset
limiter.reset()

CLI Tool

Test any rate limit configuration interactively:

ratelimiter-test --limit 5 --window second
ratelimiter-test --limit 10 --window minute --burst 3 --calls 15

Output:

  Call   1/15  ✅ ALLOWED  remaining=9  [█████████░]
  Call   2/15  ✅ ALLOWED  remaining=8  [████████░░]
  ...
  Call  11/15  ❌ BLOCKED  (retry in 0.823s)

API Reference

RateLimiter

RateLimiter(
    limit,                  # Max calls per window
    window="second",        # "second", "minute", "hour", "day"
    burst=0,                # Extra burst calls above limit
    key_func=None,          # Callable(args, kwargs) -> str for per-key limiting
    raise_on_limit=True,    # False = wait instead of raise
    additional_windows=[],  # [{"limit": N, "window": "..."}]
)
Method Description
__call__(func) Use as decorator
check(key) Check status without consuming
reset(key) Reset counter
stats(key) Get usage statistics

rate_limit

Functional decorator factory — same parameters as RateLimiter.


Running Tests

pip install pytest
pytest tests/ -v

License

MIT © prabhay759

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

ratelimiterapi-1.0.0.tar.gz (10.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ratelimiterapi-1.0.0-py3-none-any.whl (9.7 kB view details)

Uploaded Python 3

File details

Details for the file ratelimiterapi-1.0.0.tar.gz.

File metadata

  • Download URL: ratelimiterapi-1.0.0.tar.gz
  • Upload date:
  • Size: 10.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ratelimiterapi-1.0.0.tar.gz
Algorithm Hash digest
SHA256 1dc175712c145bb8191d229d3a46c74a2701e6021a32c423b5725a1367bb29b0
MD5 aae7081652647b8b818cb876d3eb1de2
BLAKE2b-256 2624861b9f999196b7f1b1c517f518564bfeba95ba3111461dfef2e7fee94419

See more details on using hashes here.

Provenance

The following attestation bundles were made for ratelimiterapi-1.0.0.tar.gz:

Publisher: publish.yml on prabhay759/ratelimiter

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ratelimiterapi-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: ratelimiterapi-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 9.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ratelimiterapi-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a3bc783d02f610b8977239c7e343d5f0e307bb151996d341c22e2dea04e6cd66
MD5 35894ee475db682df95a4acebb241605
BLAKE2b-256 b9eda6af6d1f51b48c0f93f86c90ec5b3ba37aa6f051658a46d4b4d831ced618

See more details on using hashes here.

Provenance

The following attestation bundles were made for ratelimiterapi-1.0.0-py3-none-any.whl:

Publisher: publish.yml on prabhay759/ratelimiter

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page