{"id":1692,"library":"ratelimit","title":"Ratelimit Decorator","description":"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.","status":"active","version":"2.2.1","language":"en","source_language":"en","source_url":"https://github.com/tomasbasham/ratelimit","tags":["rate-limiting","decorator","concurrency","api-tools","timing","throttling"],"install":[{"cmd":"pip install ratelimit","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"note":"The primary decorator was renamed from `ratelimit` to `limits` in version 2.0.","wrong":"from ratelimit import ratelimit","symbol":"limits","correct":"from ratelimit import limits"},{"symbol":"sleep_and_retry","correct":"from ratelimit import sleep_and_retry"},{"symbol":"RateLimitException","correct":"from ratelimit import RateLimitException"}],"quickstart":{"code":"import time\nfrom ratelimit import limits, sleep_and_retry, RateLimitException\n\nCALLS = 5\nPERIOD = 10 # seconds\n\n@sleep_and_retry\n@limits(calls=CALLS, period=PERIOD)\ndef call_mock_api(url):\n    \"\"\"Simulates an API call that is rate-limited.\"\"\"\n    print(f\"Calling API for {url} at {time.strftime('%X')}\")\n    # Simulate some work or actual API request\n    return f\"Response from {url}\"\n\nif __name__ == \"__main__\":\n    print(f\"Limiting to {CALLS} calls per {PERIOD} seconds.\\n\")\n    urls_to_fetch = [f\"http://example.com/data/{i}\" for i in range(10)]\n    \n    for url in urls_to_fetch:\n        try:\n            result = call_mock_api(url)\n            # print(result) # Uncomment to see individual results\n        except RateLimitException as e:\n            print(f\"Caught RateLimitException for {url}: {e}\")\n            # If sleep_and_retry wasn't used, this catch block would be essential.\n            # With sleep_and_retry, this block might only be hit if something else fails.\n        time.sleep(0.1) # Small delay to make output clearer\n    print(\"\\nFinished all simulated API calls.\")","lang":"python","description":"This example demonstrates how to apply a rate limit to a function using the `limits` decorator. The `sleep_and_retry` decorator automatically pauses execution until the rate limit period resets, preventing `RateLimitException` from being raised directly. If `sleep_and_retry` is omitted, you must manually catch `RateLimitException`."},"warnings":[{"fix":"Update decorator usage from `@ratelimit(N, S)` to `@limits(calls=N, period=S)`. Ensure `RateLimitException` is imported directly if catching.","message":"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.","severity":"breaking","affected_versions":"1.x to 2.x"},{"fix":"For distributed or multi-process environments, implement a custom storage backend (e.g., using Redis) by subclassing `ratelimit.BaseProxy` and passing an instance to the `limits` decorator's `rate_limiter` argument.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"For `async def` functions, wrap the rate-limited synchronous function call in `loop.run_in_executor()` or use an `async` native rate-limiting library. If the actual I/O within your `async` function is blocked by the synchronous decorator, consider refactoring.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Either always use `@sleep_and_retry` for automatic handling or explicitly wrap calls to rate-limited functions in `try...except RateLimitException` blocks to manage the error gracefully.","message":"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.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-09T00:00:00.000Z","next_check":"2026-07-08T00:00:00.000Z"}