Another Python package aim to offer "Rate Limiting" functionality for general use cases.
Project description
PYGRL - Python General Rate Limiter
Another Python package aim to offer "Rate Limiting" functionality for general use cases.
Features
- Flexible storage strategy (Memory | File | Database)
- MemoryStorage
BasicStorage
- FileStorage
SQLite3_Storage
- MemoryStorage
- Cleanup expired rate limiters
- Use as a decorator
- Use as a variable
- Compatible with fastapi (TO BE TESTED)
- Support asynchronous DB operations (TODO)
Dependencies
- Python 3.10
Installation
pip3 install pygrl
Example - BasicStorage
Imports
from pygrl import BasicStorage, GeneralRateLimiter as grl, ExceededRateLimitError
Check limit with BasicStorage
storage = BasicStorage()
rate_limiter = grl(storage, 10, 1)
try:
for i in range(12):
allowed_to_pass = rate_limiter.check_limit("client-key")
if allowed_to_pass:
print(f"Request {i + 1}: Allowed")
else:
print(f"Request {i + 1}: Exceeded rate limit")
except Exception as e:
print(f"Rate limit exceeded: {e}")
Apply rate limiter decorator with BasicStorage
@grl.general_rate_limiter(storage=BasicStorage(), max_requests=10, time_window=1)
def fn(a, b):
return a + b
try:
for i in range(12):
result = fn(i, i + 1)
print(f"Result {i + 1}: {result}")
except ExceededRateLimitError as e:
print(f"Rate limit exceeded: {e}")
Apply rate limiter decorator with BasicStorage (Keyed function)
import random
@grl.general_rate_limiter(storage=BasicStorage(), max_requests=2, time_window=1)
def connect(key: str, host: str, port: int):
return f"{key} connected to {host}:{port}"
users = ["Alice", "Bob", "Charlie", "David", "Eve"]
try:
for i in range(12):
user = random.choice(users)
result = connect(key=user, host="localhost", port=3306)
print(f"Result: {result}")
except ExceededRateLimitError as e:
print(f"Rate limit exceeded: {e}")
Apply rate limiter decorator with BasicStorage (key_builder with arguments)
import random
# Take all arguments to construct the key!
key_builder = lambda f, *args, **kwargs: ",".join(list(map(lambda x: str(x), args)))
@grl.general_rate_limiter(
storage=BasicStorage(),
max_requests=2,
time_window=1,
key_builder=key_builder
)
def connect(username: str, host: str, port: int, *args):
return f"{username} connected to {host}:{port}"
users = ["Alice", "Bob", "Charlie", "David", "Eve"]
try:
for i in range(12):
user = random.choice(users)
result = connect(user, "localhost", 3306)
# Modify the function call like below would make every call unique,
# thus never trigger the `ExceedRateLimitError`.
# result = connect(user, "localhost", 3306, i) # `i` is unique
print(f"Result: {result}")
except ExceededRateLimitError as e:
print(f"Rate limit exceeded: {e}")
Apply rate limiter decorator with BasicStorage (key_builder with keyword argument)
import random
@grl.general_rate_limiter(
storage=BasicStorage(),
max_requests=2,
time_window=1,
key_builder=lambda f, *args, **kwargs: kwargs["username"]
)
def connect(username: str, host: str, port: int):
return f"{username} connected to {host}:{port}"
users = ["Alice", "Bob", "Charlie", "David", "Eve"]
try:
for i in range(12):
user = random.choice(users)
result = connect(username=user, host="localhost", port=3306)
print(f"Result: {result}")
except ExceededRateLimitError as e:
print(f"Rate limit exceeded: {e}")
Example - SQLite3_Storage
Imports
from pygrl import SQLite3_Storage, GeneralRateLimiter as grl, ExceededRateLimitError
Check limit with SQLite3_Storage
storage = SQLite3_Storage("storage1.db", overwrite=True)
rate_limiter = grl(storage, 10, 1)
try:
for i in range(12):
allowed_to_pass = rate_limiter.check_limit("client-key")
if allowed_to_pass:
print(f"Request {i + 1}: Allowed")
else:
print(f"Request {i + 1}: Exceeded rate limit")
except Exception as e:
print(f"Rate limit exceeded: {e}")
Apply rate limiter decorator with SQLite3_Storage
@grl.general_rate_limiter(storage=SQLite3_Storage("storage2.db", overwrite=True), max_requests=10, time_window=1)
def fn(a, b):
return a + b
try:
for i in range(12):
result = fn(i, i + 1)
print(f"Result {i + 1}: {result}")
except ExceededRateLimitError as e:
print(f"Rate limit exceeded: {e}")
Apply rate limiter decorator with SQLite3_Storage (Keyed function)
import random
@grl.general_rate_limiter(storage=SQLite3_Storage("storage3.db", overwrite=True), max_requests=2, time_window=1)
def connect(key: str, host: str, port: int):
return f"{key} connected to {host}:{port}"
users = ["Alice", "Bob", "Charlie", "David", "Eve"]
try:
for i in range(12):
user = random.choice(users)
result = connect(key=user, host="localhost", port=3306)
print(f"Result: {result}")
except ExceededRateLimitError as e:
print(f"Rate limit exceeded: {e}")
Apply rate limiter decorator with SQLite3_Storage (key_builder with arguments)
import random
# Take all arguments to construct the key!
key_builder = lambda f, *args, **kwargs: ",".join(list(map(lambda x: str(x), args)))
@grl.general_rate_limiter(
storage=storage=SQLite3_Storage("storage3.db", overwrite=True),
max_requests=2,
time_window=1,
key_builder=key_builder
)
def connect(username: str, host: str, port: int, *args):
return f"{username} connected to {host}:{port}"
users = ["Alice", "Bob", "Charlie", "David", "Eve"]
try:
for i in range(12):
user = random.choice(users)
result = connect(user, "localhost", 3306)
# Modify the function call like below would make every call unique,
# thus never trigger the `ExceedRateLimitError`.
# result = connect(user, "localhost", 3306, i) # `i` is unique
print(f"Result: {result}")
except ExceededRateLimitError as e:
print(f"Rate limit exceeded: {e}")
Apply rate limiter decorator with SQLite3_Storage (key_builder with keyword argument)
import random
@grl.general_rate_limiter(
storage=storage=SQLite3_Storage("storage3.db", overwrite=True),
max_requests=2,
time_window=1,
key_builder=lambda f, *args, **kwargs: kwargs["username"]
)
def connect(username: str, host: str, port: int):
return f"{username} connected to {host}:{port}"
users = ["Alice", "Bob", "Charlie", "David", "Eve"]
try:
for i in range(12):
user = random.choice(users)
result = connect(username=user, host="localhost", port=3306)
print(f"Result: {result}")
except ExceededRateLimitError as e:
print(f"Rate limit exceeded: {e}")
Source Code
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
pygrl-0.0.6.5.tar.gz
(8.7 kB
view details)
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
pygrl-0.0.6.5-py3-none-any.whl
(10.7 kB
view details)
File details
Details for the file pygrl-0.0.6.5.tar.gz.
File metadata
- Download URL: pygrl-0.0.6.5.tar.gz
- Upload date:
- Size: 8.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1f392330ab6856880c0fe782a9c27f6c9bc47e6eeea61eb5c4127c79e43372f7
|
|
| MD5 |
fd90011f021bf8fd15a2e23f1e3eaee0
|
|
| BLAKE2b-256 |
2088e37483419c6b3c67da3b1686a5322d6b8e05a92c5ee4f58630589ce8bd7f
|
File details
Details for the file pygrl-0.0.6.5-py3-none-any.whl.
File metadata
- Download URL: pygrl-0.0.6.5-py3-none-any.whl
- Upload date:
- Size: 10.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1e85d0421d9f95d306e927955354d105e39dc87369aee41f4e1738aaa912f083
|
|
| MD5 |
8f29538662a5a729c65c6508ecf8f665
|
|
| BLAKE2b-256 |
7a688c1df71ce01703deaddbf305ac3bd447d39911c4beed230a0052c97c4aea
|