From 6f9af0f02bedeb67753828d1ab34920188ea7a38 Mon Sep 17 00:00:00 2001 From: Nebulizer1213 <fixingg@gmail.com> Date: Sun, 27 Nov 2022 20:19:24 -0500 Subject: [PATCH] Added support for views and changed how RedisLimiter and MemcachedLimiter are imported. --- .github/ISSUE_TEMPLATE/bug-report.md | 1 - .idea/aiohttp-ratelimiter.iml | 2 +- .idea/misc.xml | 2 +- README.md | 16 +++++++++++++++- aiohttp_ratelimiter.egg-info/PKG-INFO | 18 ++++++++++++++++-- aiohttplimiter/__init__.py | 2 -- aiohttplimiter/limiter.py | 12 ++++++++---- aiohttplimiter/memcached_limiter.py | 5 +++-- aiohttplimiter/memory_limiter.py | 5 +++-- aiohttplimiter/redis_limiter.py | 5 +++-- dist/aiohttp-ratelimiter-4.0.1.tar.gz | Bin 5242 -> 0 bytes dist/aiohttp-ratelimiter-4.1.1.tar.gz | Bin 0 -> 5264 bytes setup.py | 2 +- 13 files changed, 51 insertions(+), 19 deletions(-) delete mode 100644 dist/aiohttp-ratelimiter-4.0.1.tar.gz create mode 100644 dist/aiohttp-ratelimiter-4.1.1.tar.gz diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 9163304..7b0d76b 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -10,7 +10,6 @@ assignees: Nebulizer1213 # Bug Report Before you submit this request make sure you are using the latest version of aiohttp-ratelimiter. -If you want faster support you can go to https://jgltechnologies.com/contact and link this issue in the message box. ### Python version diff --git a/.idea/aiohttp-ratelimiter.iml b/.idea/aiohttp-ratelimiter.iml index 1959cc0..8e5446a 100644 --- a/.idea/aiohttp-ratelimiter.iml +++ b/.idea/aiohttp-ratelimiter.iml @@ -4,7 +4,7 @@ <content url="file://$MODULE_DIR$"> <excludeFolder url="file://$MODULE_DIR$/venv" /> </content> - <orderEntry type="jdk" jdkName="Python 3.10 (aiohttp-ratelimiter)" jdkType="Python SDK" /> + <orderEntry type="inheritedJdk" /> <orderEntry type="sourceFolder" forTests="false" /> </component> <component name="PyDocumentationSettings"> diff --git a/.idea/misc.xml b/.idea/misc.xml index 339dd29..23c9186 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> - <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (aiohttp-ratelimiter)" project-jdk-type="Python SDK" /> + <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (aiohttp-ratelimiter)" project-jdk-type="Python SDK" /> <component name="PyCharmProfessionalAdvertiser"> <option name="shown" value="true" /> </component> diff --git a/README.md b/README.md index 60457b7..0003c48 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,9 @@ Example ```python from aiohttp import web -from aiohttplimiter import default_keyfunc, Limiter, RedisLimiter, MemcachedLimiter +from aiohttplimiter import default_keyfunc, Limiter +from aiohttplimiter.redis_limiter import RedisLimiter +from aiohttplimiter.memcached_limiter import MemcachedLimiter app = web.Application() routes = web.RouteTableDef() @@ -116,5 +118,17 @@ def home(request): return web.Response(text="Hello") ``` +<br> + +Views Example + +```python +@routes.view("/") +class Home(View): + @limiter.limit("1/second") + def get(self: web.Request): + return web.Response(text="hello") +``` + diff --git a/aiohttp_ratelimiter.egg-info/PKG-INFO b/aiohttp_ratelimiter.egg-info/PKG-INFO index 33b434e..6b6b633 100644 --- a/aiohttp_ratelimiter.egg-info/PKG-INFO +++ b/aiohttp_ratelimiter.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: aiohttp-ratelimiter -Version: 4.0.1 +Version: 4.1.1 Summary: A simple rate limiter for aiohttp.web Home-page: https://jgltechnologies.com/aiohttplimiter Author: George Luca @@ -48,7 +48,9 @@ Example ```python from aiohttp import web -from aiohttplimiter import default_keyfunc, Limiter, RedisLimiter, MemcachedLimiter +from aiohttplimiter import default_keyfunc, Limiter +from aiohttplimiter.redis_limiter import RedisLimiter +from aiohttplimiter.memcached_limiter import MemcachedLimiter app = web.Application() routes = web.RouteTableDef() @@ -134,6 +136,18 @@ def home(request): return web.Response(text="Hello") ``` +<br> + +Views Example + +```python +@routes.view("/") +class Home(View): + @limiter.limit("1/second") + def get(self: web.Request): + return web.Response(text="hello") +``` + diff --git a/aiohttplimiter/__init__.py b/aiohttplimiter/__init__.py index 93a0fd4..445ff68 100644 --- a/aiohttplimiter/__init__.py +++ b/aiohttplimiter/__init__.py @@ -1,4 +1,2 @@ from .limiter import default_keyfunc, Allow, RateLimitExceeded from .memory_limiter import Limiter -from .redis_limiter import RedisLimiter -from .memcached_limiter import MemcachedLimiter diff --git a/aiohttplimiter/limiter.py b/aiohttplimiter/limiter.py index 6c4e4f8..d594f8e 100644 --- a/aiohttplimiter/limiter.py +++ b/aiohttplimiter/limiter.py @@ -2,16 +2,18 @@ import json from typing import Callable, Awaitable, Union, Optional, Coroutine, Any import asyncio -from aiohttp.web import Request, Response +from aiohttp.web import Request, Response, View from limits.aio.storage import Storage, MemoryStorage from limits.aio.strategies import MovingWindowRateLimiter from limits import parse -def default_keyfunc(request: Request) -> str: +def default_keyfunc(request: Union[Request, View]) -> str: """ Returns the user's IP """ + if isinstance(request, View): + request = request.request ip = request.headers.get( "X-Forwarded-For") or request.remote or "127.0.0.1" ip = ip.split(",")[0] @@ -51,9 +53,11 @@ def __init__(self, db: Storage, path_id: str, keyfunc: Callable, self.path_id = path_id self.moving_window = moving_window - def __call__(self, func: Union[Callable, Awaitable]) -> Coroutine[Any, Any, Response]: + def __call__(self, func: Union[Callable, Awaitable]) -> Callable[[Union[Request, View]], Coroutine[Any, Any, Response]]: @wraps(func) - async def wrapper(request: Request) -> Response: + async def wrapper(request: Union[Request, View]) -> Response: + if isinstance(request, View): + request = request.request key = self.keyfunc(request) db_key = f"{key}:{self.path_id or request.path}" diff --git a/aiohttplimiter/memcached_limiter.py b/aiohttplimiter/memcached_limiter.py index 537c15f..86390d0 100644 --- a/aiohttplimiter/memcached_limiter.py +++ b/aiohttplimiter/memcached_limiter.py @@ -1,4 +1,5 @@ -from typing import Callable, Awaitable, Union, Optional +from typing import Callable, Awaitable, Union, Optional, Any, Coroutine +from aiohttp.web import Request, Response, View from limits.aio.storage import MemcachedStorage from .limiter import BaseRateLimitDecorator from limits.aio.strategies import MovingWindowRateLimiter @@ -26,7 +27,7 @@ def __init__(self, keyfunc: Callable, uri: str, exempt_ips: Optional[set] = None def limit(self, ratelimit: str, keyfunc: Callable = None, exempt_ips: Optional[set] = None, error_handler: Optional[Union[Callable, Awaitable]] = None, path_id: str = None) -> Callable: - def wrapper(func: Callable) -> Awaitable: + def wrapper(func: Callable) -> Callable[[Union[Request, View]], Coroutine[Any, Any, Response]]: _exempt_ips = exempt_ips or self.exempt_ips _keyfunc = keyfunc or self.keyfunc _error_handler = self.error_handler or error_handler diff --git a/aiohttplimiter/memory_limiter.py b/aiohttplimiter/memory_limiter.py index 05fb03f..9febc89 100644 --- a/aiohttplimiter/memory_limiter.py +++ b/aiohttplimiter/memory_limiter.py @@ -1,7 +1,8 @@ +from aiohttp.web import Request, Response, View from limits.aio.storage import MemoryStorage from limits.aio.strategies import MovingWindowRateLimiter from .limiter import BaseRateLimitDecorator -from typing import Callable, Optional, Union, Awaitable +from typing import Callable, Optional, Union, Awaitable, Any, Coroutine class Limiter: @@ -26,7 +27,7 @@ def __init__(self, keyfunc: Callable, exempt_ips: Optional[set] = None, def limit(self, ratelimit: str, keyfunc: Callable = None, exempt_ips: Optional[set] = None, error_handler: Optional[Union[Callable, Awaitable]] = None, path_id: str = None) -> Callable: - def wrapper(func: Callable) -> Awaitable: + def wrapper(func: Callable) -> Callable[[Union[Request, View]], Coroutine[Any, Any, Response]]: _exempt_ips = exempt_ips or self.exempt_ips _keyfunc = keyfunc or self.keyfunc _error_handler = self.error_handler or error_handler diff --git a/aiohttplimiter/redis_limiter.py b/aiohttplimiter/redis_limiter.py index 8814863..6fb7e78 100644 --- a/aiohttplimiter/redis_limiter.py +++ b/aiohttplimiter/redis_limiter.py @@ -1,5 +1,6 @@ -from typing import Callable, Awaitable, Union, Optional +from typing import Callable, Awaitable, Union, Optional, Any, Coroutine import coredis +from aiohttp.web import Request, Response, View from limits.aio.storage import RedisStorage from .limiter import BaseRateLimitDecorator from limits.aio.strategies import MovingWindowRateLimiter @@ -27,7 +28,7 @@ def __init__(self, keyfunc: Callable, uri: str, exempt_ips: Optional[set] = None def limit(self, ratelimit: str, keyfunc: Callable = None, exempt_ips: Optional[set] = None, error_handler: Optional[Union[Callable, Awaitable]] = None, path_id: str = None) -> Callable: - def wrapper(func: Callable) -> Awaitable: + def wrapper(func: Callable) -> Callable[[Union[Request, View]], Coroutine[Any, Any, Response]]: _exempt_ips = exempt_ips or self.exempt_ips _keyfunc = keyfunc or self.keyfunc _error_handler = self.error_handler or error_handler diff --git a/dist/aiohttp-ratelimiter-4.0.1.tar.gz b/dist/aiohttp-ratelimiter-4.0.1.tar.gz deleted file mode 100644 index 44d1484d6cf1436685c65eb9e1d1add4842b99b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5242 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 diff --git a/dist/aiohttp-ratelimiter-4.1.1.tar.gz b/dist/aiohttp-ratelimiter-4.1.1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..9cf8645a2184a1884803eab3b3a6db6adb50f400 GIT binary patch literal 5264 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 CRhxJK literal 0 HcmV?d00001 diff --git a/setup.py b/setup.py index 51014dc..e36fe80 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ def get_long_description(): return file.read() -VERSION = "4.0.1" +VERSION = "4.1.1" classifiers = [ "Development Status :: 5 - Production/Stable",