Ratelimit Decorator
The `ratelimit` library provides a simple, yet powerful, API rate limiting decorator for Python functions. It allows developers to easily control the frequency at which a function can be called, preventing abuse or excessive resource consumption. Currently at version 2.2.1, it follows a stable release cadence, with updates primarily for bug fixes and compatibility.
Warnings
- breaking Version 2.0 introduced significant breaking changes. The main decorator was renamed from `ratelimit` to `limits`, and its signature changed from positional arguments to keyword arguments (`calls`, `period`). The `enforce` argument was removed.
- gotcha The default in-memory storage for rate limits is not thread-safe or process-safe across multiple Python processes or distributed applications. If you run your application with multiple workers or on different machines, they will not share the same rate limit state.
- gotcha While `ratelimit` works with `asyncio` applications, it is not inherently `async`/`await` native. The decorators are synchronous and will block the event loop if applied directly to `async def` functions, leading to reduced concurrency.
- gotcha The `sleep_and_retry` decorator handles `RateLimitException` for you. If you omit `@sleep_and_retry`, you *must* implement your own `try...except RateLimitException` block, otherwise, your application will crash when the limit is exceeded.
Install
-
pip install ratelimit
Imports
- limits
from ratelimit import limits
- sleep_and_retry
from ratelimit import sleep_and_retry
- RateLimitException
from ratelimit import RateLimitException
Quickstart
import time
from ratelimit import limits, sleep_and_retry, RateLimitException
CALLS = 5
PERIOD = 10 # seconds
@sleep_and_retry
@limits(calls=CALLS, period=PERIOD)
def call_mock_api(url):
"""Simulates an API call that is rate-limited."""
print(f"Calling API for {url} at {time.strftime('%X')}")
# Simulate some work or actual API request
return f"Response from {url}"
if __name__ == "__main__":
print(f"Limiting to {CALLS} calls per {PERIOD} seconds.\n")
urls_to_fetch = [f"http://example.com/data/{i}" for i in range(10)]
for url in urls_to_fetch:
try:
result = call_mock_api(url)
# print(result) # Uncomment to see individual results
except RateLimitException as e:
print(f"Caught RateLimitException for {url}: {e}")
# If sleep_and_retry wasn't used, this catch block would be essential.
# With sleep_and_retry, this block might only be hit if something else fails.
time.sleep(0.1) # Small delay to make output clearer
print("\nFinished all simulated API calls.")