This is an automated email from the ASF dual-hosted git repository.

arm pushed a commit to branch rate_limiting
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git

commit 2469e1054563322256ddc7ec6f460a27d8339094
Author: Alastair McFarlane <[email protected]>
AuthorDate: Fri Jan 23 11:02:58 2026 +0000

    #535 - Add global and API rate limits and proxyfix middleware.
---
 atr/blueprints/api.py | 10 ++++++++-
 atr/server.py         | 28 ++++++++++++++++++++++--
 pyproject.toml        |  1 +
 uv.lock               | 60 +++++++++++++++++++++++++++++++--------------------
 4 files changed, 73 insertions(+), 26 deletions(-)

diff --git a/atr/blueprints/api.py b/atr/blueprints/api.py
index d5c1491..3c84266 100644
--- a/atr/blueprints/api.py
+++ b/atr/blueprints/api.py
@@ -14,7 +14,7 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
+import datetime
 import sys
 from types import ModuleType
 from typing import Any
@@ -23,6 +23,7 @@ import asfquart.base as base
 import pydantic
 import quart
 import quart.blueprints as blueprints
+import quart_rate_limiter as rate_limiter
 import quart_schema
 import werkzeug.exceptions as exceptions
 
@@ -38,6 +39,13 @@ def register(app: base.QuartApp) -> tuple[ModuleType, 
list[str]]:
     return api, []
 
 
+@_BLUEPRINT.before_request
+@rate_limiter.rate_limit(500, datetime.timedelta(hours=1))
+async def _api_rate_limit() -> None:
+    """Set API-wide rate limit"""
+    pass
+
+
 def _exempt_blueprint(app: base.QuartApp) -> None:
     csrf = app.extensions.get("csrf")
     if csrf is not None:
diff --git a/atr/server.py b/atr/server.py
index efc421a..31b818c 100644
--- a/atr/server.py
+++ b/atr/server.py
@@ -37,7 +37,9 @@ import asfquart.base as base
 import asfquart.generics
 import asfquart.session
 import blockbuster
+import hypercorn.middleware.proxy_fix as proxy_fix
 import quart
+import quart_rate_limiter as rate_limiter
 import quart_schema
 import quart_wtf
 import werkzeug.routing as routing
@@ -127,6 +129,10 @@ def _app_create_base(app_config: type[config.AppConfig]) 
-> base.QuartApp:
     asfquart_secret_key = app.secret_key
     app.config.from_object(app_config)
     app.secret_key = asfquart_secret_key
+
+    # if not util.is_dev_environment():
+    app.asgi_app = proxy_fix.ProxyFixMiddleware(app.asgi_app, mode="legacy", 
trusted_hops=1)
+
     return app
 
 
