
Security News
ECMAScript 2025 Finalized with Iterator Helpers, Set Methods, RegExp.escape, and More
ECMAScript 2025 introduces Iterator Helpers, Set methods, JSON modules, and more in its latest spec update approved by Ecma in June 2025.
.. |ci| image:: https://github.com/alisaifee/limits/actions/workflows/main.yml/badge.svg?branch=master :target: https://github.com/alisaifee/limits/actions?query=branch%3Amaster+workflow%3ACI .. |codecov| image:: https://codecov.io/gh/alisaifee/limits/branch/master/graph/badge.svg :target: https://codecov.io/gh/alisaifee/limits .. |pypi| image:: https://img.shields.io/pypi/v/limits.svg?style=flat-square :target: https://pypi.python.org/pypi/limits .. |pypi-versions| image:: https://img.shields.io/pypi/pyversions/limits?style=flat-square :target: https://pypi.python.org/pypi/limits .. |license| image:: https://img.shields.io/pypi/l/limits.svg?style=flat-square :target: https://pypi.python.org/pypi/limits .. |docs| image:: https://readthedocs.org/projects/limits/badge/?version=latest :target: https://limits.readthedocs.org
limits
|docs| |ci| |codecov| |pypi| |pypi-versions| |license|
limits is a python library for rate limiting via multiple strategies with commonly used storage backends (Redis, Memcached & MongoDB).
The library provides identical APIs for use in sync and
async <https://limits.readthedocs.io/en/stable/async.html>
_ codebases.
All strategies support the follow methods:
hit <https://limits.readthedocs.io/en/stable/api.html#limits.strategies.RateLimiter.hit>
_: consume a request.test <https://limits.readthedocs.io/en/stable/api.html#limits.strategies.RateLimiter.test>
_: check if a request is allowed.get_window_stats <https://limits.readthedocs.io/en/stable/api.html#limits.strategies.RateLimiter.get_window_stats>
_: retrieve remaining quota and reset time.Fixed Window <https://limits.readthedocs.io/en/latest/strategies.html#fixed-window>
_
This strategy is the most memory‑efficient because it uses a single counter per resource and rate limit. When the first request arrives, a window is started for a fixed duration (e.g., for a rate limit of 10 requests per minute the window expires in 60 seconds from the first request). All requests in that window increment the counter and when the window expires, the counter resets.
Burst traffic that bypasses the rate limit may occur at window boundaries.
For example, with a rate limit of 10 requests per minute:
Moving Window <https://limits.readthedocs.io/en/latest/strategies.html#moving-window>
_
This strategy adds each request’s timestamp to a log if the nth
oldest entry (where n
is the limit) is either not present or is older than the duration of the window (for example with a rate limit of
10 requests per minute
if there are either less than 10 entries or the 10th oldest entry is at least
60 seconds old). Upon adding a new entry to the log "expired" entries are truncated.
For example, with a rate limit of 10 requests per minute:
Sliding Window Counter <https://limits.readthedocs.io/en/latest/strategies.html#sliding-window-counter>
_
This strategy approximates the moving window while using less memory by maintaining two counters:
When a request arrives, the effective request count is calculated as::
weighted_count = current_count + floor(previous_count * weight)
The weight is based on how much time has elapsed in the current bucket::
weight = (bucket_duration - elapsed_time) / bucket_duration
If weighted_count
is below the limit, the request is allowed.
For example, with a rate limit of 10 requests per minute:
Assume:
Scenario 1:
weight = (60 - 30) / 60 = 0.5
.weighted_count = floor(8 + (4 * 0.5)) = floor(8 + 2) = 10
.Scenario 2:
weight = (60 - 40) / 60 ≈ 0.33
.weighted_count = floor(8 + (4 * 0.33)) = floor(8 + 1.32) = 9
.Redis <https://limits.readthedocs.io/en/latest/storage.html#redis-storage>
_Memcached <https://limits.readthedocs.io/en/latest/storage.html#memcached-storage>
_MongoDB <https://limits.readthedocs.io/en/latest/storage.html#mongodb-storage>
_In-Memory <https://limits.readthedocs.io/en/latest/storage.html#in-memory-storage>
_Initialize the storage backend
.. code-block:: python
from limits import storage backend = storage.MemoryStorage()
backend = storage.MemcachedStorage("memcached://localhost:11211")
backend = storage.RedisStorage("redis://localhost:6379")
backend = storage.MongoDbStorage("mongodb://localhost:27017")
storage_uri = "memcached://localhost:11211" backend = storage.storage_from_string(storage_uri)
Initialize a rate limiter with a strategy
.. code-block:: python
from limits import strategies strategy = strategies.MovingWindowRateLimiter(backend)
strategy = strategies.FixedWindowRateLimiter(backend)
strategy = strategies.SlidingWindowCounterRateLimiter(backend)
Initialize a rate limit
.. code-block:: python
from limits import parse
one_per_minute = parse("1/minute")
Initialize a rate limit explicitly
.. code-block:: python
from limits import RateLimitItemPerSecond
one_per_second = RateLimitItemPerSecond(1, 1)
Test the limits
.. code-block:: python
import time
assert True == strategy.hit(one_per_minute, "test_namespace", "foo")
assert False == strategy.hit(one_per_minute, "test_namespace", "foo")
assert True == strategy.hit(one_per_minute, "test_namespace", "bar")
assert True == strategy.hit(one_per_second, "test_namespace", "foo")
assert False == strategy.hit(one_per_second, "test_namespace", "foo")
time.sleep(1)
assert True == strategy.hit(one_per_second, "test_namespace", "foo")
Check specific limits without hitting them
.. code-block:: python
assert True == strategy.hit(one_per_second, "test_namespace", "foo")
while not strategy.test(one_per_second, "test_namespace", "foo"):
time.sleep(0.01)
assert True == strategy.hit(one_per_second, "test_namespace", "foo")
Query available capacity and reset time for a limit
.. code-block:: python
assert True == strategy.hit(one_per_minute, "test_namespace", "foo") window = strategy.get_window_stats(one_per_minute, "test_namespace", "foo") assert window.remaining == 0 assert False == strategy.hit(one_per_minute, "test_namespace", "foo") time.sleep(window.reset_time - time.time()) assert True == strategy.hit(one_per_minute, "test_namespace", "foo")
Documentation <http://limits.readthedocs.org/en/latest>
_Benchmarks <http://limits.readthedocs.org/en/latest/performance.html>
_Changelog <http://limits.readthedocs.org/en/stable/changelog.html>
_FAQs
Rate limiting utilities
We found that limits demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
ECMAScript 2025 introduces Iterator Helpers, Set methods, JSON modules, and more in its latest spec update approved by Ecma in June 2025.
Security News
A new Node.js homepage button linking to paid support for EOL versions has sparked a heated discussion among contributors and the wider community.
Research
North Korean threat actors linked to the Contagious Interview campaign return with 35 new malicious npm packages using a stealthy multi-stage malware loader.