An elegant, thread-safe, in-memory rate limiter for Python
Project description
Sheriff 🤠
An elegant, thread-safe, in-memory rate limiter for Python.
sheriff implements the Token Bucket algorithm, ensuring complete thread-safety with fine-grained locking and zero-leak memory management. It is designed to be lightweight, dependency-free, and extremely easy to integrate into any application or web framework (like FastAPI).
Features
- 🔒 Thread-Safe: Uses fine-grained concurrent locks to ensure rate-limiting consistency across multiple threads.
- 🪣 Token Bucket Algorithm: Standard token bucket rate limiting with lazy, high-precision token replenishment.
- 🧹 Self-Cleaning (Lazy Cleanup): Prunes stale/fully-replenished buckets from memory automatically to prevent memory leaks.
- ⚡ Zero Dependencies: Pure Python, built using standard library tools.
- 🚀 FastAPI / Web Ready: Fits perfectly into FastAPI's dependency injection (
Depends) system.
Installation
Install using pip:
pip install sheriff-limiter
Quick Start
Basic Usage
Use is_allowed for a simple boolean check:
from sheriff import RateLimiter
# Default: 10 requests capacity, replenishes 1 token per second
limiter = RateLimiter()
# Check if allowed
if limiter.is_allowed("user_ip_address"):
print("Request allowed!")
else:
print("Rate limit exceeded.")
Configuration Options
Initialize the limiter with custom parameters:
from sheriff import RateLimiter
# Configured for max 100 requests per minute
limiter = RateLimiter(max_requests=100, period=60.0)
# Or set capacity and refill rate directly
# Capacity of 5 tokens, refilling 0.5 tokens/sec
limiter = RateLimiter(capacity=5.0, refill_rate=0.5)
Advanced Features
1. Raising Exceptions on Exceeding Limits
You can use .check() which raises a RateLimitExceeded exception. The exception contains a retry_after parameter telling you how long to wait in seconds.
from sheriff import RateLimiter, RateLimitExceeded
limiter = RateLimiter(max_requests=5, period=10.0)
try:
# Consume 1 token
limiter.check("client_1")
except RateLimitExceeded as e:
print(f"Rate limit exceeded! Retry after {e.retry_after:.2f} seconds.")
2. Manual Resets
Clear specific keys or reset all rate limits entirely:
# Reset a single client
limiter.reset("client_1")
# Reset all clients and clear the memory cache
limiter.reset_all()
FastAPI Integration
sheriff is perfect for FastAPI dependencies. Here is how you can use it to rate-limit endpoints by IP address:
from fastapi import FastAPI, Depends, Request, HTTPException, status
from sheriff import RateLimiter, RateLimitExceeded
app = FastAPI()
# 100 requests per minute limit
limiter = RateLimiter(max_requests=100, period=60.0)
def rate_limit(request: Request):
client_ip = request.client.host if request.client else "unknown"
try:
limiter.check(client_ip)
except RateLimitExceeded as e:
raise HTTPException(
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
detail="Too many requests. Please slow down.",
headers={"Retry-After": str(int(e.retry_after or 0))}
)
@app.get("/items", dependencies=[Depends(rate_limit)])
async def read_items():
return {"status": "ok"}
License
MIT License. See LICENSE for details.
Project details
Release history Release notifications | RSS feed
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 sheriff_limiter-0.1.0.tar.gz.
File metadata
- Download URL: sheriff_limiter-0.1.0.tar.gz
- Upload date:
- Size: 6.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f832f6410f75d50c2c92266bc907f8547c8bd3a823da7dbe2c742a9ab6eb7bdb
|
|
| MD5 |
4183e9724583872173ce7a322fda4c72
|
|
| BLAKE2b-256 |
dad1531843c690f4fabbef292401cf07038d33d38b981debaae12ae5f376a297
|
File details
Details for the file sheriff_limiter-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sheriff_limiter-0.1.0-py3-none-any.whl
- Upload date:
- Size: 5.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
04025508f2cc3079a06c251ebc9cd372dcd7a01e66ce21cd718d7c1b2febc13a
|
|
| MD5 |
5c33a57883fe235149107cfed746b066
|
|
| BLAKE2b-256 |
0e928f7c6a91be54e40362e8c742fcc2a4dee5a4e647c182226ae62908296156
|