# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['requests_ratelimiter']

package_data = \
{'': ['*']}

install_requires = \
['pyrate-limiter>=2.8', 'requests>=2.20']

extras_require = \
{'docs': ['furo==2022.9.15',
          'myst-parser>=0.17',
          'sphinx>=4.3.0,<5.0.0',
          'sphinx-autodoc-typehints>=1.17,<2.0',
          'sphinx-copybutton>=0.5']}

setup_kwargs = {
    'name': 'requests-ratelimiter',
    'version': '0.4.0',
    'description': 'Rate-limiting for the requests library',
    'long_description': '# Requests-Ratelimiter\n[![Build\nstatus](https://github.com/JWCook/requests-ratelimiter/workflows/Build/badge.svg)](https://github.com/JWCook/requests-ratelimiter/actions)\n[![Codecov](https://codecov.io/gh/JWCook/requests-ratelimiter/branch/main/graph/badge.svg)](https://codecov.io/gh/JWCook/requests-ratelimiter)\n[![Documentation Status](https://img.shields.io/readthedocs/requests-ratelimiter/stable?label=docs)](https://requests-ratelimiter.readthedocs.io)\n[![PyPI](https://img.shields.io/pypi/v/requests-ratelimiter?color=blue)](https://pypi.org/project/requests-ratelimiter)\n[![Conda](https://img.shields.io/conda/vn/conda-forge/requests-ratelimiter?color=blue)](https://anaconda.org/conda-forge/requests-ratelimiter)\n[![PyPI - Python Versions](https://img.shields.io/pypi/pyversions/requests-ratelimiter)](https://pypi.org/project/requests-ratelimiter)\n[![PyPI - Format](https://img.shields.io/pypi/format/requests-ratelimiter?color=blue)](https://pypi.org/project/requests-ratelimiter)\n\nThis package is a simple wrapper around [pyrate-limiter](https://pyratelimiter.readthedocs.io)\nthat adds convenient integration with the [requests](https://requests.readthedocs.io) library.\n\nFull project documentation can be found at [requests-ratelimiter.readthedocs.io](https://requests-ratelimiter.readthedocs.io).\n\n\n# Features\n* `pyrate-limiter` is a general-purpose rate limiting library that implements the leaky bucket\n  algorithm, supports multiple rate limits, and has optional persistence with SQLite and Redis\n  backends\n* `requests-ratelimiter` adds some extra conveniences specific to sending HTTP requests with the\n  `requests` library\n* It can be used as either a\n  [session](https://requests.readthedocs.io/en/latest/user/advanced/#session-objects) or a\n  [transport adapter](https://requests.readthedocs.io/en/latest/user/advanced/#transport-adapters)\n* It can also be used as a mixin, for compatibility with other `requests`-based libraries\n* Rate limits are tracked separately per host\n* Different rate limits can optionally be applied to different hosts\n\n# Installation\n```\npip install requests-ratelimiter\n```\n\n# Usage\n\n## Usage Options\nThere are three ways to use `requests-ratelimiter`:\n\n### Session\nThe simplest option is\n[`LimiterSession`](https://requests-ratelimiter.readthedocs.io/en/stable/reference.html#requests_ratelimiter.LimiterSession),\nwhich can be used as a drop-in replacement for\n[`requests.Session`](https://requests.readthedocs.io/en/latest/api/#requests.Session).\n\nExample:\n```python\nfrom requests_ratelimiter import LimiterSession\nfrom time import time\n\n# Apply a rate limit of 5 requests per second to all requests\nsession = LimiterSession(per_second=5)\nstart = time()\n\n# Send requests that stay within the defined rate limit\nfor i in range(20):\n    response = session.get(\'https://httpbin.org/get\')\n    print(f\'[t+{time()-start:.2f}] Sent request {i+1}\')\n```\n\nExample output:\n```bash\n[t+0.22] Sent request 1\n[t+0.26] Sent request 2\n[t+0.30] Sent request 3\n[t+0.34] Sent request 4\n[t+0.39] Sent request 5\n[t+1.24] Sent request 6\n[t+1.28] Sent request 7\n[t+1.32] Sent request 8\n[t+1.37] Sent request 9\n[t+1.41] Sent request 10\n[t+2.04] Sent request 11\n...\n```\n\n### Adapter\nFor more advanced usage,\n[`LimiterAdapter`](https://requests-ratelimiter.readthedocs.io/en/stable/reference.html#requests_ratelimiter.LimiterAdapter)\nis available to be used as a\n[transport adapter](https://requests.readthedocs.io/en/latest/user/advanced/#transport-adapters).\n\nExample:\n```python\nfrom requests import Session\nfrom requests_ratelimiter import LimiterAdapter\n\nsession = Session()\n\n# Apply a rate-limit (5 requests per second) to all requests\nadapter = LimiterAdapter(per_second=5)\nsession.mount(\'http://\', adapter)\nsession.mount(\'https://\', adapter)\n\n# Send rate-limited requests\nfor user_id in range(100):\n    response = session.get(f\'https://api.some_site.com/v1/users/{user_id}\')\n    print(response.json())\n```\n\n### Mixin\nFinally,\n[`LimiterMixin`](https://requests-ratelimiter.readthedocs.io/en/stable/reference.html#requests_ratelimiter.LimiterMixin)\nis available for advanced use cases in which you want add rate-limiting features to a custom session\nor adapter class. See\n[Custom Session Example](#custom-session-example-requests-cache) below for an example.\n\n## Rate Limit Settings\n### Basic Settings\nThe following parameters are available for the most common rate limit intervals:\n* `per_second`: Max requests per second\n* `per_minute`: Max requests per minute\n* `per_hour`: Max requests per hour\n* `per_day`: Max requests per day\n* `per_month`: Max requests per month\n* `burst`: Max number of consecutive requests allowed before applying per-second rate-limiting\n\n<!-- TODO: Section explaining burst rate limit -->\n\n### Advanced Settings\nIf you need to define more complex rate limits, you can create a `Limiter` object instead:\n```python\nfrom pyrate_limiter import Duration, RequestRate, Limiter\nfrom requests_ratelimiter LimiterSession\n\nnanocentury_rate = RequestRate(10, Duration.SECOND * 3.156)\nfortnight_rate = RequestRate(1000, Duration.DAY * 14)\ntrimonthly_rate = RequestRate(10000, Duration.MONTH * 3)\nlimiter = Limiter(nanocentury_rate, fortnight_rate, trimonthly_rate)\n\nsession = LimiterSession(limiter=limiter)\n```\n\nSee [pyrate-limiter docs](https://pyratelimiter.readthedocs.io/en/latest/#basic-usage) for more `Limiter` usage details.\n\n## Backends\nBy default, rate limits are tracked in memory and are not persistent. You can optionally use either\nSQLite or Redis to persist rate limits across threads, processes, and/or application restarts.\nYou can specify which backend to use with the `bucket_class` argument. For example, to use SQLite:\n```python\nfrom pyrate_limiter import SQLiteBucket\nfrom requests_ratelimiter import LimiterSession\n\nsession = LimiterSession(per_second=5, bucket_class=SQLiteBucket)\n```\n\nSee [pyrate-limiter docs](https://pyratelimiter.readthedocs.io/en/latest/#backends) for more details.\n\n## Other Features\n### Per-Host Rate Limit Tracking\nWith either `LimiterSession` or `LimiterAdapter`, rate limits are tracked separately for each host.\nIn other words, requests sent to one host will not count against the rate limit for any other hosts:\n\n```python\nsession = LimiterSession(per_second=5)\n\n# Make requests for two different hosts\nfor _ in range(10):\n    response = session.get(f\'https://httpbin.org/get\')\n    print(response.json())\n    session.get(f\'https://httpbingo.org/get\')\n    print(response.json())\n```\n\nIf you have a case where multiple hosts share the same rate limit, you can disable this behavior\nwith the `per_host` option:\n```python\nsession = LimiterSession(per_second=5, per_host=False)\n```\n\n### Per-Host Rate Limit Definitions\nWith `LimiterAdapter`, you can apply different rate limits to different hosts or URLs:\n```python\n# Apply a different set of rate limits (2/second and 100/minute) to a specific host\nadapter_2 = LimiterAdapter(per_second=2, per_minute=100)\nsession.mount(\'https://api.some_site.com\', adapter_2)\n```\n\nBehavior for matching requests is the same as other transport adapters: `requests` will use the\nadapter with the most specific (i.e., longest) URL prefix that matches a given request. For example:\n```python\nsession.mount(\'https://api.some_site.com/v1\', adapter_3)\nsession.mount(\'https://api.some_site.com/v1/users\', adapter_4)\n\n# This request will use adapter_3\nsession.get(\'https://api.some_site.com/v1/\')\n\n# This request will use adapter_4\nsession.get(\'https://api.some_site.com/v1/users/1234\')\n```\n\n### Rate Limit Error Handling\nSometimes, server-side rate limiting may not behave exactly as documented (or may not be documented\nat all). Or you might encounter other scenarios where your client-side limit gets out of sync with\nthe server-side limit. Typically, a server will send a `429: Too Many Requests` response for an\nexceeded rate limit.\n\nWhen this happens, `requests-ratelimiter` will adjust its request log in an attempt to catch up to\nthe server-side limit. If a server sends a different status code other than 429 to indicate an\nexceeded limit, you can set this with `limit_statuses`:\n```python\nsession = LimiterSession(per_second=5, limit_statuses=[429, 500])\n```\n\nOr if you would prefer to disable this behavior and handle it yourself:\n```python\nsession = LimiterSession(per_second=5, limit_statuses=[])\n```\n\n# Compatibility\nThere are many other useful libraries out there that add features to `requests`, most commonly by\nextending or modifying\n[requests.Session](https://requests.readthedocs.io/en/latest/api/#requests.Session) or\n[requests.HTTPAdapter](https://requests.readthedocs.io/en/latest/api/#requests.adapters.HTTPAdapter).\n\nTo use `requests-ratelimiter` with one of these libraries, you have a few different options:\n1. If the library provides a custom `Session` class, mount a `LimiterAdapter` on it\n2. Or use `LimiterMixin` to create a custom `Session` class with features from both libraries\n3. If the library provides a custom `Adapter` class, use `LimiterMixin` to create a custom `Adapter`\n   class with features from both libraries\n\n## Custom Session Example: Requests-Cache\nFor example, to combine with [requests-cache](https://github.com/requests-cache/requests-cache), which\nalso includes a separate mixin class:\n```python\nfrom requests import Session\nfrom requests_cache import CacheMixin, RedisCache\nfrom requests_ratelimiter import LimiterMixin, RedisBucket\n\n\nclass CachedLimiterSession(CacheMixin, LimiterMixin, Session):\n    """Session class with caching and rate-limiting behavior. Accepts arguments for both\n    LimiterSession and CachedSession.\n    """\n\n\n# Optionally use Redis as both the bucket backend and the cache backend\nsession = CachedLimiterSession(\n    per_second=5,\n    bucket_class=RedisBucket,\n    backend=RedisCache(),\n)\n```\n\nThis example has an extra benefit: cache hits won\'t count against your rate limit!\n',
    'author': 'Jordan Cook',
    'author_email': 'None',
    'maintainer': 'None',
    'maintainer_email': 'None',
    'url': 'https://github.com/JWCook/requests-ratelimiter',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'extras_require': extras_require,
    'python_requires': '>=3.7,<4.0',
}


setup(**setup_kwargs)
