pygrl


Namepygrl JSON
Version 0.0.6.5 PyPI version JSON
download
home_pageNone
SummaryAnother Python package aim to offer "Rate Limiting" functionality for general use cases.
upload_time2024-07-09 09:57:32
maintainerNone
docs_urlNone
authorjonah_whaler_2348
requires_pythonNone
licenseMIT
keywords python rate limiter rate limiter rate limiting
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            ![my-logo](https://jonahtzuchi.github.io/rate-limiter/logo-mini.jpg "pygrl-Logo")

[![Downloads](https://static.pepy.tech/badge/pygrl)](https://pepy.tech/project/pygrl)

# 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`
- 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
```bash
pip3 install pygrl
```

# Example - BasicStorage

## Imports
```python
from pygrl import BasicStorage, GeneralRateLimiter as grl, ExceededRateLimitError
```

# Check limit with BasicStorage
```python
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
```python
@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)
```python
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)
```python
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)
```python
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
```python
from pygrl import SQLite3_Storage, GeneralRateLimiter as grl, ExceededRateLimitError
```

## Check limit with SQLite3_Storage
```python
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
```python
@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)
```python
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)
```python
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)
```python
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
- https://github.com/JonahTzuChi/rate-limiter



            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "pygrl",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": "python, rate, limiter, rate limiter, rate limiting",
    "author": "jonah_whaler_2348",
    "author_email": "jk_saga@proton.me",
    "download_url": "https://files.pythonhosted.org/packages/20/88/e37483419c6b3c67da3b1686a5322d6b8e05a92c5ee4f58630589ce8bd7f/pygrl-0.0.6.5.tar.gz",
    "platform": null,
    "description": "![my-logo](https://jonahtzuchi.github.io/rate-limiter/logo-mini.jpg \"pygrl-Logo\")\n\n[![Downloads](https://static.pepy.tech/badge/pygrl)](https://pepy.tech/project/pygrl)\n\n# PYGRL - Python General Rate Limiter\nAnother Python package aim to offer \"Rate Limiting\" functionality for general use cases.\n\n# Features\n- Flexible storage strategy (Memory | File | Database)\n  - MemoryStorage\n    - `BasicStorage`\n  - FileStorage\n    - `SQLite3_Storage`\n- Cleanup expired rate limiters\n- Use as a decorator\n- Use as a variable\n- Compatible with fastapi (TO BE TESTED)\n- Support asynchronous DB operations (TODO)\n\n# Dependencies\n- Python 3.10\n\n# Installation\n```bash\npip3 install pygrl\n```\n\n# Example - BasicStorage\n\n## Imports\n```python\nfrom pygrl import BasicStorage, GeneralRateLimiter as grl, ExceededRateLimitError\n```\n\n# Check limit with BasicStorage\n```python\nstorage = BasicStorage()\nrate_limiter = grl(storage, 10, 1)\ntry:\n    for i in range(12):\n        allowed_to_pass = rate_limiter.check_limit(\"client-key\")\n        if allowed_to_pass:\n            print(f\"Request {i + 1}: Allowed\")\n        else:\n            print(f\"Request {i + 1}: Exceeded rate limit\")\nexcept Exception as e:\n    print(f\"Rate limit exceeded: {e}\")\n```\n\n## Apply rate limiter decorator with BasicStorage\n```python\n@grl.general_rate_limiter(storage=BasicStorage(), max_requests=10, time_window=1)\ndef fn(a, b):\n    return a + b\n\ntry:\n    for i in range(12):\n        result = fn(i, i + 1)\n        print(f\"Result {i + 1}: {result}\")\nexcept ExceededRateLimitError as e:\n    print(f\"Rate limit exceeded: {e}\")\n```\n\n# Apply rate limiter decorator with BasicStorage (Keyed function)\n```python\nimport random\n\n@grl.general_rate_limiter(storage=BasicStorage(), max_requests=2, time_window=1)\ndef connect(key: str, host: str, port: int):\n    return f\"{key} connected to {host}:{port}\"\n\nusers = [\"Alice\", \"Bob\", \"Charlie\", \"David\", \"Eve\"]\ntry:\n    for i in range(12):\n        user = random.choice(users)\n        result = connect(key=user, host=\"localhost\", port=3306)\n        print(f\"Result: {result}\")\nexcept ExceededRateLimitError as e:\n    print(f\"Rate limit exceeded: {e}\")\n```\n\n\n# Apply rate limiter decorator with BasicStorage (key_builder with arguments)\n```python\nimport random\n\n# Take all arguments to construct the key!\nkey_builder = lambda f, *args, **kwargs: \",\".join(list(map(lambda x: str(x), args)))\n\n@grl.general_rate_limiter(\n    storage=BasicStorage(), \n    max_requests=2, \n    time_window=1, \n    key_builder=key_builder\n)\ndef connect(username: str, host: str, port: int, *args):\n    return f\"{username} connected to {host}:{port}\"\n\nusers = [\"Alice\", \"Bob\", \"Charlie\", \"David\", \"Eve\"]\ntry:\n    for i in range(12):\n        user = random.choice(users)\n        result = connect(user, \"localhost\", 3306)\n        # Modify the function call like below would make every call unique, \n        # thus never trigger the `ExceedRateLimitError`.\n        # result = connect(user, \"localhost\", 3306, i) # `i` is unique\n        print(f\"Result: {result}\")\nexcept ExceededRateLimitError as e:\n    print(f\"Rate limit exceeded: {e}\")\n```\n\n\n# Apply rate limiter decorator with BasicStorage (key_builder with keyword argument)\n```python\nimport random\n\n@grl.general_rate_limiter(\n    storage=BasicStorage(), \n    max_requests=2, \n    time_window=1, \n    key_builder=lambda f, *args, **kwargs: kwargs[\"username\"]\n)\ndef connect(username: str, host: str, port: int):\n    return f\"{username} connected to {host}:{port}\"\n\nusers = [\"Alice\", \"Bob\", \"Charlie\", \"David\", \"Eve\"]\ntry:\n    for i in range(12):\n        user = random.choice(users)\n        result = connect(username=user, host=\"localhost\", port=3306)\n        print(f\"Result: {result}\")\nexcept ExceededRateLimitError as e:\n    print(f\"Rate limit exceeded: {e}\")\n```\n\n# Example - SQLite3_Storage\n\n## Imports\n```python\nfrom pygrl import SQLite3_Storage, GeneralRateLimiter as grl, ExceededRateLimitError\n```\n\n## Check limit with SQLite3_Storage\n```python\nstorage = SQLite3_Storage(\"storage1.db\", overwrite=True)\nrate_limiter = grl(storage, 10, 1)\ntry:\n    for i in range(12):\n        allowed_to_pass = rate_limiter.check_limit(\"client-key\")\n        if allowed_to_pass:\n            print(f\"Request {i + 1}: Allowed\")\n        else:\n            print(f\"Request {i + 1}: Exceeded rate limit\")\nexcept Exception as e:\n    print(f\"Rate limit exceeded: {e}\")\n```\n\n## Apply rate limiter decorator with SQLite3_Storage\n```python\n@grl.general_rate_limiter(storage=SQLite3_Storage(\"storage2.db\", overwrite=True), max_requests=10, time_window=1)\ndef fn(a, b):\n    return a + b\n\ntry:\n    for i in range(12):\n        result = fn(i, i + 1)\n        print(f\"Result {i + 1}: {result}\")\nexcept ExceededRateLimitError as e:\n    print(f\"Rate limit exceeded: {e}\")\n```\n\n## Apply rate limiter decorator with SQLite3_Storage (Keyed function)\n```python\nimport random\n\n@grl.general_rate_limiter(storage=SQLite3_Storage(\"storage3.db\", overwrite=True), max_requests=2, time_window=1)\ndef connect(key: str, host: str, port: int):\n    return f\"{key} connected to {host}:{port}\"\n\nusers = [\"Alice\", \"Bob\", \"Charlie\", \"David\", \"Eve\"]\ntry:\n    for i in range(12):\n        user = random.choice(users)\n        result = connect(key=user, host=\"localhost\", port=3306)\n        print(f\"Result: {result}\")\nexcept ExceededRateLimitError as e:\n    print(f\"Rate limit exceeded: {e}\")\n```\n\n# Apply rate limiter decorator with SQLite3_Storage (key_builder with arguments)\n```python\nimport random\n\n# Take all arguments to construct the key!\nkey_builder = lambda f, *args, **kwargs: \",\".join(list(map(lambda x: str(x), args)))\n\n@grl.general_rate_limiter(\n    storage=storage=SQLite3_Storage(\"storage3.db\", overwrite=True), \n    max_requests=2, \n    time_window=1, \n    key_builder=key_builder\n)\ndef connect(username: str, host: str, port: int, *args):\n    return f\"{username} connected to {host}:{port}\"\n\nusers = [\"Alice\", \"Bob\", \"Charlie\", \"David\", \"Eve\"]\ntry:\n    for i in range(12):\n        user = random.choice(users)\n        result = connect(user, \"localhost\", 3306)\n        # Modify the function call like below would make every call unique, \n        # thus never trigger the `ExceedRateLimitError`.\n        # result = connect(user, \"localhost\", 3306, i) # `i` is unique\n        print(f\"Result: {result}\")\nexcept ExceededRateLimitError as e:\n    print(f\"Rate limit exceeded: {e}\")\n```\n\n\n# Apply rate limiter decorator with SQLite3_Storage (key_builder with keyword argument)\n```python\nimport random\n\n@grl.general_rate_limiter(\n    storage=storage=SQLite3_Storage(\"storage3.db\", overwrite=True), \n    max_requests=2, \n    time_window=1, \n    key_builder=lambda f, *args, **kwargs: kwargs[\"username\"]\n)\ndef connect(username: str, host: str, port: int):\n    return f\"{username} connected to {host}:{port}\"\n\nusers = [\"Alice\", \"Bob\", \"Charlie\", \"David\", \"Eve\"]\ntry:\n    for i in range(12):\n        user = random.choice(users)\n        result = connect(username=user, host=\"localhost\", port=3306)\n        print(f\"Result: {result}\")\nexcept ExceededRateLimitError as e:\n    print(f\"Rate limit exceeded: {e}\")\n```\n\n# Source Code\n- https://github.com/JonahTzuChi/rate-limiter\n\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Another Python package aim to offer \"Rate Limiting\" functionality for general use cases.",
    "version": "0.0.6.5",
    "project_urls": null,
    "split_keywords": [
        "python",
        " rate",
        " limiter",
        " rate limiter",
        " rate limiting"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7a688c1df71ce01703deaddbf305ac3bd447d39911c4beed230a0052c97c4aea",
                "md5": "8f29538662a5a729c65c6508ecf8f665",
                "sha256": "1e85d0421d9f95d306e927955354d105e39dc87369aee41f4e1738aaa912f083"
            },
            "downloads": -1,
            "filename": "pygrl-0.0.6.5-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "8f29538662a5a729c65c6508ecf8f665",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 10656,
            "upload_time": "2024-07-09T09:57:30",
            "upload_time_iso_8601": "2024-07-09T09:57:30.636261Z",
            "url": "https://files.pythonhosted.org/packages/7a/68/8c1df71ce01703deaddbf305ac3bd447d39911c4beed230a0052c97c4aea/pygrl-0.0.6.5-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2088e37483419c6b3c67da3b1686a5322d6b8e05a92c5ee4f58630589ce8bd7f",
                "md5": "fd90011f021bf8fd15a2e23f1e3eaee0",
                "sha256": "1f392330ab6856880c0fe782a9c27f6c9bc47e6eeea61eb5c4127c79e43372f7"
            },
            "downloads": -1,
            "filename": "pygrl-0.0.6.5.tar.gz",
            "has_sig": false,
            "md5_digest": "fd90011f021bf8fd15a2e23f1e3eaee0",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 8730,
            "upload_time": "2024-07-09T09:57:32",
            "upload_time_iso_8601": "2024-07-09T09:57:32.353651Z",
            "url": "https://files.pythonhosted.org/packages/20/88/e37483419c6b3c67da3b1686a5322d6b8e05a92c5ee4f58630589ce8bd7f/pygrl-0.0.6.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-07-09 09:57:32",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "pygrl"
}
        
Elapsed time: 4.35969s