fastapi-cachex 0.1.4__py3-none-any.whl → 0.1.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of fastapi-cachex might be problematic. Click here for more details.
- fastapi_cachex/__init__.py +2 -0
- fastapi_cachex/backends/__init__.py +11 -3
- fastapi_cachex/backends/base.py +23 -0
- fastapi_cachex/backends/memcached.py +28 -1
- fastapi_cachex/backends/memory.py +34 -0
- fastapi_cachex/backends/redis.py +137 -0
- fastapi_cachex/dependencies.py +14 -0
- {fastapi_cachex-0.1.4.dist-info → fastapi_cachex-0.1.6.dist-info}/METADATA +55 -16
- fastapi_cachex-0.1.6.dist-info/RECORD +18 -0
- fastapi_cachex-0.1.4.dist-info/RECORD +0 -16
- {fastapi_cachex-0.1.4.dist-info → fastapi_cachex-0.1.6.dist-info}/WHEEL +0 -0
- {fastapi_cachex-0.1.4.dist-info → fastapi_cachex-0.1.6.dist-info}/licenses/LICENSE +0 -0
- {fastapi_cachex-0.1.4.dist-info → fastapi_cachex-0.1.6.dist-info}/top_level.txt +0 -0
fastapi_cachex/__init__.py
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
-
from .base import BaseCacheBackend
|
|
2
|
-
from .memcached import MemcachedBackend
|
|
3
|
-
from .memory import MemoryBackend
|
|
1
|
+
from fastapi_cachex.backends.base import BaseCacheBackend
|
|
2
|
+
from fastapi_cachex.backends.memcached import MemcachedBackend
|
|
3
|
+
from fastapi_cachex.backends.memory import MemoryBackend
|
|
4
|
+
from fastapi_cachex.backends.redis import AsyncRedisCacheBackend
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"AsyncRedisCacheBackend",
|
|
8
|
+
"BaseCacheBackend",
|
|
9
|
+
"MemcachedBackend",
|
|
10
|
+
"MemoryBackend",
|
|
11
|
+
]
|
fastapi_cachex/backends/base.py
CHANGED
|
@@ -25,3 +25,26 @@ class BaseCacheBackend(ABC):
|
|
|
25
25
|
@abstractmethod
|
|
26
26
|
async def clear(self) -> None:
|
|
27
27
|
"""Clear all cached responses."""
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
async def clear_path(self, path: str, include_params: bool = False) -> int:
|
|
31
|
+
"""Clear cached responses for a specific path.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
path: The path to clear cache for
|
|
35
|
+
include_params: Whether to clear all parameter variations of the path
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Number of cache entries cleared
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
async def clear_pattern(self, pattern: str) -> int:
|
|
43
|
+
"""Clear cached responses matching a pattern.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
pattern: A glob pattern to match cache keys against (e.g., "/users/*")
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Number of cache entries cleared
|
|
50
|
+
"""
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import ast
|
|
2
|
+
import warnings
|
|
2
3
|
from typing import Optional
|
|
3
4
|
|
|
4
5
|
from fastapi_cachex.backends.base import BaseCacheBackend
|
|
@@ -25,7 +26,7 @@ class MemcachedBackend(BaseCacheBackend):
|
|
|
25
26
|
"pymemcache is not installed. Please install it with 'pip install pymemcache'"
|
|
26
27
|
)
|
|
27
28
|
|
|
28
|
-
self.client = HashClient(servers)
|
|
29
|
+
self.client = HashClient(servers, connect_timeout=5, timeout=5)
|
|
29
30
|
|
|
30
31
|
async def get(self, key: str) -> Optional[ETagContent]:
|
|
31
32
|
"""Get value from cache.
|
|
@@ -72,3 +73,29 @@ class MemcachedBackend(BaseCacheBackend):
|
|
|
72
73
|
async def clear(self) -> None:
|
|
73
74
|
"""Clear all values from cache."""
|
|
74
75
|
self.client.flush_all()
|
|
76
|
+
|
|
77
|
+
async def clear_path(self, path: str, include_params: bool = False) -> int:
|
|
78
|
+
"""Clear cached responses for a specific path."""
|
|
79
|
+
if include_params:
|
|
80
|
+
warnings.warn(
|
|
81
|
+
"Memcached backend does not support pattern-based key clearing. "
|
|
82
|
+
"The include_params option will have no effect.",
|
|
83
|
+
RuntimeWarning,
|
|
84
|
+
stacklevel=2,
|
|
85
|
+
)
|
|
86
|
+
return 0
|
|
87
|
+
|
|
88
|
+
# If we're not including params, we can just try to delete the exact path
|
|
89
|
+
if self.client.delete(path, noreply=False):
|
|
90
|
+
return 1
|
|
91
|
+
return 0
|
|
92
|
+
|
|
93
|
+
async def clear_pattern(self, pattern: str) -> int: # noqa: ARG002
|
|
94
|
+
"""Clear cached responses matching a pattern."""
|
|
95
|
+
warnings.warn(
|
|
96
|
+
"Memcached backend does not support pattern matching. "
|
|
97
|
+
"Pattern-based cache clearing is not available.",
|
|
98
|
+
RuntimeWarning,
|
|
99
|
+
stacklevel=2,
|
|
100
|
+
)
|
|
101
|
+
return 0
|
|
@@ -53,6 +53,40 @@ class MemoryBackend(BaseCacheBackend):
|
|
|
53
53
|
async with self.lock:
|
|
54
54
|
self.cache.clear()
|
|
55
55
|
|
|
56
|
+
async def clear_path(self, path: str, include_params: bool = False) -> int:
|
|
57
|
+
"""Clear cached responses for a specific path."""
|
|
58
|
+
cleared_count = 0
|
|
59
|
+
async with self.lock:
|
|
60
|
+
keys_to_delete = []
|
|
61
|
+
for key in self.cache:
|
|
62
|
+
cache_path, *params = key.split(":", 1)
|
|
63
|
+
if cache_path == path and (include_params or not params):
|
|
64
|
+
keys_to_delete.append(key)
|
|
65
|
+
cleared_count += 1
|
|
66
|
+
|
|
67
|
+
for key in keys_to_delete:
|
|
68
|
+
del self.cache[key]
|
|
69
|
+
|
|
70
|
+
return cleared_count
|
|
71
|
+
|
|
72
|
+
async def clear_pattern(self, pattern: str) -> int:
|
|
73
|
+
"""Clear cached responses matching a pattern."""
|
|
74
|
+
import fnmatch
|
|
75
|
+
|
|
76
|
+
cleared_count = 0
|
|
77
|
+
async with self.lock:
|
|
78
|
+
keys_to_delete = []
|
|
79
|
+
for key in self.cache:
|
|
80
|
+
cache_path = key.split(":", 1)[0] # Get path part only
|
|
81
|
+
if fnmatch.fnmatch(cache_path, pattern):
|
|
82
|
+
keys_to_delete.append(key)
|
|
83
|
+
cleared_count += 1
|
|
84
|
+
|
|
85
|
+
for key in keys_to_delete:
|
|
86
|
+
del self.cache[key]
|
|
87
|
+
|
|
88
|
+
return cleared_count
|
|
89
|
+
|
|
56
90
|
async def _cleanup_task_impl(self) -> None:
|
|
57
91
|
try:
|
|
58
92
|
while True:
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
from typing import Any
|
|
3
|
+
from typing import Literal
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from fastapi_cachex.backends.base import BaseCacheBackend
|
|
7
|
+
from fastapi_cachex.exceptions import CacheXError
|
|
8
|
+
from fastapi_cachex.types import ETagContent
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from redis.asyncio import Redis as AsyncRedis
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
import orjson as json
|
|
15
|
+
|
|
16
|
+
except ImportError: # pragma: no cover
|
|
17
|
+
import json # type: ignore[no-redef]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AsyncRedisCacheBackend(BaseCacheBackend):
|
|
21
|
+
"""Async Redis cache backend implementation."""
|
|
22
|
+
|
|
23
|
+
client: "AsyncRedis[str]"
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
host: str = "127.0.0.1",
|
|
28
|
+
port: int = 6379,
|
|
29
|
+
password: Optional[str] = None,
|
|
30
|
+
db: int = 0,
|
|
31
|
+
encoding: str = "utf-8",
|
|
32
|
+
decode_responses: Literal[True] = True,
|
|
33
|
+
socket_timeout: float = 1.0,
|
|
34
|
+
socket_connect_timeout: float = 1.0,
|
|
35
|
+
**kwargs: Any,
|
|
36
|
+
) -> None:
|
|
37
|
+
"""Initialize async Redis cache backend.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
host: Redis host
|
|
41
|
+
port: Redis port
|
|
42
|
+
password: Redis password
|
|
43
|
+
db: Redis database number
|
|
44
|
+
encoding: Character encoding to use
|
|
45
|
+
decode_responses: Whether to decode response automatically
|
|
46
|
+
socket_timeout: Timeout for socket operations (in seconds)
|
|
47
|
+
socket_connect_timeout: Timeout for socket connection (in seconds)
|
|
48
|
+
**kwargs: Additional arguments to pass to Redis client
|
|
49
|
+
"""
|
|
50
|
+
try:
|
|
51
|
+
from redis.asyncio import Redis as AsyncRedis
|
|
52
|
+
except ImportError:
|
|
53
|
+
raise CacheXError(
|
|
54
|
+
"redis[hiredis] is not installed. Please install it with 'pip install \"redis[hiredis]\"'"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
self.client = AsyncRedis(
|
|
58
|
+
host=host,
|
|
59
|
+
port=port,
|
|
60
|
+
password=password,
|
|
61
|
+
db=db,
|
|
62
|
+
encoding=encoding,
|
|
63
|
+
decode_responses=decode_responses,
|
|
64
|
+
socket_timeout=socket_timeout,
|
|
65
|
+
socket_connect_timeout=socket_connect_timeout,
|
|
66
|
+
**kwargs,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def _serialize(self, value: ETagContent) -> str:
|
|
70
|
+
"""Serialize ETagContent to JSON string."""
|
|
71
|
+
serialized = json.dumps(
|
|
72
|
+
{
|
|
73
|
+
"etag": value.etag,
|
|
74
|
+
"content": value.content.decode()
|
|
75
|
+
if isinstance(value.content, bytes)
|
|
76
|
+
else value.content,
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if isinstance(serialized, bytes):
|
|
81
|
+
# If using orjson, it returns bytes
|
|
82
|
+
return serialized.decode()
|
|
83
|
+
|
|
84
|
+
return serialized # type: ignore[unreachable]
|
|
85
|
+
|
|
86
|
+
def _deserialize(self, value: Optional[str]) -> Optional[ETagContent]:
|
|
87
|
+
"""Deserialize JSON string to ETagContent."""
|
|
88
|
+
if value is None:
|
|
89
|
+
return None
|
|
90
|
+
try:
|
|
91
|
+
data = json.loads(value)
|
|
92
|
+
return ETagContent(
|
|
93
|
+
etag=data["etag"],
|
|
94
|
+
content=data["content"].encode()
|
|
95
|
+
if isinstance(data["content"], str)
|
|
96
|
+
else data["content"],
|
|
97
|
+
)
|
|
98
|
+
except (json.JSONDecodeError, KeyError):
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
async def get(self, key: str) -> Optional[ETagContent]:
|
|
102
|
+
"""Retrieve a cached response."""
|
|
103
|
+
result = await self.client.get(key)
|
|
104
|
+
return self._deserialize(result)
|
|
105
|
+
|
|
106
|
+
async def set(
|
|
107
|
+
self, key: str, value: ETagContent, ttl: Optional[int] = None
|
|
108
|
+
) -> None:
|
|
109
|
+
"""Store a response in the cache."""
|
|
110
|
+
serialized = self._serialize(value)
|
|
111
|
+
if ttl is not None:
|
|
112
|
+
await self.client.setex(key, ttl, serialized)
|
|
113
|
+
else:
|
|
114
|
+
await self.client.set(key, serialized)
|
|
115
|
+
|
|
116
|
+
async def delete(self, key: str) -> None:
|
|
117
|
+
"""Remove a response from the cache."""
|
|
118
|
+
await self.client.delete(key)
|
|
119
|
+
|
|
120
|
+
async def clear(self) -> None:
|
|
121
|
+
"""Clear all cached responses."""
|
|
122
|
+
await self.client.flushdb()
|
|
123
|
+
|
|
124
|
+
async def clear_path(self, path: str, include_params: bool = False) -> int:
|
|
125
|
+
"""Clear cached responses for a specific path."""
|
|
126
|
+
pattern = f"{path}*" if include_params else path
|
|
127
|
+
keys = await self.client.keys(pattern)
|
|
128
|
+
if keys:
|
|
129
|
+
return await self.client.delete(*keys)
|
|
130
|
+
return 0
|
|
131
|
+
|
|
132
|
+
async def clear_pattern(self, pattern: str) -> int:
|
|
133
|
+
"""Clear cached responses matching a pattern."""
|
|
134
|
+
keys = await self.client.keys(pattern)
|
|
135
|
+
if keys:
|
|
136
|
+
return await self.client.delete(*keys)
|
|
137
|
+
return 0
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from typing import Annotated
|
|
2
|
+
|
|
3
|
+
from fastapi import Depends
|
|
4
|
+
|
|
5
|
+
from fastapi_cachex.backends.base import BaseCacheBackend
|
|
6
|
+
from fastapi_cachex.proxy import BackendProxy
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_cache_backend() -> BaseCacheBackend:
|
|
10
|
+
"""Dependency to get the current cache backend instance."""
|
|
11
|
+
return BackendProxy.get_backend()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
CacheBackend = Annotated[BaseCacheBackend, Depends(get_cache_backend)]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-cachex
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
4
|
Summary: A caching library for FastAPI with support for Cache-Control, ETag, and multiple backends.
|
|
5
5
|
Author-email: Allen <s96016641@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -24,9 +24,11 @@ Requires-Python: >=3.10
|
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
25
25
|
License-File: LICENSE
|
|
26
26
|
Requires-Dist: fastapi
|
|
27
|
-
Requires-Dist: httpx
|
|
28
27
|
Provides-Extra: memcache
|
|
29
28
|
Requires-Dist: pymemcache; extra == "memcache"
|
|
29
|
+
Provides-Extra: redis
|
|
30
|
+
Requires-Dist: redis[hiredis]; extra == "redis"
|
|
31
|
+
Requires-Dist: orjson; extra == "redis"
|
|
30
32
|
Dynamic: license-file
|
|
31
33
|
|
|
32
34
|
# FastAPI-Cache X
|
|
@@ -34,7 +36,7 @@ Dynamic: license-file
|
|
|
34
36
|
[](https://github.com/astral-sh/uv)
|
|
35
37
|
[](https://github.com/astral-sh/ruff)
|
|
36
38
|
[](https://github.com/allen0099/FastAPI-CacheX/actions/workflows/test.yml)
|
|
37
|
-
[](https://github.com/allen0099/FastAPI-CacheX/actions/workflows/
|
|
39
|
+
[](https://github.com/allen0099/FastAPI-CacheX/actions/workflows/coverage.yml)
|
|
38
40
|
|
|
39
41
|
[](https://pepy.tech/project/fastapi-cachex)
|
|
40
42
|
[](https://pepy.tech/project/fastapi-cachex)
|
|
@@ -60,6 +62,24 @@ A high-performance caching extension for FastAPI, providing comprehensive HTTP c
|
|
|
60
62
|
- Complete Cache-Control directive implementation
|
|
61
63
|
- Easy-to-use `@cache` decorator
|
|
62
64
|
|
|
65
|
+
### Cache-Control Directives
|
|
66
|
+
|
|
67
|
+
| Directive | Supported | Description |
|
|
68
|
+
|--------------------------|--------------------|---------------------------------------------------------------------------------------------------------|
|
|
69
|
+
| `max-age` | :white_check_mark: | Specifies the maximum amount of time a resource is considered fresh. |
|
|
70
|
+
| `s-maxage` | :x: | Specifies the maximum amount of time a resource is considered fresh for shared caches. |
|
|
71
|
+
| `no-cache` | :white_check_mark: | Forces caches to submit the request to the origin server for validation before releasing a cached copy. |
|
|
72
|
+
| `no-store` | :white_check_mark: | Instructs caches not to store any part of the request or response. |
|
|
73
|
+
| `no-transform` | :x: | Instructs caches not to transform the response content. |
|
|
74
|
+
| `must-revalidate` | :white_check_mark: | Forces caches to revalidate the response with the origin server after it becomes stale. |
|
|
75
|
+
| `proxy-revalidate` | :x: | Similar to `must-revalidate`, but only for shared caches. |
|
|
76
|
+
| `must-understand` | :x: | Indicates that the recipient must understand the directive or treat it as an error. |
|
|
77
|
+
| `private` | :white_check_mark: | Indicates that the response is intended for a single user and should not be stored by shared caches. |
|
|
78
|
+
| `public` | :white_check_mark: | Indicates that the response may be cached by any cache, even if it is normally non-cacheable. |
|
|
79
|
+
| `immutable` | :white_check_mark: | Indicates that the response body will not change over time, allowing for longer caching. |
|
|
80
|
+
| `stale-while-revalidate` | :white_check_mark: | Indicates that a cache can serve a stale response while it revalidates the response in the background. |
|
|
81
|
+
| `stale-if-error` | :white_check_mark: | Indicates that a cache can serve a stale response if the origin server is unavailable. |
|
|
82
|
+
|
|
63
83
|
## Installation
|
|
64
84
|
|
|
65
85
|
### Using pip
|
|
@@ -78,31 +98,44 @@ uv pip install fastapi-cachex
|
|
|
78
98
|
|
|
79
99
|
```python
|
|
80
100
|
from fastapi import FastAPI
|
|
81
|
-
from fastapi_cachex import cache
|
|
82
|
-
from fastapi_cachex
|
|
101
|
+
from fastapi_cachex import cache
|
|
102
|
+
from fastapi_cachex import CacheBackend
|
|
83
103
|
|
|
84
104
|
app = FastAPI()
|
|
85
105
|
|
|
86
|
-
# Configure your cache backend
|
|
87
|
-
memory_backend = MemoryBackend() # In-memory cache
|
|
88
|
-
# or
|
|
89
|
-
memcached_backend = MemcachedBackend(servers=["localhost:11211"]) # Memcached
|
|
90
|
-
|
|
91
|
-
# Set the backend you want to use
|
|
92
|
-
BackendProxy.set_backend(memory_backend) # or memcached_backend
|
|
93
|
-
|
|
94
106
|
|
|
95
107
|
@app.get("/")
|
|
96
108
|
@cache(ttl=60) # Cache for 60 seconds
|
|
97
109
|
async def read_root():
|
|
98
110
|
return {"Hello": "World"}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@app.get("/no-cache")
|
|
114
|
+
@cache(no_cache=True) # Mark this endpoint as non-cacheable
|
|
115
|
+
async def non_cache_endpoint():
|
|
116
|
+
return {"Hello": "World"}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@app.get("/no-store")
|
|
120
|
+
@cache(no_store=True) # Mark this endpoint as non-cacheable
|
|
121
|
+
async def non_store_endpoint():
|
|
122
|
+
return {"Hello": "World"}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@app.get("/clear_cache")
|
|
126
|
+
async def remove_cache(cache: CacheBackend):
|
|
127
|
+
await cache.clear_path("/path/to/clear") # Clear cache for a specific path
|
|
128
|
+
await cache.clear_pattern("/path/to/clear/*") # Clear cache for a specific pattern
|
|
99
129
|
```
|
|
100
130
|
|
|
101
131
|
## Backend Configuration
|
|
102
132
|
|
|
103
133
|
FastAPI-CacheX supports multiple caching backends. You can easily switch between them using the `BackendProxy`.
|
|
104
134
|
|
|
105
|
-
### In-Memory Cache
|
|
135
|
+
### In-Memory Cache (default)
|
|
136
|
+
|
|
137
|
+
If you don't specify a backend, FastAPI-CacheX will use the in-memory cache by default.
|
|
138
|
+
This is suitable for development and testing purposes.
|
|
106
139
|
|
|
107
140
|
```python
|
|
108
141
|
from fastapi_cachex.backends import MemoryBackend
|
|
@@ -122,9 +155,15 @@ backend = MemcachedBackend(servers=["localhost:11211"])
|
|
|
122
155
|
BackendProxy.set_backend(backend)
|
|
123
156
|
```
|
|
124
157
|
|
|
125
|
-
### Redis
|
|
158
|
+
### Redis
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
from fastapi_cachex.backends import AsyncRedisCacheBackend
|
|
162
|
+
from fastapi_cachex import BackendProxy
|
|
126
163
|
|
|
127
|
-
|
|
164
|
+
backend = AsyncRedisCacheBackend(host="127.0.1", port=6379, db=0)
|
|
165
|
+
BackendProxy.set_backend(backend)
|
|
166
|
+
```
|
|
128
167
|
|
|
129
168
|
## Documentation
|
|
130
169
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
fastapi_cachex/__init__.py,sha256=_g7ewsAAjvbeMoDOttsfSD-G5ebPCN7MVPl-p2fY0tU,202
|
|
2
|
+
fastapi_cachex/cache.py,sha256=b-55IR0kdcVj4yUk8dplqqUy2avW49P-oI01ART9pyU,9174
|
|
3
|
+
fastapi_cachex/dependencies.py,sha256=K4565NSU7j8ktqe5ib_hs-fBB6IbIrM0nw6pTHpjLc4,385
|
|
4
|
+
fastapi_cachex/directives.py,sha256=kJCmsbyQ89m6tsWo_c1vVJn3rk0pD5JZaY8xtNLcRh0,530
|
|
5
|
+
fastapi_cachex/exceptions.py,sha256=coYct4u6uK_pdjetUWDwM5OUCfhql0OkTECynMRUq4M,379
|
|
6
|
+
fastapi_cachex/proxy.py,sha256=vFShY7_xp4Sh1XU9dJzsBv2ICN8Rtwx6g1qCcCvmdf8,810
|
|
7
|
+
fastapi_cachex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
fastapi_cachex/types.py,sha256=YkXlBARIr5lHQE4PYQrwXjEoLHdz9CIjfX7V-S9N8p0,328
|
|
9
|
+
fastapi_cachex/backends/__init__.py,sha256=KJHzYs2NZLl-LDAz-VIynaDhZ8XCXKrcnVG-j3sYMRI,357
|
|
10
|
+
fastapi_cachex/backends/base.py,sha256=oBoHUaejZNQ_ex1n1YrpUP4CU94w2TbsXd6qau0F_T8,1383
|
|
11
|
+
fastapi_cachex/backends/memcached.py,sha256=vy7isgu2qW2odBPTl8Q8ulqUo36KIsnZ3YVCr3sflfc,3211
|
|
12
|
+
fastapi_cachex/backends/memory.py,sha256=4TBdvxnjMY0BnN1Gjr93rJllWJjU055RxG12QJixrrM,3611
|
|
13
|
+
fastapi_cachex/backends/redis.py,sha256=bCfF0GHBaLXkfQiwciaAtZFD0fWCcv0wNihuDGzdtUI,4489
|
|
14
|
+
fastapi_cachex-0.1.6.dist-info/licenses/LICENSE,sha256=asJkHbd10YDSnjeAOIlKafh7E_exwtKXY5rA-qc_Mno,11339
|
|
15
|
+
fastapi_cachex-0.1.6.dist-info/METADATA,sha256=6f_-B8g8b6DoEWK-GXNoGjQ5cWplWw59wTw9AQyjqZE,7634
|
|
16
|
+
fastapi_cachex-0.1.6.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
17
|
+
fastapi_cachex-0.1.6.dist-info/top_level.txt,sha256=97FfG5FDycd3hks-_JznEr-5lUOgg8AZd8pqK5imWj0,15
|
|
18
|
+
fastapi_cachex-0.1.6.dist-info/RECORD,,
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
fastapi_cachex/__init__.py,sha256=K8zRD7pEOo77Ged7SJQ-BFNMe6Pnz8yM5ePFq97nI_s,82
|
|
2
|
-
fastapi_cachex/cache.py,sha256=b-55IR0kdcVj4yUk8dplqqUy2avW49P-oI01ART9pyU,9174
|
|
3
|
-
fastapi_cachex/directives.py,sha256=kJCmsbyQ89m6tsWo_c1vVJn3rk0pD5JZaY8xtNLcRh0,530
|
|
4
|
-
fastapi_cachex/exceptions.py,sha256=coYct4u6uK_pdjetUWDwM5OUCfhql0OkTECynMRUq4M,379
|
|
5
|
-
fastapi_cachex/proxy.py,sha256=vFShY7_xp4Sh1XU9dJzsBv2ICN8Rtwx6g1qCcCvmdf8,810
|
|
6
|
-
fastapi_cachex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
-
fastapi_cachex/types.py,sha256=YkXlBARIr5lHQE4PYQrwXjEoLHdz9CIjfX7V-S9N8p0,328
|
|
8
|
-
fastapi_cachex/backends/__init__.py,sha256=U65JrCeh1eusklqUfV5yvZGK7Kfy5RctzfVrRfFPuaI,166
|
|
9
|
-
fastapi_cachex/backends/base.py,sha256=eGfn0oZNQ8_drNHz4ZtqBVFSxKxEwW8y4ojw5iShgLQ,707
|
|
10
|
-
fastapi_cachex/backends/memcached.py,sha256=g3184fHpFK7LH1UY9xfzRszBBzqmzeaLG806B5MsZDM,2190
|
|
11
|
-
fastapi_cachex/backends/memory.py,sha256=7KFSn5e1CvDzflZ5zqUPDQsBf6emcV0ob_tCsLQcDLw,2445
|
|
12
|
-
fastapi_cachex-0.1.4.dist-info/licenses/LICENSE,sha256=asJkHbd10YDSnjeAOIlKafh7E_exwtKXY5rA-qc_Mno,11339
|
|
13
|
-
fastapi_cachex-0.1.4.dist-info/METADATA,sha256=6qK6F6Pi338JYWN0NEv5SnR8gN4eJaXyFntNmFAu57s,4669
|
|
14
|
-
fastapi_cachex-0.1.4.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
15
|
-
fastapi_cachex-0.1.4.dist-info/top_level.txt,sha256=97FfG5FDycd3hks-_JznEr-5lUOgg8AZd8pqK5imWj0,15
|
|
16
|
-
fastapi_cachex-0.1.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|