# Credit Rate Limiter
> Easily rate limit async requests to API using credits, computation unit per second (CUPS) or request units, and to those just counting the number of requests per time unit
---
#### Project Information
[![Tests & Lint](https://github.com/Elnaril/credit-rate-limit/actions/workflows/tests.yml/badge.svg)](https://github.com/Elnaril/credit-rate-limit/actions/workflows/tests.yml)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/credit-rate-limit)](https://pypi.org/project/credit-rate-limit/)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/Elnaril/credit-rate-limit)](https://github.com/Elnaril/credit-rate-limit/releases)
[![PyPi Repository](https://img.shields.io/badge/repository-pipy.org-blue)](https://pypi.org/project/credit-rate-limit/)
[![GitHub](https://img.shields.io/github/license/Elnaril/credit-rate-limit)](https://github.com/Elnaril/credit-rate-limit/blob/master/LICENSE)
#### Code Quality
[![CodeQL](https://github.com/elnaril/credit-rate-limit/workflows/CodeQL/badge.svg)](https://github.com/Elnaril/credit-rate-limit/actions/workflows/github-code-scanning/codeql)
[![Test Coverage](https://img.shields.io/badge/dynamic/json?color=blueviolet&label=coverage&query=%24.totals.percent_covered_display&suffix=%25&url=https%3A%2F%2Fraw.githubusercontent.com%2FElnaril%2Fcredit-rate-limit%2Fmaster%2Fcoverage.json)](https://github.com/Elnaril/credit-rate-limit/blob/master/coverage.json)
[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)
[![Type Checker: mypy](https://img.shields.io/badge/%20type%20checker-mypy-%231674b1?style=flat&labelColor=ef8336)](https://mypy-lang.org/)
[![Linter: flake8](https://img.shields.io/badge/%20linter-flake8-%231674b1?style=flat&labelColor=ef8336)](https://flake8.pycqa.org/en/latest/)
---
## Overview
Some APIs enforce a rate limit based on credits (or computation unit per second (CUPS) or request units).
Meaning the call to an endpoint may not weigh as the call to another one.
For example, let's consider a "Compute Unit Costs" sample from an actual crypto related API:
| Method | Compute Units
| ------ | -------------
| eth_chainId | 0
| eth_blockNumber | 10
| eth_getTransactionReceipt | 15
| eth_getBalance | 19
| eth_call | 26
| eth_estimateGas | 87
| eth_sendRawTransaction | 250
It is clear that calling some methods will impact your rate limit more than some others!
This library aims to provide an easy way to limit the rate at which an `async` function or method can be called, considering its own credit cost and the credits already used for a given period.
It also supports rate limitation just based on number of calls.
Finally, you can "group" calls so requesting one API does not impact the rate limit of another one.
It works well for any request pace, but especially well if there are some bursts of fast requests, and it can be optimized for even better performances.
## Installation
```bash
pip install credit-rate-limit
```
## Usage
This library provides 2 "Rate Limiters":
- CreditRateLimiter: for APIs that use credits, computation unit per second (CUPS), request units ...
- CountRateLimiter: for APIs that just counts the number of calls per time unit.
Once the "Rate Limiter" is built, you just have to add the decorator `throughput` to the functions or methods you wish to limit.
### Examples
```python
from credit_rate_limit import CreditRateLimiter, throughput
credit_rate_limiter = CreditRateLimiter(200, 1) # the API allows 200 credits per 1 second
@throughput(credit_rate_limiter, request_credits=40) # this function costs 40 credits to call
async def request_api():
...
```
If you wish to define a "Rate Limiter" as an object attribute, just gives its name as a `str` to the decorator:
```python
from credit_rate_limit import CreditRateLimiter, throughput
class MyClass:
def __init__(self):
self.my_credit_rate_limiter = CreditRateLimiter(200, 1)
# @throughput(self.my_credit_rate_limiter, request_credits=40) /!\ Error: self is unknown here !!
@throughput(attribute_name="my_credit_rate_limiter", request_credits=40)
async def request_api(self):
...
```
`CountRateLimiter` can be used in the same way, albeit without `request_credits`. For example:
```python
from credit_rate_limit import CountRateLimiter, throughput
credit_rate_limiter = CountRateLimiter(5, 1) # the API allows 5 requests per 1 second
@throughput(credit_rate_limiter)
async def request_api():
...
```
### Optimization
Both `CreditRateLimiter` and `CountRateLimiter` have the `adjustment` parameter that can be used to speed up the requests (to some extent)
It can take any value between `0` (default) and `interval`. A higher value means better performances, but also a higher risk of being rate limited by the API.
There is no right value: it depends on the API, the request speeds and the network state and would be discovered with tests.
But if this parameter is correctly set, maybe with a re-try mechanism, it may give a nice performance improvement in some use cases.
```python
rate_limiter = CreditRateLimiter(max_credits=2000, interval=1, adjustment=0.1)
```
Raw data
{
"_id": null,
"home_page": null,
"name": "credit-rate-limit",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "rate limit, rate limiter, rate-limit, rate-limiter, ratelimit, ratelimiter, throttler, API, decorator, asynchronous, async",
"author": null,
"author_email": "Elnaril <elnaril_dev@caramail.com>",
"download_url": "https://files.pythonhosted.org/packages/20/12/6918c98ba203647b50252a70b1164fd2993e3242329218bac95fb145d355/credit_rate_limit-0.2.0.tar.gz",
"platform": null,
"description": "# Credit Rate Limiter\n\n> Easily rate limit async requests to API using credits, computation unit per second (CUPS) or request units, and to those just counting the number of requests per time unit\n \n---\n\n#### Project Information\n[![Tests & Lint](https://github.com/Elnaril/credit-rate-limit/actions/workflows/tests.yml/badge.svg)](https://github.com/Elnaril/credit-rate-limit/actions/workflows/tests.yml)\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/credit-rate-limit)](https://pypi.org/project/credit-rate-limit/)\n[![GitHub release (latest by date)](https://img.shields.io/github/v/release/Elnaril/credit-rate-limit)](https://github.com/Elnaril/credit-rate-limit/releases)\n[![PyPi Repository](https://img.shields.io/badge/repository-pipy.org-blue)](https://pypi.org/project/credit-rate-limit/)\n[![GitHub](https://img.shields.io/github/license/Elnaril/credit-rate-limit)](https://github.com/Elnaril/credit-rate-limit/blob/master/LICENSE)\n\n#### Code Quality\n[![CodeQL](https://github.com/elnaril/credit-rate-limit/workflows/CodeQL/badge.svg)](https://github.com/Elnaril/credit-rate-limit/actions/workflows/github-code-scanning/codeql)\n[![Test Coverage](https://img.shields.io/badge/dynamic/json?color=blueviolet&label=coverage&query=%24.totals.percent_covered_display&suffix=%25&url=https%3A%2F%2Fraw.githubusercontent.com%2FElnaril%2Fcredit-rate-limit%2Fmaster%2Fcoverage.json)](https://github.com/Elnaril/credit-rate-limit/blob/master/coverage.json)\n[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)\n[![Type Checker: mypy](https://img.shields.io/badge/%20type%20checker-mypy-%231674b1?style=flat&labelColor=ef8336)](https://mypy-lang.org/)\n[![Linter: flake8](https://img.shields.io/badge/%20linter-flake8-%231674b1?style=flat&labelColor=ef8336)](https://flake8.pycqa.org/en/latest/)\n\n---\n\n## Overview\n\nSome APIs enforce a rate limit based on credits (or computation unit per second (CUPS) or request units).\nMeaning the call to an endpoint may not weigh as the call to another one.\nFor example, let's consider a \"Compute Unit Costs\" sample from an actual crypto related API:\n\n| Method | Compute Units\n| ------ | -------------\n| eth_chainId | 0\n| eth_blockNumber | 10\n| eth_getTransactionReceipt | 15\n| eth_getBalance | 19\n| eth_call | 26\n| eth_estimateGas | 87\n| eth_sendRawTransaction | 250\n\nIt is clear that calling some methods will impact your rate limit more than some others!\n\nThis library aims to provide an easy way to limit the rate at which an `async` function or method can be called, considering its own credit cost and the credits already used for a given period.\nIt also supports rate limitation just based on number of calls.\nFinally, you can \"group\" calls so requesting one API does not impact the rate limit of another one.\n\nIt works well for any request pace, but especially well if there are some bursts of fast requests, and it can be optimized for even better performances.\n\n## Installation\n\n```bash\npip install credit-rate-limit\n```\n\n## Usage\nThis library provides 2 \"Rate Limiters\":\n- CreditRateLimiter: for APIs that use credits, computation unit per second (CUPS), request units ...\n- CountRateLimiter: for APIs that just counts the number of calls per time unit.\n\nOnce the \"Rate Limiter\" is built, you just have to add the decorator `throughput` to the functions or methods you wish to limit.\n\n### Examples\n\n```python\nfrom credit_rate_limit import CreditRateLimiter, throughput\n\ncredit_rate_limiter = CreditRateLimiter(200, 1) # the API allows 200 credits per 1 second\n\n@throughput(credit_rate_limiter, request_credits=40) # this function costs 40 credits to call\nasync def request_api():\n ...\n\n```\n\nIf you wish to define a \"Rate Limiter\" as an object attribute, just gives its name as a `str` to the decorator:\n\n```python\nfrom credit_rate_limit import CreditRateLimiter, throughput\n\nclass MyClass:\n def __init__(self):\n self.my_credit_rate_limiter = CreditRateLimiter(200, 1)\n\n # @throughput(self.my_credit_rate_limiter, request_credits=40) /!\\ Error: self is unknown here !!\n @throughput(attribute_name=\"my_credit_rate_limiter\", request_credits=40)\n async def request_api(self):\n ...\n```\n\n`CountRateLimiter` can be used in the same way, albeit without `request_credits`. For example:\n\n```python\nfrom credit_rate_limit import CountRateLimiter, throughput\n\ncredit_rate_limiter = CountRateLimiter(5, 1) # the API allows 5 requests per 1 second\n\n\n@throughput(credit_rate_limiter)\nasync def request_api():\n ...\n\n```\n\n### Optimization\nBoth `CreditRateLimiter` and `CountRateLimiter` have the `adjustment` parameter that can be used to speed up the requests (to some extent) \nIt can take any value between `0` (default) and `interval`. A higher value means better performances, but also a higher risk of being rate limited by the API. \nThere is no right value: it depends on the API, the request speeds and the network state and would be discovered with tests. \nBut if this parameter is correctly set, maybe with a re-try mechanism, it may give a nice performance improvement in some use cases.\n\n```python\nrate_limiter = CreditRateLimiter(max_credits=2000, interval=1, adjustment=0.1)\n```\n",
"bugtrack_url": null,
"license": "MIT License",
"summary": "Easily rate limit async requests to API using credits, computation unit per second (CUPS) or request units, and to those just counting the number of requests per time unit",
"version": "0.2.0",
"project_urls": {
"Bug Tracker": "https://github.com/Elnaril/credit-rate-limit/issues",
"Buy Me A Coffee": "https://www.buymeacoffee.com/elnaril",
"Fiverr": "https://www.fiverr.com/freelancers/elnaril",
"Homepage": "https://github.com/Elnaril/credit-rate-limit",
"Malt": "https://www.malt.com/profile/elnaril"
},
"split_keywords": [
"rate limit",
" rate limiter",
" rate-limit",
" rate-limiter",
" ratelimit",
" ratelimiter",
" throttler",
" api",
" decorator",
" asynchronous",
" async"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "60d050f8c45b560583ddb92daab94fdf256ee23156ef4f822e191909c424da95",
"md5": "dac153b39f31f64efd9f0cc23f55fa11",
"sha256": "f0bd5d27f90bc3d41cb7a4eb5341a8fced33e09c38f71e1ffde2dc16c24a3488"
},
"downloads": -1,
"filename": "credit_rate_limit-0.2.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "dac153b39f31f64efd9f0cc23f55fa11",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 6614,
"upload_time": "2024-10-21T08:50:30",
"upload_time_iso_8601": "2024-10-21T08:50:30.736464Z",
"url": "https://files.pythonhosted.org/packages/60/d0/50f8c45b560583ddb92daab94fdf256ee23156ef4f822e191909c424da95/credit_rate_limit-0.2.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "20126918c98ba203647b50252a70b1164fd2993e3242329218bac95fb145d355",
"md5": "3ab67c0014a279d20822a915592463d5",
"sha256": "85c3363f0439a5a3f183ce64ae38eb12326c7f42ec641ebabd27b91ecf907abd"
},
"downloads": -1,
"filename": "credit_rate_limit-0.2.0.tar.gz",
"has_sig": false,
"md5_digest": "3ab67c0014a279d20822a915592463d5",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 7008,
"upload_time": "2024-10-21T08:50:31",
"upload_time_iso_8601": "2024-10-21T08:50:31.746276Z",
"url": "https://files.pythonhosted.org/packages/20/12/6918c98ba203647b50252a70b1164fd2993e3242329218bac95fb145d355/credit_rate_limit-0.2.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-21 08:50:31",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Elnaril",
"github_project": "credit-rate-limit",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"tox": true,
"lcname": "credit-rate-limit"
}