From 3510ea564a673fcf14657f1ea7d4cd7479610504 Mon Sep 17 00:00:00 2001 From: zanewalker Date: Wed, 4 Feb 2026 01:07:32 +0000 Subject: [PATCH] refactor: use contextlib.suppress and sort __slots__ in backends --- fastapi_traffic/backends/base.py | 1 + fastapi_traffic/backends/memory.py | 7 +++--- fastapi_traffic/backends/sqlite.py | 35 ++++++++++++++++-------------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/fastapi_traffic/backends/base.py b/fastapi_traffic/backends/base.py index 8a43d87..826ed46 100644 --- a/fastapi_traffic/backends/base.py +++ b/fastapi_traffic/backends/base.py @@ -71,6 +71,7 @@ class Backend(ABC): """Clear all rate limit data.""" ... + @abstractmethod async def close(self) -> None: """Close the backend connection.""" pass diff --git a/fastapi_traffic/backends/memory.py b/fastapi_traffic/backends/memory.py index 6279656..22b342c 100644 --- a/fastapi_traffic/backends/memory.py +++ b/fastapi_traffic/backends/memory.py @@ -3,6 +3,7 @@ from __future__ import annotations import asyncio +import contextlib import time from collections import OrderedDict from typing import Any @@ -13,7 +14,7 @@ from fastapi_traffic.backends.base import Backend class MemoryBackend(Backend): """Thread-safe in-memory backend with LRU eviction and TTL support.""" - __slots__ = ("_data", "_lock", "_max_size", "_cleanup_interval", "_cleanup_task") + __slots__ = ("_cleanup_interval", "_cleanup_task", "_data", "_lock", "_max_size") def __init__( self, @@ -127,10 +128,8 @@ class MemoryBackend(Backend): """Stop cleanup task and clear data.""" if self._cleanup_task is not None: self._cleanup_task.cancel() - try: + with contextlib.suppress(asyncio.CancelledError): await self._cleanup_task - except asyncio.CancelledError: - pass self._cleanup_task = None await self.clear() diff --git a/fastapi_traffic/backends/sqlite.py b/fastapi_traffic/backends/sqlite.py index ea13395..8dad400 100644 --- a/fastapi_traffic/backends/sqlite.py +++ b/fastapi_traffic/backends/sqlite.py @@ -3,27 +3,30 @@ from __future__ import annotations import asyncio +import contextlib import json import sqlite3 import time -from pathlib import Path -from typing import Any +from typing import TYPE_CHECKING, Any from fastapi_traffic.backends.base import Backend from fastapi_traffic.exceptions import BackendError +if TYPE_CHECKING: + from pathlib import Path + class SQLiteBackend(Backend): """SQLite-based backend with connection pooling and async support.""" __slots__ = ( - "_db_path", - "_connection", - "_lock", "_cleanup_interval", "_cleanup_task", - "_pool_size", + "_connection", "_connections", + "_db_path", + "_lock", + "_pool_size", ) def __init__( @@ -59,9 +62,7 @@ class SQLiteBackend(Backend): """Ensure a database connection exists.""" if self._connection is None: loop = asyncio.get_event_loop() - self._connection = await loop.run_in_executor( - None, self._create_connection - ) + self._connection = await loop.run_in_executor(None, self._create_connection) assert self._connection is not None return self._connection @@ -87,16 +88,20 @@ class SQLiteBackend(Backend): def _create_tables_sync(self, conn: sqlite3.Connection) -> None: """Synchronously create tables.""" - conn.execute(""" + conn.execute( + """ CREATE TABLE IF NOT EXISTS rate_limits ( key TEXT PRIMARY KEY, data TEXT NOT NULL, expires_at REAL NOT NULL ) - """) - conn.execute(""" + """ + ) + conn.execute( + """ CREATE INDEX IF NOT EXISTS idx_expires_at ON rate_limits(expires_at) - """) + """ + ) async def _cleanup_loop(self) -> None: """Background task to clean up expired entries.""" @@ -247,10 +252,8 @@ class SQLiteBackend(Backend): """Close the database connection.""" if self._cleanup_task is not None: self._cleanup_task.cancel() - try: + with contextlib.suppress(asyncio.CancelledError): await self._cleanup_task - except asyncio.CancelledError: - pass self._cleanup_task = None if self._connection is not None: