0
# Limits
1
2
A comprehensive Python library for implementing rate limiting functionality across various storage backends. Limits provides multiple rate limiting strategies including Fixed Window, Moving Window, and Sliding Window Counter algorithms, each with different memory efficiency and accuracy trade-offs.
3
4
## Package Information
5
6
- **Package Name**: limits
7
- **Language**: Python
8
- **Installation**: `pip install limits`
9
- **Repository**: https://github.com/alisaifee/limits
10
- **Documentation**: https://limits.readthedocs.io/
11
12
## Core Imports
13
14
```python
15
import limits
16
```
17
18
Common imports for rate limiting:
19
20
```python
21
from limits import RateLimitItem, parse
22
from limits.storage import storage_from_string
23
from limits.strategies import FixedWindowRateLimiter
24
```
25
26
For asynchronous usage:
27
28
```python
29
from limits.aio.strategies import FixedWindowRateLimiter as AsyncFixedWindowRateLimiter
30
from limits.storage import storage_from_string # Same function, use "async+" prefix
31
```
32
33
## Basic Usage
34
35
```python
36
from limits import RateLimitItemPerMinute, parse
37
from limits.storage import storage_from_string
38
from limits.strategies import FixedWindowRateLimiter
39
40
# Create rate limit items
41
rate_limit = RateLimitItemPerMinute(10) # 10 requests per minute
42
# Or parse from string
43
rate_limit = parse("10/minute")
44
45
# Set up storage backend
46
storage = storage_from_string("memory://")
47
# Or use Redis
48
# storage = storage_from_string("redis://localhost:6379")
49
50
# Create rate limiter with chosen strategy
51
limiter = FixedWindowRateLimiter(storage)
52
53
# Apply rate limiting
54
user_id = "user123"
55
if limiter.test(rate_limit, user_id):
56
# Request allowed
57
limiter.hit(rate_limit, user_id)
58
print("Request processed")
59
else:
60
print("Rate limit exceeded")
61
62
# Check remaining quota
63
stats = limiter.get_window_stats(rate_limit, user_id)
64
print(f"Remaining: {stats.remaining}, Reset at: {stats.reset_time}")
65
```
66
67
## Architecture
68
69
The limits library follows a modular architecture with three core components:
70
71
- **Rate Limit Items**: Define the rate limit parameters (amount, time window, granularity)
72
- **Storage Backends**: Handle persistence and distribution of rate limit counters across different storage systems
73
- **Rate Limiting Strategies**: Implement different algorithms for rate limit enforcement
74
75
This design enables flexible combinations of time windows, storage backends, and algorithmic strategies based on specific requirements for accuracy, memory efficiency, and distribution needs.
76
77
## Capabilities
78
79
### Rate Limit Items
80
81
Core classes for defining rate limits with different time granularities, supporting custom namespaces and time multipliers for flexible rate limiting configurations.
82
83
```python { .api }
84
class RateLimitItem:
85
def __init__(self, amount: int, multiples: int | None = 1, namespace: str = "LIMITER"): ...
86
def get_expiry(self) -> int: ...
87
def key_for(self, *identifiers: str | int | float | bytes) -> str: ...
88
89
class RateLimitItemPerSecond(RateLimitItem): ...
90
class RateLimitItemPerMinute(RateLimitItem): ...
91
class RateLimitItemPerHour(RateLimitItem): ...
92
class RateLimitItemPerDay(RateLimitItem): ...
93
class RateLimitItemPerMonth(RateLimitItem): ...
94
class RateLimitItemPerYear(RateLimitItem): ...
95
```
96
97
[Rate Limit Items](./rate-limit-items.md)
98
99
### Rate Limiting Strategies
100
101
Different algorithmic approaches for enforcing rate limits, each with distinct characteristics for accuracy, memory usage, and computational efficiency.
102
103
```python { .api }
104
class FixedWindowRateLimiter:
105
def __init__(self, storage: Storage): ...
106
def hit(self, item: RateLimitItem, *identifiers: str, cost: int = 1) -> bool: ...
107
def test(self, item: RateLimitItem, *identifiers: str, cost: int = 1) -> bool: ...
108
def get_window_stats(self, item: RateLimitItem, *identifiers: str) -> WindowStats: ...
109
110
class MovingWindowRateLimiter:
111
def __init__(self, storage: Storage): ...
112
def hit(self, item: RateLimitItem, *identifiers: str, cost: int = 1) -> bool: ...
113
def test(self, item: RateLimitItem, *identifiers: str, cost: int = 1) -> bool: ...
114
def get_window_stats(self, item: RateLimitItem, *identifiers: str) -> WindowStats: ...
115
116
class SlidingWindowCounterRateLimiter:
117
def __init__(self, storage: Storage): ...
118
def hit(self, item: RateLimitItem, *identifiers: str, cost: int = 1) -> bool: ...
119
def test(self, item: RateLimitItem, *identifiers: str, cost: int = 1) -> bool: ...
120
def get_window_stats(self, item: RateLimitItem, *identifiers: str) -> WindowStats: ...
121
```
122
123
[Rate Limiting Strategies](./strategies.md)
124
125
### Storage Backends
126
127
Multiple storage implementations supporting both local and distributed rate limiting with various backends including in-memory, Redis, Memcached, MongoDB, and etcd.
128
129
```python { .api }
130
def storage_from_string(storage_string: str, **options: float | str | bool) -> Storage: ...
131
132
class MemoryStorage(Storage): ...
133
class RedisStorage(Storage): ...
134
class RedisClusterStorage(Storage): ...
135
class RedisSentinelStorage(Storage): ...
136
class MemcachedStorage(Storage): ...
137
class MongoDBStorage(Storage): ...
138
class EtcdStorage(Storage): ...
139
```
140
141
[Storage Backends](./storage.md)
142
143
### Asynchronous Support
144
145
Complete async/await API providing the same functionality as the synchronous API but optimized for asynchronous applications and frameworks.
146
147
```python { .api }
148
# Async strategies mirror sync API but with async methods
149
class FixedWindowRateLimiter:
150
def __init__(self, storage: Storage): ...
151
async def hit(self, item: RateLimitItem, *identifiers: str, cost: int = 1) -> bool: ...
152
async def test(self, item: RateLimitItem, *identifiers: str, cost: int = 1) -> bool: ...
153
async def get_window_stats(self, item: RateLimitItem, *identifiers: str) -> WindowStats: ...
154
155
# Async storage backends with same interface as sync versions
156
class RedisStorage(Storage): ...
157
class MemoryStorage(Storage): ...
158
```
159
160
[Asynchronous API](./async.md)
161
162
### Utilities and Parsing
163
164
Helper functions for parsing rate limit strings, managing window statistics, and handling dependencies for different storage backends.
165
166
```python { .api }
167
def parse(limit_string: str) -> RateLimitItem: ...
168
def parse_many(limit_string: str) -> list[RateLimitItem]: ...
169
170
class WindowStats:
171
reset_time: float
172
remaining: int
173
```
174
175
[Utilities](./utilities.md)
176
177
## Types
178
179
Core type definitions used throughout the library:
180
181
```python { .api }
182
from typing import NamedTuple
183
184
class WindowStats(NamedTuple):
185
"""Statistics for a rate limit window"""
186
reset_time: float # Time when window resets (seconds since epoch)
187
remaining: int # Remaining quota in current window
188
189
class Granularity(NamedTuple):
190
"""Time granularity definition"""
191
seconds: int # Duration in seconds
192
name: str # Granularity name (second, minute, hour, etc.)
193
```
194
195
## Error Handling
196
197
The library defines several exception types for different error scenarios. These must be imported from `limits.errors`:
198
199
```python
200
from limits.errors import ConfigurationError, ConcurrentUpdateError, StorageError
201
```
202
203
```python { .api }
204
class ConfigurationError(Exception):
205
"""Raised when configuration problem is encountered"""
206
207
class ConcurrentUpdateError(Exception):
208
"""Raised when update fails due to concurrent updates"""
209
def __init__(self, key: str, attempts: int):
210
"""
211
Args:
212
key: The key that failed to update
213
attempts: Number of attempts made before giving up
214
"""
215
216
class StorageError(Exception):
217
"""Raised when error is encountered in storage backend"""
218
def __init__(self, storage_error: Exception):
219
"""
220
Args:
221
storage_error: The underlying storage exception that occurred
222
"""
223
storage_error: Exception # The original exception that was wrapped
224
```