diff --git a/fastapi_cache/__init__.py b/fastapi_cache/__init__.py index e21e4b7..e9ef55e 100644 --- a/fastapi_cache/__init__.py +++ b/fastapi_cache/__init__.py @@ -1,9 +1,8 @@ from typing import ClassVar, Optional, Type -from fastapi_cache.backends import Backend from fastapi_cache.coder import Coder, JsonCoder from fastapi_cache.key_builder import default_key_builder -from fastapi_cache.types import KeyBuilder +from fastapi_cache.types import Backend, KeyBuilder __all__ = [ diff --git a/fastapi_cache/backends/__init__.py b/fastapi_cache/backends/__init__.py index 4519aa9..261af6c 100644 --- a/fastapi_cache/backends/__init__.py +++ b/fastapi_cache/backends/__init__.py @@ -1,20 +1,29 @@ -import abc -from typing import Optional, Tuple +from fastapi_cache.types import Backend +from fastapi_cache.backends import inmemory -class Backend: - @abc.abstractmethod - async def get_with_ttl(self, key: str) -> Tuple[int, Optional[bytes]]: - raise NotImplementedError +__all__ = ["Backend", "inmemory"] - @abc.abstractmethod - async def get(self, key: str) -> Optional[bytes]: - raise NotImplementedError +# import each backend in turn and add to __all__. This syntax +# is explicitly supported by type checkers, while more dynamic +# syntax would not be recognised. +try: + from fastapi_cache.backends import dynamodb +except ImportError: + pass +else: + __all__ += ["dynamodb"] - @abc.abstractmethod - async def set(self, key: str, value: bytes, expire: Optional[int] = None) -> None: - raise NotImplementedError +try: + from fastapi_cache.backends import memcached +except ImportError: + pass +else: + __all__ += ["memcached"] - @abc.abstractmethod - async def clear(self, namespace: Optional[str] = None, key: Optional[str] = None) -> int: - raise NotImplementedError +try: + from fastapi_cache.backends import redis +except ImportError: + pass +else: + __all__ += ["redis"] diff --git a/fastapi_cache/backends/dynamodb.py b/fastapi_cache/backends/dynamodb.py index 94318c9..ec639d1 100644 --- a/fastapi_cache/backends/dynamodb.py +++ b/fastapi_cache/backends/dynamodb.py @@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Optional, Tuple from aiobotocore.client import AioBaseClient from aiobotocore.session import AioSession, get_session -from fastapi_cache.backends import Backend +from fastapi_cache.types import Backend if TYPE_CHECKING: from types_aiobotocore_dynamodb import DynamoDBClient diff --git a/fastapi_cache/backends/inmemory.py b/fastapi_cache/backends/inmemory.py index 219dd25..5ef101b 100644 --- a/fastapi_cache/backends/inmemory.py +++ b/fastapi_cache/backends/inmemory.py @@ -3,7 +3,7 @@ from asyncio import Lock from dataclasses import dataclass from typing import Dict, Optional, Tuple -from fastapi_cache.backends import Backend +from fastapi_cache.types import Backend @dataclass diff --git a/fastapi_cache/backends/memcached.py b/fastapi_cache/backends/memcached.py index 22e201f..156a3e6 100644 --- a/fastapi_cache/backends/memcached.py +++ b/fastapi_cache/backends/memcached.py @@ -2,7 +2,7 @@ from typing import Optional, Tuple from aiomcache import Client -from fastapi_cache.backends import Backend +from fastapi_cache.types import Backend class MemcachedBackend(Backend): diff --git a/fastapi_cache/backends/redis.py b/fastapi_cache/backends/redis.py index 22a63ef..5eef48f 100644 --- a/fastapi_cache/backends/redis.py +++ b/fastapi_cache/backends/redis.py @@ -3,11 +3,11 @@ from typing import Optional, Tuple, Union from redis.asyncio.client import Redis from redis.asyncio.cluster import RedisCluster -from fastapi_cache.backends import Backend +from fastapi_cache.types import Backend class RedisBackend(Backend): - def __init__(self, redis: Union[Redis[bytes], RedisCluster[bytes]]): + def __init__(self, redis: Union["Redis[bytes]", "RedisCluster[bytes]"]): self.redis = redis self.is_cluster: bool = isinstance(redis, RedisCluster) diff --git a/fastapi_cache/types.py b/fastapi_cache/types.py index 63192ab..1ae4069 100644 --- a/fastapi_cache/types.py +++ b/fastapi_cache/types.py @@ -1,3 +1,4 @@ +import abc from typing import Any, Awaitable, Callable, Dict, Optional, Tuple, Union from starlette.requests import Request @@ -20,3 +21,21 @@ class KeyBuilder(Protocol): kwargs: Dict[str, Any], ) -> Union[Awaitable[str], str]: ... + + +class Backend(abc.ABC): + @abc.abstractmethod + async def get_with_ttl(self, key: str) -> Tuple[int, Optional[bytes]]: + raise NotImplementedError + + @abc.abstractmethod + async def get(self, key: str) -> Optional[bytes]: + raise NotImplementedError + + @abc.abstractmethod + async def set(self, key: str, value: bytes, expire: Optional[int] = None) -> None: + raise NotImplementedError + + @abc.abstractmethod + async def clear(self, namespace: Optional[str] = None, key: Optional[str] = None) -> int: + raise NotImplementedError