Skip to main content

limitkit

A small, flexible rate-limiting library for Python.

  • 4 algorithms: token bucket, fixed window, sliding window, leaky bucket
  • 2 storage backends: in-memory (default) and Redis (for cross-process / distributed limiting)
  • Per-key limiting: one limiter instance handles per-user / per-IP / per-API-key buckets
  • Three API styles: direct check, context manager, decorator
  • Sync and async: every API works in both worlds

Install

pip install limitkit             # in-memory only
pip install limitkit[redis]      # adds the Redis backend

60-second tour

from limitkit import TokenBucket

# 5 req/sec sustained, burst tolerance of 5
limiter = TokenBucket(capacity=5, refill_rate=5)

# direct check
if limiter.allow("user:alice"):
    serve_request()

# context manager (raises RateLimitExceeded when over the limit)
with limiter:
    serve_request()

# decorator
@limiter
def search(query):
    ...

Algorithms

All four classes share the same surface (.allow(), with, @, async with, async @). Pick by the behavior you want:

Class Behavior When to use
TokenBucket(capacity, refill_rate) Allows bursts up to capacity; refills at refill_rate per second. Most APIs. "Up to 100 req with sustained 10 req/sec."
FixedWindow(limit, window) limit requests allowed per window seconds; resets at window boundaries. Simple counters: "max 1000 calls per hour." Cheap.
SlidingWindow(limit, window) Same limit but no boundary burst — the window slides with the request log. When fixed-window boundary bursts matter.
LeakyBucket(capacity, leak_rate) Smooths output to a constant rate; queues up to capacity units. Enforcing a maximum sustained outflow.

Per-key limiting

Pass a key to .allow() and one instance handles many independent buckets:

limiter = TokenBucket(capacity=10, refill_rate=2)

limiter.allow("user:alice")      # alice's bucket
limiter.allow("user:bob")        # bob's bucket — independent
limiter.allow("ip:192.0.2.1")    # any string works
limiter.allow()                  # uses key="default"

Async support

Every algorithm works in async code:

import asyncio
from limitkit import TokenBucket, RateLimitExceeded

limiter = TokenBucket(capacity=5, refill_rate=5)

@limiter
async def fetch(url):
    ...

async def main():
    async with limiter:
        await fetch("...")

    try:
        await fetch("...")
    except RateLimitExceeded:
        ...

asyncio.run(main())

Redis backend (cross-process / distributed)

In-memory limiters protect a single process. With multiple workers behind a load balancer you need shared state — pass a redis_url:

from limitkit import TokenBucket

limiter = TokenBucket(
    capacity=100,
    refill_rate=10,
    redis_url="redis://localhost:6379",
)

limiter.allow("user:alice")   # state lives in Redis; all workers see the same counter

Under the hood every check is a single Lua script call, so updates are atomic — no races between workers. Keys auto-expire after the bucket is fully refilled so abandoned keys don't accumulate.

Heavy / weighted requests

Use n= to mark a call as costing more than 1:

limiter.allow("user:alice", n=5)   # consumes 5 tokens instead of 1

Catching the limit

The decorator and context manager raise RateLimitExceeded:

from limitkit import RateLimitExceeded

try:
    with limiter:
        ...
except RateLimitExceeded:
    return 429

.allow() returns bool instead — pick whichever style fits your code.

License

MIT

Metadata

Release files for limitkit 0.1.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 limitkit 0.1.0
File Size Uploaded Provenance
limitkit-0.1.0.tar.gz 10.3 kB Without provenance Details

Built distribution (wheel)

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

Total release size: 19.3 kB

Release files / limitkit-0.1.0.tar.gz

Download URL limitkit-0.1.0.tar.gz
Size 10.3 kB
Tags Source
SHA-256 checksum
How to use checksums
95fb9c7b371ca75817c8fc87603fdcbbfe6a0527e167ebd34b60591d4023e7d8
BLAKE2b-256 checksum
How to use checksums
ba73aaaeb84863d2091440b4b57d74dbb0185d0a1131a981029e3ee1f5367aa8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release files / limitkit-0.1.0-py3-none-any.whl

Download URL limitkit-0.1.0-py3-none-any.whl
Size 9.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c5efa3d373e46bb2b6436ddd660c6922afbb82a29b0b3bb20b333a1fd9efc4bf
BLAKE2b-256 checksum
How to use checksums
1bef41e834a724d9c60ca0831913fc6d6b492c2d9a205a1de0aa2748df3ca844
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Security for limitkit 0.1.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.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

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