Skip to main content

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sheriff_limiter-0.1.0.tar.gz (6.7 kB view details)

Uploaded Source

Built Distribution

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

sheriff_limiter-0.1.0-py3-none-any.whl (5.2 kB view details)

Uploaded Python 3

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

Hashes for sheriff_limiter-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f832f6410f75d50c2c92266bc907f8547c8bd3a823da7dbe2c742a9ab6eb7bdb
MD5 4183e9724583872173ce7a322fda4c72
BLAKE2b-256 dad1531843c690f4fabbef292401cf07038d33d38b981debaae12ae5f376a297

See more details on using hashes here.

File details

Details for the file sheriff_limiter-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for sheriff_limiter-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 04025508f2cc3079a06c251ebc9cd372dcd7a01e66ce21cd718d7c1b2febc13a
MD5 5c33a57883fe235149107cfed746b066
BLAKE2b-256 0e928f7c6a91be54e40362e8c742fcc2a4dee5a4e647c182226ae62908296156

See more details on using hashes here.

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