@@ -380,6 +386,24 @@ def _app_setup_logging(app: base.QuartApp, config_mode: 
config.Mode, app_config:
             log.info(f"STATE_DIR    = {app_config.STATE_DIR}")
 
 
+def _app_setup_rate_limits(app: base.QuartApp):
+    async def get_rate_limit_key() -> str:
+        """Authenticated users -> pool per user"""
+        session = await asfquart.session.read()
+        if session is not None:
+            return f"user:{session.uid}"
+        return f"ip:{quart.request.remote_addr}"
+
+    rate_limiter.RateLimiter(
+        app,
+        default_limits=[
+            rate_limiter.RateLimit(100, datetime.timedelta(minutes=1)),
+            rate_limiter.RateLimit(1000, datetime.timedelta(hours=1)),
+        ],
+        key_function=get_rate_limit_key,
+    )
+
+
 def _app_setup_request_lifecycle(app: base.QuartApp) -> None:
     """Setup application request lifecycle hooks."""
     import structlog
@@ -396,8 +420,6 @@ def _app_setup_request_lifecycle(app: base.QuartApp) -> 
None:
         if session is not None:
             log.add_context(user_id=session.uid)
 
-        log.debug("headers", **quart.request.headers)
-
     @app.after_request
     async def log_request(response: quart.Response) -> quart.Response:
         logger.info(
@@ -484,6 +506,8 @@ def _create_app(app_config: type[config.AppConfig]) -> 
base.QuartApp:
 
     _app_setup_api_docs(app)
     quart_wtf.CSRFProtect(app)
+
+    _app_setup_rate_limits(app)
     _app_setup_logging(app, config_mode, app_config)
     db.init_database(app)
     _register_routes(app)
diff --git a/pyproject.toml b/pyproject.toml
index e6826a5..a57bd65 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -42,6 +42,7 @@ dependencies = [
   # "pynacl>=1.5.0",
   "python-decouple~=3.8",
   "python-gnupg~=0.5",
+  "quart-rate-limiter>=0.12.1",
   "quart-schema[pydantic]~=0.21",
   "quart-wtforms~=1.0.3",
   "rich~=14.0.0",
diff --git a/uv.lock b/uv.lock
index 443e89f..8f36126 100644
--- a/uv.lock
+++ b/uv.lock
@@ -3,7 +3,7 @@ revision = 3
 requires-python = "==3.13.*"
 
 [options]
-exclude-newer = "2026-01-22T16:14:01Z"
+exclude-newer = "2026-01-23T11:01:06Z"
 
 [[package]]
 name = "aiofiles"
@@ -1500,6 +1500,18 @@ wheels = [
     { url = 
"https://files.pythonhosted.org/packages/7e/e9/cc28f21f52913adf333f653b9e0a3bf9cb223f5083a26422968ba73edd8d/quart-0.20.0-py3-none-any.whl";,
 hash = 
"sha256:003c08f551746710acb757de49d9b768986fd431517d0eb127380b656b98b8f1", size 
= 77960, upload-time = "2024-12-23T13:53:02.842Z" },
 ]
 
+[[package]]
+name = "quart-rate-limiter"
+version = "0.12.1"
+source = { registry = "https://pypi.org/simple"; }
+dependencies = [
+    { name = "quart" },
+]
+sdist = { url = 
"https://files.pythonhosted.org/packages/db/c4/84c073f15612ad6971e95cd541e75534de0fdeab9e59d6ff968f17622a18/quart_rate_limiter-0.12.1.tar.gz";,
 hash = 
"sha256:9bd44b35372d0255ae716bff9aedeb041188cc3480a51a37e1f9e00b178941f3", size 
= 9647, upload-time = "2025-08-13T12:41:26.594Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/17/c2/ed5b657287b9cf5b7ef59e243f5c95265a26f78bf3f96a06b3b44d30ea5d/quart_rate_limiter-0.12.1-py3-none-any.whl";,
 hash = 
"sha256:c910aa603b1eaaedb02d9475c9df1626e32b2bd936647228609d00269521f656", size 
= 8960, upload-time = "2025-08-13T12:41:25.207Z" },
+]
+
 [[package]]
 name = "quart-schema"
 version = "0.23.0"
@@ -1699,28 +1711,28 @@ wheels = [
 
 [[package]]
 name = "ruff"
-version = "0.14.13"
-source = { registry = "https://pypi.org/simple"; }
-sdist = { url = 
"https://files.pythonhosted.org/packages/50/0a/1914efb7903174b381ee2ffeebb4253e729de57f114e63595114c8ca451f/ruff-0.14.13.tar.gz";,
 hash = 
"sha256:83cd6c0763190784b99650a20fec7633c59f6ebe41c5cc9d45ee42749563ad47", size 
= 6059504, upload-time = "2026-01-15T20:15:16.918Z" }
-wheels = [
-    { url = 
"https://files.pythonhosted.org/packages/c3/ae/0deefbc65ca74b0ab1fd3917f94dc3b398233346a74b8bbb0a916a1a6bf6/ruff-0.14.13-py3-none-linux_armv6l.whl";,
 hash = 
"sha256:76f62c62cd37c276cb03a275b198c7c15bd1d60c989f944db08a8c1c2dbec18b", size 
= 13062418, upload-time = "2026-01-15T20:14:50.779Z" },
-    { url = 
"https://files.pythonhosted.org/packages/47/df/5916604faa530a97a3c154c62a81cb6b735c0cb05d1e26d5ad0f0c8ac48a/ruff-0.14.13-py3-none-macosx_10_12_x86_64.whl";,
 hash = 
"sha256:914a8023ece0528d5cc33f5a684f5f38199bbb566a04815c2c211d8f40b5d0ed", size 
= 13442344, upload-time = "2026-01-15T20:15:07.94Z" },
-    { url = 
"https://files.pythonhosted.org/packages/4c/f3/e0e694dd69163c3a1671e102aa574a50357536f18a33375050334d5cd517/ruff-0.14.13-py3-none-macosx_11_0_arm64.whl";,
 hash = 
"sha256:d24899478c35ebfa730597a4a775d430ad0d5631b8647a3ab368c29b7e7bd063", size 
= 12354720, upload-time = "2026-01-15T20:15:09.854Z" },
-    { url = 
"https://files.pythonhosted.org/packages/c3/e8/67f5fcbbaee25e8fc3b56cc33e9892eca7ffe09f773c8e5907757a7e3bdb/ruff-0.14.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl";,
 hash = 
"sha256:9aaf3870f14d925bbaf18b8a2347ee0ae7d95a2e490e4d4aea6813ed15ebc80e", size 
= 12774493, upload-time = "2026-01-15T20:15:20.908Z" },
-    { url = 
"https://files.pythonhosted.org/packages/6b/ce/d2e9cb510870b52a9565d885c0d7668cc050e30fa2c8ac3fb1fda15c083d/ruff-0.14.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl";,
 hash = 
"sha256:ac5b7f63dd3b27cc811850f5ffd8fff845b00ad70e60b043aabf8d6ecc304e09", size 
= 12815174, upload-time = "2026-01-15T20:15:05.74Z" },
-    { url = 
"https://files.pythonhosted.org/packages/88/00/c38e5da58beebcf4fa32d0ddd993b63dfacefd02ab7922614231330845bf/ruff-0.14.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl";,
 hash = 
"sha256:78d2b1097750d90ba82ce4ba676e85230a0ed694178ca5e61aa9b459970b3eb9", size 
= 13680909, upload-time = "2026-01-15T20:15:14.537Z" },
-    { url = 
"https://files.pythonhosted.org/packages/61/61/cd37c9dd5bd0a3099ba79b2a5899ad417d8f3b04038810b0501a80814fd7/ruff-0.14.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl";,
 hash = 
"sha256:7d0bf87705acbbcb8d4c24b2d77fbb73d40210a95c3903b443cd9e30824a5032", size 
= 15144215, upload-time = "2026-01-15T20:15:22.886Z" },
-    { url = 
"https://files.pythonhosted.org/packages/56/8a/85502d7edbf98c2df7b8876f316c0157359165e16cdf98507c65c8d07d3d/ruff-0.14.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl";,
 hash = 
"sha256:a3eb5da8e2c9e9f13431032fdcbe7681de9ceda5835efee3269417c13f1fed5c", size 
= 14706067, upload-time = "2026-01-15T20:14:48.271Z" },
-    { url = 
"https://files.pythonhosted.org/packages/7e/2f/de0df127feb2ee8c1e54354dc1179b4a23798f0866019528c938ba439aca/ruff-0.14.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl";,
 hash = 
"sha256:642442b42957093811cd8d2140dfadd19c7417030a7a68cf8d51fcdd5f217427", size 
= 14133916, upload-time = "2026-01-15T20:14:57.357Z" },
-    { url = 
"https://files.pythonhosted.org/packages/0d/77/9b99686bb9fe07a757c82f6f95e555c7a47801a9305576a9c67e0a31d280/ruff-0.14.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl";,
 hash = 
"sha256:4acdf009f32b46f6e8864af19cbf6841eaaed8638e65c8dac845aea0d703c841", size 
= 13859207, upload-time = "2026-01-15T20:14:55.111Z" },
-    { url = 
"https://files.pythonhosted.org/packages/7d/46/2bdcb34a87a179a4d23022d818c1c236cb40e477faf0d7c9afb6813e5876/ruff-0.14.13-py3-none-manylinux_2_31_riscv64.whl";,
 hash = 
"sha256:591a7f68860ea4e003917d19b5c4f5ac39ff558f162dc753a2c5de897fd5502c", size 
= 14043686, upload-time = "2026-01-15T20:14:52.841Z" },
-    { url = 
"https://files.pythonhosted.org/packages/1a/a9/5c6a4f56a0512c691cf143371bcf60505ed0f0860f24a85da8bd123b2bf1/ruff-0.14.13-py3-none-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:774c77e841cc6e046fc3e91623ce0903d1cd07e3a36b1a9fe79b81dab3de506b", size 
= 12663837, upload-time = "2026-01-15T20:15:18.921Z" },
-    { url = 
"https://files.pythonhosted.org/packages/fe/bb/b920016ece7651fa7fcd335d9d199306665486694d4361547ccb19394c44/ruff-0.14.13-py3-none-musllinux_1_2_armv7l.whl";,
 hash = 
"sha256:61f4e40077a1248436772bb6512db5fc4457fe4c49e7a94ea7c5088655dd21ae", size 
= 12805867, upload-time = "2026-01-15T20:14:59.272Z" },
-    { url = 
"https://files.pythonhosted.org/packages/7d/b3/0bd909851e5696cd21e32a8fc25727e5f58f1934b3596975503e6e85415c/ruff-0.14.13-py3-none-musllinux_1_2_i686.whl";,
 hash = 
"sha256:6d02f1428357fae9e98ac7aa94b7e966fd24151088510d32cf6f902d6c09235e", size 
= 13208528, upload-time = "2026-01-15T20:15:03.732Z" },
-    { url = 
"https://files.pythonhosted.org/packages/3b/3b/e2d94cb613f6bbd5155a75cbe072813756363eba46a3f2177a1fcd0cd670/ruff-0.14.13-py3-none-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:e399341472ce15237be0c0ae5fbceca4b04cd9bebab1a2b2c979e015455d8f0c", size 
= 13929242, upload-time = "2026-01-15T20:15:11.918Z" },
-    { url = 
"https://files.pythonhosted.org/packages/6a/c5/abd840d4132fd51a12f594934af5eba1d5d27298a6f5b5d6c3be45301caf/ruff-0.14.13-py3-none-win32.whl";,
 hash = 
"sha256:ef720f529aec113968b45dfdb838ac8934e519711da53a0456038a0efecbd680", size 
= 12919024, upload-time = "2026-01-15T20:14:43.647Z" },
-    { url = 
"https://files.pythonhosted.org/packages/c2/55/6384b0b8ce731b6e2ade2b5449bf07c0e4c31e8a2e68ea65b3bafadcecc5/ruff-0.14.13-py3-none-win_amd64.whl";,
 hash = 
"sha256:6070bd026e409734b9257e03e3ef18c6e1a216f0435c6751d7a8ec69cb59abef", size 
= 14097887, upload-time = "2026-01-15T20:15:01.48Z" },
-    { url = 
"https://files.pythonhosted.org/packages/4d/e1/7348090988095e4e39560cfc2f7555b1b2a7357deba19167b600fdf5215d/ruff-0.14.13-py3-none-win_arm64.whl";,
 hash = 
"sha256:7ab819e14f1ad9fe39f246cfcc435880ef7a9390d81a2b6ac7e01039083dd247", size 
= 13080224, upload-time = "2026-01-15T20:14:45.853Z" },
+version = "0.14.14"
+source = { registry = "https://pypi.org/simple"; }
+sdist = { url = 
"https://files.pythonhosted.org/packages/2e/06/f71e3a86b2df0dfa2d2f72195941cd09b44f87711cb7fa5193732cb9a5fc/ruff-0.14.14.tar.gz";,
 hash = 
"sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b", size 
= 4515732, upload-time = "2026-01-22T22:30:17.527Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/d2/89/20a12e97bc6b9f9f68343952da08a8099c57237aef953a56b82711d55edd/ruff-0.14.14-py3-none-linux_armv6l.whl";,
 hash = 
"sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed", size 
= 10467650, upload-time = "2026-01-22T22:30:08.578Z" },
+    { url = 
"https://files.pythonhosted.org/packages/a3/b1/c5de3fd2d5a831fcae21beda5e3589c0ba67eec8202e992388e4b17a6040/ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl";,
 hash = 
"sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c", size 
= 10883245, upload-time = "2026-01-22T22:30:04.155Z" },
+    { url = 
"https://files.pythonhosted.org/packages/b8/7c/3c1db59a10e7490f8f6f8559d1db8636cbb13dccebf18686f4e3c9d7c772/ruff-0.14.14-py3-none-macosx_11_0_arm64.whl";,
 hash = 
"sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de", size 
= 10231273, upload-time = "2026-01-22T22:30:34.642Z" },
+    { url = 
"https://files.pythonhosted.org/packages/a1/6e/5e0e0d9674be0f8581d1f5e0f0a04761203affce3232c1a1189d0e3b4dad/ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl";,
 hash = 
"sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e", size 
= 10585753, upload-time = "2026-01-22T22:30:31.781Z" },
+    { url = 
"https://files.pythonhosted.org/packages/23/09/754ab09f46ff1884d422dc26d59ba18b4e5d355be147721bb2518aa2a014/ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl";,
 hash = 
"sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8", size 
= 10286052, upload-time = "2026-01-22T22:30:24.827Z" },
+    { url = 
"https://files.pythonhosted.org/packages/c8/cc/e71f88dd2a12afb5f50733851729d6b571a7c3a35bfdb16c3035132675a0/ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl";,
 hash = 
"sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906", size 
= 11043637, upload-time = "2026-01-22T22:30:13.239Z" },
+    { url = 
"https://files.pythonhosted.org/packages/67/b2/397245026352494497dac935d7f00f1468c03a23a0c5db6ad8fc49ca3fb2/ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl";,
 hash = 
"sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480", size 
= 12194761, upload-time = "2026-01-22T22:30:22.542Z" },
+    { url = 
"https://files.pythonhosted.org/packages/5b/06/06ef271459f778323112c51b7587ce85230785cd64e91772034ddb88f200/ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl";,
 hash = 
"sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df", size 
= 12005701, upload-time = "2026-01-22T22:30:20.499Z" },
+    { url = 
"https://files.pythonhosted.org/packages/41/d6/99364514541cf811ccc5ac44362f88df66373e9fec1b9d1c4cc830593fe7/ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl";,
 hash = 
"sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b", size 
= 11282455, upload-time = "2026-01-22T22:29:59.679Z" },
+    { url = 
"https://files.pythonhosted.org/packages/ca/71/37daa46f89475f8582b7762ecd2722492df26421714a33e72ccc9a84d7a5/ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl";,
 hash = 
"sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974", size 
= 11215882, upload-time = "2026-01-22T22:29:57.032Z" },
+    { url = 
"https://files.pythonhosted.org/packages/2c/10/a31f86169ec91c0705e618443ee74ede0bdd94da0a57b28e72db68b2dbac/ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl";,
 hash = 
"sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66", size 
= 11180549, upload-time = "2026-01-22T22:30:27.175Z" },
+    { url = 
"https://files.pythonhosted.org/packages/fd/1e/c723f20536b5163adf79bdd10c5f093414293cdf567eed9bdb7b83940f3f/ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13", size 
= 10543416, upload-time = "2026-01-22T22:30:01.964Z" },
+    { url = 
"https://files.pythonhosted.org/packages/3e/34/8a84cea7e42c2d94ba5bde1d7a4fae164d6318f13f933d92da6d7c2041ff/ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl";,
 hash = 
"sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412", size 
= 10285491, upload-time = "2026-01-22T22:30:29.51Z" },
+    { url = 
"https://files.pythonhosted.org/packages/55/ef/b7c5ea0be82518906c978e365e56a77f8de7678c8bb6651ccfbdc178c29f/ruff-0.14.14-py3-none-musllinux_1_2_i686.whl";,
 hash = 
"sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3", size 
= 10733525, upload-time = "2026-01-22T22:30:06.499Z" },
+    { url = 
"https://files.pythonhosted.org/packages/6a/5b/aaf1dfbcc53a2811f6cc0a1759de24e4b03e02ba8762daabd9b6bd8c59e3/ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b", size 
= 11315626, upload-time = "2026-01-22T22:30:36.848Z" },
+    { url = 
"https://files.pythonhosted.org/packages/2c/aa/9f89c719c467dfaf8ad799b9bae0df494513fb21d31a6059cb5870e57e74/ruff-0.14.14-py3-none-win32.whl";,
 hash = 
"sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167", size 
= 10502442, upload-time = "2026-01-22T22:30:38.93Z" },
+    { url = 
"https://files.pythonhosted.org/packages/87/44/90fa543014c45560cae1fffc63ea059fb3575ee6e1cb654562197e5d16fb/ruff-0.14.14-py3-none-win_amd64.whl";,
 hash = 
"sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd", size 
= 11630486, upload-time = "2026-01-22T22:30:10.852Z" },
+    { url = 
"https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl";,
 hash = 
"sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size 
= 10920448, upload-time = "2026-01-22T22:30:15.417Z" },
 ]
 
 [[package]]
@@ -1862,6 +1874,7 @@ dependencies = [
     { name = "pyjwt" },
     { name = "python-decouple" },
     { name = "python-gnupg" },
+    { name = "quart-rate-limiter" },
     { name = "quart-schema", extra = ["pydantic"] },
     { name = "quart-wtforms" },
     { name = "rich" },
@@ -1923,6 +1936,7 @@ requires-dist = [
     { name = "pyjwt", specifier = ">=2.10.1,<3.0.0" },
     { name = "python-decouple", specifier = "~=3.8" },
     { name = "python-gnupg", specifier = "~=0.5" },
+    { name = "quart-rate-limiter", specifier = ">=0.12.1" },
     { name = "quart-schema", extras = ["pydantic"], specifier = "~=0.21" },
     { name = "quart-wtforms", specifier = "~=1.0.3" },
     { name = "rich", specifier = "~=14.0.0" },


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to