Quart-Rate-Limiter
==================
|Build Status| |pypi| |python| |license|
Quart-Rate-Limiter is an extension for `Quart
<https://github.com/pgjones/quart>`_ to allow for rate limits to be
defined and enforced on a per route basis. The 429 error response
includes a `RFC7231
<https://tools.ietf.org/html/rfc7231#section-7.1.3>`_ compliant
``Retry-After`` header and the successful responses contain headers
compliant with the `RateLimit Header Fields for HTTP
<https://tools.ietf.org/html/draft-polli-ratelimit-headers-00>`_ RFC
draft.
Usage
-----
To add a rate limit first initialise the RateLimiting extension with
the application,
.. code-block:: python
app = Quart(__name__)
rate_limiter = RateLimiter(app)
or via the factory pattern,
.. code-block:: python
rate_limiter = RateLimiter()
def create_app():
app = Quart(__name__)
rate_limiter.init_app(app)
return app
Now this is done you can apply rate limits to any route by using the
``rate_limit`` decorator,
.. code-block:: python
@app.route('/')
@rate_limit(1, timedelta(seconds=10))
async def handler():
...
Or to apply rate limits to all routes within a blueprint by using the
``limit_blueprint`` function,
.. code-block:: python
blueprint = Blueprint("name", __name__)
limit_blueprint(blueprint, 1, timedelta(seconds=10))
Or to apply rate limits to all routes in an app, define the default
limits when initialising the RateLimiter,
.. code-block:: python
rate_limiter = RateLimiter(
default_limits=[RateLimit(1, timedelta(seconds=10))]
)
and then to exempt a route,
.. code-block:: python
@app.route("/exempt")
@rate_exempt
async def handler():
...
To alter the identification of remote users you can either supply a
global key function when initialising the extension, or on a per route
basis.
By default rate limiting information (TATs) will be stored in memory,
which will result in unexpected behaviour if multiple workers are
used. To solve this a redis store can be used by installing the
``redis`` extra (``pip install quart-rate-limiter[redis]``) and then
using as so,
.. code-block:: python
from quart_rate_limiter.redis_store import RedisStore
redis_store = RedisStore(address)
RateLimiter(app, store=redis_store)
This store uses `redis <https://github.com/redis/redis-py>`_,
and any extra keyword arguments passed to the ``RedisStore``
constructor will be passed to the redis ``create_redis`` function.
A custom store is possible, see the ``RateLimiterStoreABC`` for the
required interface.
Simple examples
~~~~~~~~~~~~~~~
To limit a route to 1 request per second and a maximum of 20 per minute,
.. code-block:: python
@app.route('/')
@rate_limit(1, timedelta(seconds=1))
@rate_limit(20, timedelta(minutes=1))
async def handler():
...
Alternatively the ``limits`` argument can be used for multiple limits,
.. code-block:: python
@app.route('/')
@rate_limit(
limits=[
RateLimit(1, timedelta(seconds=1)),
RateLimit(20, timedelta(minutes=1)),
],
)
async def handler():
...
To identify remote users based on their authentication ID, rather than
their IP,
.. code-block:: python
async def key_function():
return current_user.id
RateLimiter(app, key_function=key_function)
The ``key_function`` is a coroutine function to allow session lookups
if appropriate.
Contributing
------------
Quart-Rate-Limiter is developed on `GitHub
<https://github.com/pgjones/quart-rate-limiter>`_. You are very welcome to
open `issues <https://github.com/pgjones/quart-rate-limiter/issues>`_ or
propose `merge requests
<https://github.com/pgjones/quart-rate-limiter/merge_requests>`_.
Testing
~~~~~~~
The best way to test Quart-Rate-Limiter is with Tox,
.. code-block:: console
$ pip install tox
$ tox
this will check the code style and run the tests.
Help
----
This README is the best place to start, after that try opening an
`issue <https://github.com/pgjones/quart-rate-limiter/issues>`_.
.. |Build Status| image:: https://github.com/pgjones/quart-rate-limiter/actions/workflows/ci.yml/badge.svg
:target: https://github.com/pgjones/quart-rate-limiter/commits/main
.. |pypi| image:: https://img.shields.io/pypi/v/quart-rate-limiter.svg
:target: https://pypi.python.org/pypi/Quart-Rate-Limiter/
.. |python| image:: https://img.shields.io/pypi/pyversions/quart-rate-limiter.svg
:target: https://pypi.python.org/pypi/Quart-Rate-Limiter/
.. |license| image:: https://img.shields.io/badge/license-MIT-blue.svg
:target: https://github.com/pgjones/quart-rate-limiter/blob/main/LICENSE
Raw data
{
"_id": null,
"home_page": "https://github.com/pgjones/quart-rate-limiter/",
"name": "quart-rate-limiter",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": "",
"keywords": "",
"author": "pgjones",
"author_email": "philip.graham.jones@googlemail.com",
"download_url": "https://files.pythonhosted.org/packages/80/60/ecdd6313dddd4d3ed117fde35a5fc236caa285fae57c5e11d7373ca1bdfa/quart_rate_limiter-0.9.0.tar.gz",
"platform": null,
"description": "Quart-Rate-Limiter\n==================\n\n|Build Status| |pypi| |python| |license|\n\nQuart-Rate-Limiter is an extension for `Quart\n<https://github.com/pgjones/quart>`_ to allow for rate limits to be\ndefined and enforced on a per route basis. The 429 error response\nincludes a `RFC7231\n<https://tools.ietf.org/html/rfc7231#section-7.1.3>`_ compliant\n``Retry-After`` header and the successful responses contain headers\ncompliant with the `RateLimit Header Fields for HTTP\n<https://tools.ietf.org/html/draft-polli-ratelimit-headers-00>`_ RFC\ndraft.\n\nUsage\n-----\n\nTo add a rate limit first initialise the RateLimiting extension with\nthe application,\n\n.. code-block:: python\n\n app = Quart(__name__)\n rate_limiter = RateLimiter(app)\n\nor via the factory pattern,\n\n.. code-block:: python\n\n rate_limiter = RateLimiter()\n\n def create_app():\n app = Quart(__name__)\n rate_limiter.init_app(app)\n return app\n\nNow this is done you can apply rate limits to any route by using the\n``rate_limit`` decorator,\n\n.. code-block:: python\n\n @app.route('/')\n @rate_limit(1, timedelta(seconds=10))\n async def handler():\n ...\n\nOr to apply rate limits to all routes within a blueprint by using the\n``limit_blueprint`` function,\n\n.. code-block:: python\n\n blueprint = Blueprint(\"name\", __name__)\n limit_blueprint(blueprint, 1, timedelta(seconds=10))\n\nOr to apply rate limits to all routes in an app, define the default\nlimits when initialising the RateLimiter,\n\n.. code-block:: python\n\n rate_limiter = RateLimiter(\n default_limits=[RateLimit(1, timedelta(seconds=10))]\n )\n\nand then to exempt a route,\n\n.. code-block:: python\n\n @app.route(\"/exempt\")\n @rate_exempt\n async def handler():\n ...\n\n\nTo alter the identification of remote users you can either supply a\nglobal key function when initialising the extension, or on a per route\nbasis.\n\nBy default rate limiting information (TATs) will be stored in memory,\nwhich will result in unexpected behaviour if multiple workers are\nused. To solve this a redis store can be used by installing the\n``redis`` extra (``pip install quart-rate-limiter[redis]``) and then\nusing as so,\n\n.. code-block:: python\n\n from quart_rate_limiter.redis_store import RedisStore\n\n redis_store = RedisStore(address)\n RateLimiter(app, store=redis_store)\n\nThis store uses `redis <https://github.com/redis/redis-py>`_,\nand any extra keyword arguments passed to the ``RedisStore``\nconstructor will be passed to the redis ``create_redis`` function.\n\nA custom store is possible, see the ``RateLimiterStoreABC`` for the\nrequired interface.\n\nSimple examples\n~~~~~~~~~~~~~~~\n\nTo limit a route to 1 request per second and a maximum of 20 per minute,\n\n.. code-block:: python\n\n @app.route('/')\n @rate_limit(1, timedelta(seconds=1))\n @rate_limit(20, timedelta(minutes=1))\n async def handler():\n ...\n\nAlternatively the ``limits`` argument can be used for multiple limits,\n\n.. code-block:: python\n\n @app.route('/')\n @rate_limit(\n limits=[\n RateLimit(1, timedelta(seconds=1)),\n RateLimit(20, timedelta(minutes=1)),\n ],\n )\n async def handler():\n ...\n\nTo identify remote users based on their authentication ID, rather than\ntheir IP,\n\n.. code-block:: python\n\n async def key_function():\n return current_user.id\n\n RateLimiter(app, key_function=key_function)\n\nThe ``key_function`` is a coroutine function to allow session lookups\nif appropriate.\n\nContributing\n------------\n\nQuart-Rate-Limiter is developed on `GitHub\n<https://github.com/pgjones/quart-rate-limiter>`_. You are very welcome to\nopen `issues <https://github.com/pgjones/quart-rate-limiter/issues>`_ or\npropose `merge requests\n<https://github.com/pgjones/quart-rate-limiter/merge_requests>`_.\n\nTesting\n~~~~~~~\n\nThe best way to test Quart-Rate-Limiter is with Tox,\n\n.. code-block:: console\n\n $ pip install tox\n $ tox\n\nthis will check the code style and run the tests.\n\nHelp\n----\n\nThis README is the best place to start, after that try opening an\n`issue <https://github.com/pgjones/quart-rate-limiter/issues>`_.\n\n\n.. |Build Status| image:: https://github.com/pgjones/quart-rate-limiter/actions/workflows/ci.yml/badge.svg\n :target: https://github.com/pgjones/quart-rate-limiter/commits/main\n\n.. |pypi| image:: https://img.shields.io/pypi/v/quart-rate-limiter.svg\n :target: https://pypi.python.org/pypi/Quart-Rate-Limiter/\n\n.. |python| image:: https://img.shields.io/pypi/pyversions/quart-rate-limiter.svg\n :target: https://pypi.python.org/pypi/Quart-Rate-Limiter/\n\n.. |license| image:: https://img.shields.io/badge/license-MIT-blue.svg\n :target: https://github.com/pgjones/quart-rate-limiter/blob/main/LICENSE\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A Quart extension to provide rate limiting support",
"version": "0.9.0",
"project_urls": {
"Homepage": "https://github.com/pgjones/quart-rate-limiter/",
"Repository": "https://github.com/pgjones/quart-rate-limiter/"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "12fbd70128e3cd131e6d43481b5924988ef75f86df9a129970c39174c664f6dc",
"md5": "2464dd3af1640979af24483cea88a95c",
"sha256": "ad5a0230223344bda92a859d1b4e173047f7f529036ae6fe7836a1a737a3daed"
},
"downloads": -1,
"filename": "quart_rate_limiter-0.9.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "2464dd3af1640979af24483cea88a95c",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 8209,
"upload_time": "2023-10-07T16:57:25",
"upload_time_iso_8601": "2023-10-07T16:57:25.952889Z",
"url": "https://files.pythonhosted.org/packages/12/fb/d70128e3cd131e6d43481b5924988ef75f86df9a129970c39174c664f6dc/quart_rate_limiter-0.9.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "8060ecdd6313dddd4d3ed117fde35a5fc236caa285fae57c5e11d7373ca1bdfa",
"md5": "4efcc58cdbdd684006fb0de6304dadcb",
"sha256": "2479c5f5bbdfb710850e97dc040280a29e0dfcdaad00617ae8e3cf0cb4b4af29"
},
"downloads": -1,
"filename": "quart_rate_limiter-0.9.0.tar.gz",
"has_sig": false,
"md5_digest": "4efcc58cdbdd684006fb0de6304dadcb",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 8497,
"upload_time": "2023-10-07T16:57:27",
"upload_time_iso_8601": "2023-10-07T16:57:27.172200Z",
"url": "https://files.pythonhosted.org/packages/80/60/ecdd6313dddd4d3ed117fde35a5fc236caa285fae57c5e11d7373ca1bdfa/quart_rate_limiter-0.9.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-10-07 16:57:27",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "pgjones",
"github_project": "quart-rate-limiter",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"tox": true,
"lcname": "quart-rate-limiter"
}