cachekit 0.17.1__tar.gz → 0.19.0__tar.gz
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.
- {cachekit-0.17.1 → cachekit-0.19.0}/Cargo.lock +4 -3
- {cachekit-0.17.1 → cachekit-0.19.0}/PKG-INFO +49 -22
- {cachekit-0.17.1 → cachekit-0.19.0}/README.md +43 -18
- {cachekit-0.17.1 → cachekit-0.19.0}/pyproject.toml +47 -19
- {cachekit-0.17.1 → cachekit-0.19.0}/rust/Cargo.toml +7 -3
- {cachekit-0.17.1 → cachekit-0.19.0}/rust/README.md +43 -18
- {cachekit-0.17.1 → cachekit-0.19.0}/rust/TEST_EXPANSION_SUMMARY.md +2 -2
- cachekit-0.19.0/rust/src/lib.rs +84 -0
- cachekit-0.19.0/rust/src/msgpack_bounds.rs +87 -0
- cachekit-0.19.0/rust/src/python_bindings.rs +636 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/__init__.py +8 -7
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/base.py +13 -7
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/cachekitio/backend.py +72 -20
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/cachekitio/error_handler.py +11 -6
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/errors.py +11 -4
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/file/backend.py +118 -34
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/memcached/backend.py +4 -1
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/memcached/error_handler.py +18 -8
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/provider.py +10 -8
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/redis/backend.py +5 -5
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/redis/error_handler.py +12 -7
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/redis/provider.py +25 -11
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/cache_handler.py +250 -109
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/config/decorator.py +0 -6
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/config/nested.py +0 -2
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/config/settings.py +170 -2
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/decorators/intent.py +5 -1
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/decorators/orchestrator.py +26 -9
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/decorators/session.py +16 -8
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/decorators/wrapper.py +294 -106
- cachekit-0.19.0/src/cachekit/hash_utils.py +146 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/hiredis_compat.py +5 -3
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/interop.py +2 -4
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/key_generator.py +14 -8
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/l1_cache.py +18 -205
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/logging.py +30 -129
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/monitoring/pool_monitor.py +5 -5
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/object_cache.py +1 -1
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/reliability/async_metrics.py +4 -2
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/reliability/metrics_collection.py +47 -32
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/reliability/profiles.py +0 -14
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/serializers/__init__.py +10 -3
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/serializers/auto_serializer.py +237 -122
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/serializers/base.py +119 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/serializers/encryption_wrapper.py +245 -16
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/serializers/orjson_serializer.py +1 -1
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/serializers/standard_serializer.py +17 -7
- cachekit-0.17.1/rust/src/lib.rs +0 -61
- cachekit-0.17.1/rust/src/python_bindings.rs +0 -400
- cachekit-0.17.1/rust/supply-chain/audits.toml +0 -4
- cachekit-0.17.1/rust/supply-chain/config.toml +0 -1341
- cachekit-0.17.1/rust/supply-chain/imports.lock +0 -2
- cachekit-0.17.1/src/cachekit/hash_utils.py +0 -50
- {cachekit-0.17.1 → cachekit-0.19.0}/Cargo.toml +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/LICENSE +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/rust/Makefile +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/rust/tsan_suppressions.txt +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/__init__.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/base_config.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/cachekitio/__init__.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/cachekitio/client.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/cachekitio/config.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/cachekitio/session.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/file/__init__.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/file/config.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/memcached/__init__.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/memcached/config.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/redis/__init__.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/redis/client.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/backends/redis/config.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/config/__init__.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/config/singleton.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/config/validation.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/decorators/__init__.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/decorators/local_wrapper.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/decorators/main.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/decorators/stats_context.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/decorators/tenant_context.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/decorators/utils/__init__.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/di.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/health.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/imports.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/monitoring/__init__.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/monitoring/correlation_tracking.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/monitoring/protocols.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/py.typed +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/reliability/__init__.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/reliability/circuit_breaker.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/reliability/error_classification.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/reliability/load_control.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/serializers/arrow_serializer.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/serializers/interop_serializer.py +0 -0
- {cachekit-0.17.1 → cachekit-0.19.0}/src/cachekit/serializers/wrapper.py +0 -0
|
@@ -245,9 +245,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
|
|
|
245
245
|
|
|
246
246
|
[[package]]
|
|
247
247
|
name = "cachekit-core"
|
|
248
|
-
version = "0.
|
|
248
|
+
version = "0.5.0"
|
|
249
249
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
250
|
-
checksum = "
|
|
250
|
+
checksum = "12089baacc5ff661a62d2071588c895973bc48e42ed359178afaee22decb5559"
|
|
251
251
|
dependencies = [
|
|
252
252
|
"aes",
|
|
253
253
|
"aes-gcm",
|
|
@@ -271,7 +271,7 @@ dependencies = [
|
|
|
271
271
|
|
|
272
272
|
[[package]]
|
|
273
273
|
name = "cachekit-rs"
|
|
274
|
-
version = "0.
|
|
274
|
+
version = "0.19.0"
|
|
275
275
|
dependencies = [
|
|
276
276
|
"cachekit-core",
|
|
277
277
|
"criterion",
|
|
@@ -282,6 +282,7 @@ dependencies = [
|
|
|
282
282
|
"pprof",
|
|
283
283
|
"proptest",
|
|
284
284
|
"pyo3",
|
|
285
|
+
"zeroize",
|
|
285
286
|
]
|
|
286
287
|
|
|
287
288
|
[[package]]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cachekit
|
|
3
|
-
Version: 0.
|
|
4
|
-
Classifier: Development Status ::
|
|
3
|
+
Version: 0.19.0
|
|
4
|
+
Classifier: Development Status :: 4 - Beta
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
|
7
7
|
Classifier: Operating System :: OS Independent
|
|
@@ -21,13 +21,15 @@ Classifier: Framework :: AsyncIO
|
|
|
21
21
|
Classifier: Typing :: Typed
|
|
22
22
|
Requires-Dist: redis[hiredis]>=4.0.0
|
|
23
23
|
Requires-Dist: pydantic>=2.0.0
|
|
24
|
-
Requires-Dist: pydantic-settings>=2.
|
|
24
|
+
Requires-Dist: pydantic-settings>=2.7.0
|
|
25
25
|
Requires-Dist: prometheus-client>=0.22.1
|
|
26
26
|
Requires-Dist: psutil>=7.0.0
|
|
27
27
|
Requires-Dist: blake3>=1.0.5
|
|
28
28
|
Requires-Dist: msgpack>=1.2.1
|
|
29
29
|
Requires-Dist: xxhash>=3.5.0
|
|
30
30
|
Requires-Dist: httpx[http2]>=0.28.1
|
|
31
|
+
Requires-Dist: anyio>=4.14.2
|
|
32
|
+
Requires-Dist: h2>=4.4.1
|
|
31
33
|
Requires-Dist: numpy>=2.0.2 ; extra == 'data'
|
|
32
34
|
Requires-Dist: pandas>=1.3.0 ; extra == 'data'
|
|
33
35
|
Requires-Dist: pyarrow>=21.0.0 ; extra == 'data'
|
|
@@ -37,7 +39,7 @@ Provides-Extra: data
|
|
|
37
39
|
Provides-Extra: json
|
|
38
40
|
Provides-Extra: memcached
|
|
39
41
|
License-File: LICENSE
|
|
40
|
-
Summary:
|
|
42
|
+
Summary: Backend-agnostic caching for Python — intent-based decorators with circuit breaker, distributed locking, Prometheus metrics, and optional zero-knowledge AES-256-GCM encryption, on a Rust-powered core. Zero-config L1 in-memory; scales to Redis, Memcached, File, or CachekitIO.
|
|
41
43
|
Keywords: redis,cache,caching,decorator,rust,performance,reliability,production,encryption,security,circuit-breaker,prometheus,messagepack,distributed-locking
|
|
42
44
|
Home-Page: https://github.com/cachekit-io/cachekit-py
|
|
43
45
|
Author-email: cachekit Contributors <noreply@cachekit.io>
|
|
@@ -57,7 +59,7 @@ Project-URL: Repository, https://github.com/cachekit-io/cachekit-py.git
|
|
|
57
59
|
|
|
58
60
|
> **Python caching, batteries included**
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
Backend-agnostic caching with intent-based decorators — circuit breaker, distributed locking, Prometheus metrics, and optional zero-knowledge encryption on a Rust-powered core. Zero config to start, any backend when you scale.
|
|
61
63
|
|
|
62
64
|
[![PyPI Version][pypi-badge]][pypi-url]
|
|
63
65
|
[![Python Versions][python-badge]][pypi-url]
|
|
@@ -68,20 +70,16 @@ Production-ready caching for Python with intelligent reliability features and Ru
|
|
|
68
70
|
|
|
69
71
|
---
|
|
70
72
|
|
|
71
|
-
> [!
|
|
72
|
-
> **
|
|
73
|
-
>
|
|
74
|
-
> 🐛 **Found a bug?** Please [open an issue][issues-url] — even small ones help us improve.
|
|
75
|
-
>
|
|
76
|
-
> 💡 **Something feel off?** We want to hear about rough edges, confusing APIs, or missing features.
|
|
73
|
+
> [!NOTE]
|
|
74
|
+
> **Status: beta** — CacheKit is in closed beta ahead of 1.0. APIs are stabilising; minor breaking changes may still occur between 0.x releases.
|
|
77
75
|
>
|
|
78
|
-
>
|
|
76
|
+
> 🐛 **Found a bug or a rough edge?** Please [open an issue][issues-url] — your feedback directly shapes the path to 1.0.
|
|
79
77
|
|
|
80
78
|
---
|
|
81
79
|
|
|
82
80
|
## Why cachekit?
|
|
83
81
|
|
|
84
|
-
**Simple to use,
|
|
82
|
+
**Simple to use, works out of the box.**
|
|
85
83
|
|
|
86
84
|
```python
|
|
87
85
|
from cachekit import cache
|
|
@@ -125,7 +123,7 @@ backend that fits your infrastructure — they're peers behind the same `@cache`
|
|
|
125
123
|
| Backend | Best for | Select with |
|
|
126
124
|
|---------|----------|-------------|
|
|
127
125
|
| Redis | Self-hosted, full control | `REDIS_URL` / `CACHEKIT_REDIS_URL` |
|
|
128
|
-
| CachekitIO | Managed, zero-ops (
|
|
126
|
+
| CachekitIO | Managed, zero-ops (beta) | `CACHEKIT_API_KEY` |
|
|
129
127
|
| Memcached | High-throughput, existing infra | `CACHEKIT_MEMCACHED_SERVERS` |
|
|
130
128
|
| File / L1-only | Local dev, tests, no external deps | `CACHEKIT_FILE_CACHE_DIR` / `backend=None` |
|
|
131
129
|
|
|
@@ -148,7 +146,7 @@ def expensive_api_call(user_id: int):
|
|
|
148
146
|
### More Backends
|
|
149
147
|
|
|
150
148
|
<details>
|
|
151
|
-
<summary><strong>CachekitIO — Managed SaaS (
|
|
149
|
+
<summary><strong>CachekitIO — Managed SaaS (Beta)</strong></summary>
|
|
152
150
|
|
|
153
151
|
```python notest
|
|
154
152
|
import os
|
|
@@ -162,7 +160,7 @@ def expensive_api_call(user_id: int):
|
|
|
162
160
|
return fetch_user_data(user_id)
|
|
163
161
|
```
|
|
164
162
|
|
|
165
|
-
*cachekit.io is in closed
|
|
163
|
+
*cachekit.io is in closed beta — [request access](https://cachekit.io) to get started.*
|
|
166
164
|
|
|
167
165
|
</details>
|
|
168
166
|
|
|
@@ -188,9 +186,9 @@ def expensive_api_call(user_id: int):
|
|
|
188
186
|
|
|
189
187
|
---
|
|
190
188
|
|
|
191
|
-
> **CachekitIO Cloud (
|
|
189
|
+
> **CachekitIO Cloud (Beta)**
|
|
192
190
|
> Managed caching with zero infrastructure. L1+L2 caching, circuit breaker, and automatic failover — no Redis to manage.
|
|
193
|
-
> *cachekit.io is in closed
|
|
191
|
+
> *cachekit.io is in closed beta — [request access](https://cachekit.io) to get started.*
|
|
194
192
|
|
|
195
193
|
---
|
|
196
194
|
|
|
@@ -221,9 +219,8 @@ def get_user_profile(user_id: int):
|
|
|
221
219
|
| Backpressure | ✅ | ✅ | - | ✅ | ✅ |
|
|
222
220
|
| Integrity Checking | - | ✅ | - | ✅ | ✅ 🔒 |
|
|
223
221
|
| Encryption | - | - | - | - | ✅ Required |
|
|
224
|
-
| L1 SWR | - | ✅ | - | ✅ | ✅ |
|
|
222
|
+
| L1 SWR (L1-only mode) | - | ✅ | - | ✅ | ✅ |
|
|
225
223
|
| L1 Invalidation | - | - | - | ✅ | ✅ |
|
|
226
|
-
| L1 Namespace Index | - | - | - | ✅ | ✅ |
|
|
227
224
|
| Prometheus Metrics | - | - | - | ✅ | ✅ |
|
|
228
225
|
| Tracing | - | ✅ | - | ✅ | ✅ |
|
|
229
226
|
| Structured Logging | - | ✅ | - | ✅ | ✅ |
|
|
@@ -231,6 +228,8 @@ def get_user_profile(user_id: int):
|
|
|
231
228
|
|
|
232
229
|
> 🔒 `@cache.secure` forces `integrity_checking=True` — it cannot be overridden.
|
|
233
230
|
>
|
|
231
|
+
> **L1 SWR** (within-TTL background refresh) runs only in L1-only mode (`backend=None`) — with a backend configured it has no effect. `@cache.io` additionally ships past-TTL SWR via `stale_ttl` ([docs](docs/configuration.md#stale-while-revalidate-stale_ttl)).
|
|
232
|
+
>
|
|
234
233
|
> **`@cache.io()`** mirrors `@cache.production` (full reliability + observability) but routes to the managed CachekitIO SaaS backend instead of Redis. **`@cache.local()`** is a separate in-process path backed by `ObjectCache` (raw object references, entry-count LRU, no serialization) — the reliability and encryption features listed above do not apply to it.
|
|
235
234
|
|
|
236
235
|
<details>
|
|
@@ -291,6 +290,7 @@ def test_cached_function():
|
|
|
291
290
|
- Connection pooling with thread affinity (+28% throughput)
|
|
292
291
|
- Distributed locking prevents cache stampedes
|
|
293
292
|
- Pluggable backend abstraction (Redis, CachekitIO, File, Memcached, custom)
|
|
293
|
+
- Untrusted-decode bounds: nesting depth and header-declared allocation are capped on every cache read (a forged entry is a bounded cache miss), verified against the protocol's shared [`decode-bounds.json`](https://github.com/cachekit-io/protocol/blob/2d56cce231e193141f09df9316f9afac17a1538e/test-vectors/decode-bounds.json) vectors
|
|
294
294
|
|
|
295
295
|
> [!NOTE]
|
|
296
296
|
> All reliability features are **enabled by default** with `@cache.production`. Use `@cache.minimal` to disable them for maximum throughput.
|
|
@@ -346,9 +346,15 @@ def get_patient_data(hospital_id: int):
|
|
|
346
346
|
> [!CAUTION]
|
|
347
347
|
> When handling PII, medical, or financial data, always use `@cache.secure` to enforce encryption.
|
|
348
348
|
|
|
349
|
+
**Zero-downtime key rotation**: promote a new `CACHEKIT_MASTER_KEY` and keep the
|
|
350
|
+
retiring key readable via `CACHEKIT_PREVIOUS_MASTER_KEYS` (comma-separated hex,
|
|
351
|
+
max 3 decrypt-only keys). Entries are selected by exact key fingerprint — never
|
|
352
|
+
trial decryption — and old entries age out via TTL, no cache flush required. See
|
|
353
|
+
[Zero-Knowledge Encryption](docs/features/zero-knowledge-encryption.md#key-rotation-pattern).
|
|
354
|
+
|
|
349
355
|
cachekit employs comprehensive security tooling:
|
|
350
356
|
|
|
351
|
-
- **
|
|
357
|
+
- **Dependency Security**: cargo-deny for license compliance + cargo-audit for RustSec scanning
|
|
352
358
|
- **Formal Verification**: Kani proves correctness of compression, checksums, encryption
|
|
353
359
|
- **Runtime Analysis**: Miri + sanitizers for memory safety
|
|
354
360
|
- **Fuzzing**: Coverage-guided testing with >80% code coverage
|
|
@@ -408,6 +414,15 @@ exposition setup.
|
|
|
408
414
|
<details>
|
|
409
415
|
<summary><strong>Thread Safety Details</strong></summary>
|
|
410
416
|
|
|
417
|
+
**Free-threaded CPython (3.14t):** the core suites run green on
|
|
418
|
+
free-threaded 3.14 with the GIL verified disabled (CI job
|
|
419
|
+
`test-freethreaded`), and the Rust extension declares free-threaded safety
|
|
420
|
+
(`gil_used = false`). Free-threaded wheels are **not yet published** and
|
|
421
|
+
free-threaded builds are not officially supported — blocked on upstream
|
|
422
|
+
wheels (orjson, hiredis; numpy/pandas/pyarrow for `[data]`). See
|
|
423
|
+
[measured performance results](docs/free-threading.md#measured-performance) and the
|
|
424
|
+
full concurrency audit: [docs/free-threading.md](docs/free-threading.md).
|
|
425
|
+
|
|
411
426
|
**Per-Function Statistics:**
|
|
412
427
|
- Statistics tracked per function identity (`module.qualname`), shared across all calls and across re-decorations of the same function
|
|
413
428
|
- Thread-safe via RLock (all methods safe for concurrent access)
|
|
@@ -443,6 +458,7 @@ info = expensive_func.cache_info()
|
|
|
443
458
|
| [Comparison Guide][comparison-url] | How cachekit compares to lru_cache, aiocache, cachetools |
|
|
444
459
|
| [Getting Started][getting-started-url] | Progressive tutorial from basics to advanced |
|
|
445
460
|
| [API Reference][api-reference-url] | Complete API documentation |
|
|
461
|
+
| [Skyline (live example)][skyline-url] | Canonical example project: this SDK ingests the Bluesky firehose and writes the analytics entries a TypeScript edge Worker serves live, on one shared interop namespace |
|
|
446
462
|
|
|
447
463
|
### Feature Deep Dives
|
|
448
464
|
|
|
@@ -453,6 +469,11 @@ info = expensive_func.cache_info()
|
|
|
453
469
|
| [Distributed Locking][distributed-locking-url] | Cache stampede prevention |
|
|
454
470
|
| [Prometheus Metrics][prometheus-url] | Built-in observability |
|
|
455
471
|
| [Zero-Knowledge Encryption][encryption-url] | Client-side security |
|
|
472
|
+
| [Interop Mode][interop-url] | Cross-SDK cache sharing with cachekit-ts/rs |
|
|
473
|
+
| [L1 Invalidation & SWR][l1-invalidation-url] | Process-local invalidation, stale-while-revalidate |
|
|
474
|
+
| [Reference Caching][reference-caching-url] | `@cache.local()` for non-serializable objects |
|
|
475
|
+
| [Rust Serialization][rust-serialization-url] | ByteStorage layer: LZ4, xxHash3, AES-256-GCM |
|
|
476
|
+
| [SSRF Protection][ssrf-url] | URL allowlisting for the CachekitIO backend |
|
|
456
477
|
|
|
457
478
|
---
|
|
458
479
|
|
|
@@ -465,7 +486,7 @@ info = expensive_func.cache_info()
|
|
|
465
486
|
CACHEKIT_REDIS_URL="redis://localhost:6379" # Primary (preferred)
|
|
466
487
|
REDIS_URL="redis://localhost:6379" # Fallback
|
|
467
488
|
|
|
468
|
-
# CachekitIO SaaS Backend (closed
|
|
489
|
+
# CachekitIO SaaS Backend (closed beta — request access at cachekit.io)
|
|
469
490
|
CACHEKIT_API_KEY="your-api-key" # Required for @cache.io() # pragma: allowlist secret
|
|
470
491
|
CACHEKIT_API_URL="https://api.cachekit.io" # Default SaaS endpoint
|
|
471
492
|
|
|
@@ -528,6 +549,7 @@ MIT License - see [LICENSE][license-file-url] for details.
|
|
|
528
549
|
[uv-url]: https://github.com/astral-sh/uv
|
|
529
550
|
[security-url]: SECURITY.md
|
|
530
551
|
[comparison-url]: docs/comparison.md
|
|
552
|
+
[skyline-url]: https://github.com/cachekit-io/bluesky-thinking
|
|
531
553
|
[getting-started-url]: docs/getting-started.md
|
|
532
554
|
[api-reference-url]: docs/api-reference.md
|
|
533
555
|
[serializer-guide-url]: docs/serializers/index.md
|
|
@@ -535,6 +557,11 @@ MIT License - see [LICENSE][license-file-url] for details.
|
|
|
535
557
|
[distributed-locking-url]: docs/features/distributed-locking.md
|
|
536
558
|
[prometheus-url]: docs/features/prometheus-metrics.md
|
|
537
559
|
[encryption-url]: docs/features/zero-knowledge-encryption.md
|
|
560
|
+
[interop-url]: docs/features/interop-mode.md
|
|
561
|
+
[l1-invalidation-url]: docs/features/l1-invalidation.md
|
|
562
|
+
[reference-caching-url]: docs/features/reference-caching.md
|
|
563
|
+
[rust-serialization-url]: docs/features/rust-serialization.md
|
|
564
|
+
[ssrf-url]: docs/features/ssrf-protection.md
|
|
538
565
|
[contributing-url]: CONTRIBUTING.md
|
|
539
566
|
[license-file-url]: LICENSE
|
|
540
567
|
[github-url]: https://github.com/cachekit-io/cachekit-py
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
> **Python caching, batteries included**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Backend-agnostic caching with intent-based decorators — circuit breaker, distributed locking, Prometheus metrics, and optional zero-knowledge encryption on a Rust-powered core. Zero config to start, any backend when you scale.
|
|
8
8
|
|
|
9
9
|
[![PyPI Version][pypi-badge]][pypi-url]
|
|
10
10
|
[![Python Versions][python-badge]][pypi-url]
|
|
@@ -15,20 +15,16 @@ Production-ready caching for Python with intelligent reliability features and Ru
|
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
-
> [!
|
|
19
|
-
> **
|
|
20
|
-
>
|
|
21
|
-
> 🐛 **Found a bug?** Please [open an issue][issues-url] — even small ones help us improve.
|
|
22
|
-
>
|
|
23
|
-
> 💡 **Something feel off?** We want to hear about rough edges, confusing APIs, or missing features.
|
|
18
|
+
> [!NOTE]
|
|
19
|
+
> **Status: beta** — CacheKit is in closed beta ahead of 1.0. APIs are stabilising; minor breaking changes may still occur between 0.x releases.
|
|
24
20
|
>
|
|
25
|
-
>
|
|
21
|
+
> 🐛 **Found a bug or a rough edge?** Please [open an issue][issues-url] — your feedback directly shapes the path to 1.0.
|
|
26
22
|
|
|
27
23
|
---
|
|
28
24
|
|
|
29
25
|
## Why cachekit?
|
|
30
26
|
|
|
31
|
-
**Simple to use,
|
|
27
|
+
**Simple to use, works out of the box.**
|
|
32
28
|
|
|
33
29
|
```python
|
|
34
30
|
from cachekit import cache
|
|
@@ -72,7 +68,7 @@ backend that fits your infrastructure — they're peers behind the same `@cache`
|
|
|
72
68
|
| Backend | Best for | Select with |
|
|
73
69
|
|---------|----------|-------------|
|
|
74
70
|
| Redis | Self-hosted, full control | `REDIS_URL` / `CACHEKIT_REDIS_URL` |
|
|
75
|
-
| CachekitIO | Managed, zero-ops (
|
|
71
|
+
| CachekitIO | Managed, zero-ops (beta) | `CACHEKIT_API_KEY` |
|
|
76
72
|
| Memcached | High-throughput, existing infra | `CACHEKIT_MEMCACHED_SERVERS` |
|
|
77
73
|
| File / L1-only | Local dev, tests, no external deps | `CACHEKIT_FILE_CACHE_DIR` / `backend=None` |
|
|
78
74
|
|
|
@@ -95,7 +91,7 @@ def expensive_api_call(user_id: int):
|
|
|
95
91
|
### More Backends
|
|
96
92
|
|
|
97
93
|
<details>
|
|
98
|
-
<summary><strong>CachekitIO — Managed SaaS (
|
|
94
|
+
<summary><strong>CachekitIO — Managed SaaS (Beta)</strong></summary>
|
|
99
95
|
|
|
100
96
|
```python notest
|
|
101
97
|
import os
|
|
@@ -109,7 +105,7 @@ def expensive_api_call(user_id: int):
|
|
|
109
105
|
return fetch_user_data(user_id)
|
|
110
106
|
```
|
|
111
107
|
|
|
112
|
-
*cachekit.io is in closed
|
|
108
|
+
*cachekit.io is in closed beta — [request access](https://cachekit.io) to get started.*
|
|
113
109
|
|
|
114
110
|
</details>
|
|
115
111
|
|
|
@@ -135,9 +131,9 @@ def expensive_api_call(user_id: int):
|
|
|
135
131
|
|
|
136
132
|
---
|
|
137
133
|
|
|
138
|
-
> **CachekitIO Cloud (
|
|
134
|
+
> **CachekitIO Cloud (Beta)**
|
|
139
135
|
> Managed caching with zero infrastructure. L1+L2 caching, circuit breaker, and automatic failover — no Redis to manage.
|
|
140
|
-
> *cachekit.io is in closed
|
|
136
|
+
> *cachekit.io is in closed beta — [request access](https://cachekit.io) to get started.*
|
|
141
137
|
|
|
142
138
|
---
|
|
143
139
|
|
|
@@ -168,9 +164,8 @@ def get_user_profile(user_id: int):
|
|
|
168
164
|
| Backpressure | ✅ | ✅ | - | ✅ | ✅ |
|
|
169
165
|
| Integrity Checking | - | ✅ | - | ✅ | ✅ 🔒 |
|
|
170
166
|
| Encryption | - | - | - | - | ✅ Required |
|
|
171
|
-
| L1 SWR | - | ✅ | - | ✅ | ✅ |
|
|
167
|
+
| L1 SWR (L1-only mode) | - | ✅ | - | ✅ | ✅ |
|
|
172
168
|
| L1 Invalidation | - | - | - | ✅ | ✅ |
|
|
173
|
-
| L1 Namespace Index | - | - | - | ✅ | ✅ |
|
|
174
169
|
| Prometheus Metrics | - | - | - | ✅ | ✅ |
|
|
175
170
|
| Tracing | - | ✅ | - | ✅ | ✅ |
|
|
176
171
|
| Structured Logging | - | ✅ | - | ✅ | ✅ |
|
|
@@ -178,6 +173,8 @@ def get_user_profile(user_id: int):
|
|
|
178
173
|
|
|
179
174
|
> 🔒 `@cache.secure` forces `integrity_checking=True` — it cannot be overridden.
|
|
180
175
|
>
|
|
176
|
+
> **L1 SWR** (within-TTL background refresh) runs only in L1-only mode (`backend=None`) — with a backend configured it has no effect. `@cache.io` additionally ships past-TTL SWR via `stale_ttl` ([docs](docs/configuration.md#stale-while-revalidate-stale_ttl)).
|
|
177
|
+
>
|
|
181
178
|
> **`@cache.io()`** mirrors `@cache.production` (full reliability + observability) but routes to the managed CachekitIO SaaS backend instead of Redis. **`@cache.local()`** is a separate in-process path backed by `ObjectCache` (raw object references, entry-count LRU, no serialization) — the reliability and encryption features listed above do not apply to it.
|
|
182
179
|
|
|
183
180
|
<details>
|
|
@@ -238,6 +235,7 @@ def test_cached_function():
|
|
|
238
235
|
- Connection pooling with thread affinity (+28% throughput)
|
|
239
236
|
- Distributed locking prevents cache stampedes
|
|
240
237
|
- Pluggable backend abstraction (Redis, CachekitIO, File, Memcached, custom)
|
|
238
|
+
- Untrusted-decode bounds: nesting depth and header-declared allocation are capped on every cache read (a forged entry is a bounded cache miss), verified against the protocol's shared [`decode-bounds.json`](https://github.com/cachekit-io/protocol/blob/2d56cce231e193141f09df9316f9afac17a1538e/test-vectors/decode-bounds.json) vectors
|
|
241
239
|
|
|
242
240
|
> [!NOTE]
|
|
243
241
|
> All reliability features are **enabled by default** with `@cache.production`. Use `@cache.minimal` to disable them for maximum throughput.
|
|
@@ -293,9 +291,15 @@ def get_patient_data(hospital_id: int):
|
|
|
293
291
|
> [!CAUTION]
|
|
294
292
|
> When handling PII, medical, or financial data, always use `@cache.secure` to enforce encryption.
|
|
295
293
|
|
|
294
|
+
**Zero-downtime key rotation**: promote a new `CACHEKIT_MASTER_KEY` and keep the
|
|
295
|
+
retiring key readable via `CACHEKIT_PREVIOUS_MASTER_KEYS` (comma-separated hex,
|
|
296
|
+
max 3 decrypt-only keys). Entries are selected by exact key fingerprint — never
|
|
297
|
+
trial decryption — and old entries age out via TTL, no cache flush required. See
|
|
298
|
+
[Zero-Knowledge Encryption](docs/features/zero-knowledge-encryption.md#key-rotation-pattern).
|
|
299
|
+
|
|
296
300
|
cachekit employs comprehensive security tooling:
|
|
297
301
|
|
|
298
|
-
- **
|
|
302
|
+
- **Dependency Security**: cargo-deny for license compliance + cargo-audit for RustSec scanning
|
|
299
303
|
- **Formal Verification**: Kani proves correctness of compression, checksums, encryption
|
|
300
304
|
- **Runtime Analysis**: Miri + sanitizers for memory safety
|
|
301
305
|
- **Fuzzing**: Coverage-guided testing with >80% code coverage
|
|
@@ -355,6 +359,15 @@ exposition setup.
|
|
|
355
359
|
<details>
|
|
356
360
|
<summary><strong>Thread Safety Details</strong></summary>
|
|
357
361
|
|
|
362
|
+
**Free-threaded CPython (3.14t):** the core suites run green on
|
|
363
|
+
free-threaded 3.14 with the GIL verified disabled (CI job
|
|
364
|
+
`test-freethreaded`), and the Rust extension declares free-threaded safety
|
|
365
|
+
(`gil_used = false`). Free-threaded wheels are **not yet published** and
|
|
366
|
+
free-threaded builds are not officially supported — blocked on upstream
|
|
367
|
+
wheels (orjson, hiredis; numpy/pandas/pyarrow for `[data]`). See
|
|
368
|
+
[measured performance results](docs/free-threading.md#measured-performance) and the
|
|
369
|
+
full concurrency audit: [docs/free-threading.md](docs/free-threading.md).
|
|
370
|
+
|
|
358
371
|
**Per-Function Statistics:**
|
|
359
372
|
- Statistics tracked per function identity (`module.qualname`), shared across all calls and across re-decorations of the same function
|
|
360
373
|
- Thread-safe via RLock (all methods safe for concurrent access)
|
|
@@ -390,6 +403,7 @@ info = expensive_func.cache_info()
|
|
|
390
403
|
| [Comparison Guide][comparison-url] | How cachekit compares to lru_cache, aiocache, cachetools |
|
|
391
404
|
| [Getting Started][getting-started-url] | Progressive tutorial from basics to advanced |
|
|
392
405
|
| [API Reference][api-reference-url] | Complete API documentation |
|
|
406
|
+
| [Skyline (live example)][skyline-url] | Canonical example project: this SDK ingests the Bluesky firehose and writes the analytics entries a TypeScript edge Worker serves live, on one shared interop namespace |
|
|
393
407
|
|
|
394
408
|
### Feature Deep Dives
|
|
395
409
|
|
|
@@ -400,6 +414,11 @@ info = expensive_func.cache_info()
|
|
|
400
414
|
| [Distributed Locking][distributed-locking-url] | Cache stampede prevention |
|
|
401
415
|
| [Prometheus Metrics][prometheus-url] | Built-in observability |
|
|
402
416
|
| [Zero-Knowledge Encryption][encryption-url] | Client-side security |
|
|
417
|
+
| [Interop Mode][interop-url] | Cross-SDK cache sharing with cachekit-ts/rs |
|
|
418
|
+
| [L1 Invalidation & SWR][l1-invalidation-url] | Process-local invalidation, stale-while-revalidate |
|
|
419
|
+
| [Reference Caching][reference-caching-url] | `@cache.local()` for non-serializable objects |
|
|
420
|
+
| [Rust Serialization][rust-serialization-url] | ByteStorage layer: LZ4, xxHash3, AES-256-GCM |
|
|
421
|
+
| [SSRF Protection][ssrf-url] | URL allowlisting for the CachekitIO backend |
|
|
403
422
|
|
|
404
423
|
---
|
|
405
424
|
|
|
@@ -412,7 +431,7 @@ info = expensive_func.cache_info()
|
|
|
412
431
|
CACHEKIT_REDIS_URL="redis://localhost:6379" # Primary (preferred)
|
|
413
432
|
REDIS_URL="redis://localhost:6379" # Fallback
|
|
414
433
|
|
|
415
|
-
# CachekitIO SaaS Backend (closed
|
|
434
|
+
# CachekitIO SaaS Backend (closed beta — request access at cachekit.io)
|
|
416
435
|
CACHEKIT_API_KEY="your-api-key" # Required for @cache.io() # pragma: allowlist secret
|
|
417
436
|
CACHEKIT_API_URL="https://api.cachekit.io" # Default SaaS endpoint
|
|
418
437
|
|
|
@@ -475,6 +494,7 @@ MIT License - see [LICENSE][license-file-url] for details.
|
|
|
475
494
|
[uv-url]: https://github.com/astral-sh/uv
|
|
476
495
|
[security-url]: SECURITY.md
|
|
477
496
|
[comparison-url]: docs/comparison.md
|
|
497
|
+
[skyline-url]: https://github.com/cachekit-io/bluesky-thinking
|
|
478
498
|
[getting-started-url]: docs/getting-started.md
|
|
479
499
|
[api-reference-url]: docs/api-reference.md
|
|
480
500
|
[serializer-guide-url]: docs/serializers/index.md
|
|
@@ -482,6 +502,11 @@ MIT License - see [LICENSE][license-file-url] for details.
|
|
|
482
502
|
[distributed-locking-url]: docs/features/distributed-locking.md
|
|
483
503
|
[prometheus-url]: docs/features/prometheus-metrics.md
|
|
484
504
|
[encryption-url]: docs/features/zero-knowledge-encryption.md
|
|
505
|
+
[interop-url]: docs/features/interop-mode.md
|
|
506
|
+
[l1-invalidation-url]: docs/features/l1-invalidation.md
|
|
507
|
+
[reference-caching-url]: docs/features/reference-caching.md
|
|
508
|
+
[rust-serialization-url]: docs/features/rust-serialization.md
|
|
509
|
+
[ssrf-url]: docs/features/ssrf-protection.md
|
|
485
510
|
[contributing-url]: CONTRIBUTING.md
|
|
486
511
|
[license-file-url]: LICENSE
|
|
487
512
|
[github-url]: https://github.com/cachekit-io/cachekit-py
|
|
@@ -4,8 +4,8 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cachekit"
|
|
7
|
-
version = "0.
|
|
8
|
-
description = "
|
|
7
|
+
version = "0.19.0"
|
|
8
|
+
description = "Backend-agnostic caching for Python — intent-based decorators with circuit breaker, distributed locking, Prometheus metrics, and optional zero-knowledge AES-256-GCM encryption, on a Rust-powered core. Zero-config L1 in-memory; scales to Redis, Memcached, File, or CachekitIO."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
11
11
|
authors = [
|
|
@@ -31,7 +31,7 @@ keywords = [
|
|
|
31
31
|
"distributed-locking",
|
|
32
32
|
]
|
|
33
33
|
classifiers = [
|
|
34
|
-
"Development Status ::
|
|
34
|
+
"Development Status :: 4 - Beta",
|
|
35
35
|
"Intended Audience :: Developers",
|
|
36
36
|
"License :: OSI Approved :: MIT License",
|
|
37
37
|
"Operating System :: OS Independent",
|
|
@@ -56,7 +56,7 @@ dependencies = [
|
|
|
56
56
|
"redis[hiredis]>=4.0.0",
|
|
57
57
|
# Configuration and validation
|
|
58
58
|
"pydantic>=2.0.0",
|
|
59
|
-
"pydantic-settings>=2.
|
|
59
|
+
"pydantic-settings>=2.7.0", # NoDecode (previous_master_keys env parsing) first shipped in 2.7.0
|
|
60
60
|
# Monitoring and observability
|
|
61
61
|
"prometheus-client>=0.22.1",
|
|
62
62
|
"psutil>=7.0.0",
|
|
@@ -66,6 +66,22 @@ dependencies = [
|
|
|
66
66
|
"xxhash>=3.5.0",
|
|
67
67
|
# HTTP client for SaaS backend (cachekit.io)
|
|
68
68
|
"httpx[http2]>=0.28.1",
|
|
69
|
+
# anyio is transitive via the mandatory httpx dependency above, so it ships
|
|
70
|
+
# to EVERY install, not just dev. Declared here rather than as a
|
|
71
|
+
# [tool.uv] constraint because that table is uv-local: it never reaches
|
|
72
|
+
# requires-dist, so `pip install cachekit` would ignore it. 4.14.2 fixes
|
|
73
|
+
# GHSA-82r6-8w77-94w6 / CVE-2026-63374 (IDNA-2003 hostname encoding lets a
|
|
74
|
+
# hijacked connection to an internationalised domain pass TLS certificate
|
|
75
|
+
# validation; CVSS 9.3), GHSA-5p39-cfhj-2xmp / CVE-2026-64847 (undrained
|
|
76
|
+
# process-pool stderr pipe deadlocks the worker) and GHSA-3w57-8xmc-8v26 /
|
|
77
|
+
# CVE-2026-63349 (extra_groups ignored, parent supplementary groups kept).
|
|
78
|
+
"anyio>=4.14.2",
|
|
79
|
+
# h2 arrives via the http2 extra on that same mandatory httpx dependency, so
|
|
80
|
+
# it ships to every install too, and was declared as a [tool.uv] constraint
|
|
81
|
+
# with the same no-op effect. 4.4.1 fixes GHSA-6hr6-w5qg-qmwg (duplicate Host
|
|
82
|
+
# headers forwarded across an HTTP/2 -> HTTP/1.1 downgrade — a request
|
|
83
|
+
# smuggling primitive).
|
|
84
|
+
"h2>=4.4.1",
|
|
69
85
|
]
|
|
70
86
|
|
|
71
87
|
[project.optional-dependencies]
|
|
@@ -150,7 +166,6 @@ asyncio_default_fixture_loop_scope = "function"
|
|
|
150
166
|
addopts = [
|
|
151
167
|
"--strict-markers",
|
|
152
168
|
"--verbose",
|
|
153
|
-
"--basetemp=/tmp/pytest",
|
|
154
169
|
"--doctest-modules", # Validate docstring examples
|
|
155
170
|
"--doctest-continue-on-failure", # Report all doctest failures, not just first
|
|
156
171
|
"--markdown-docs", # Validate markdown documentation examples
|
|
@@ -200,8 +215,12 @@ exclude_lines = [
|
|
|
200
215
|
]
|
|
201
216
|
|
|
202
217
|
[dependency-groups]
|
|
203
|
-
|
|
204
|
-
|
|
218
|
+
# Core test toolchain — everything tests/unit + tests/critical need on ANY
|
|
219
|
+
# interpreter, including free-threaded CPython: the free-threaded CI lane
|
|
220
|
+
# installs ONLY this group (LAB-511). A dep may live here only if it ships
|
|
221
|
+
# free-threaded wheels or builds cleanly from source on 3.14t; deps that
|
|
222
|
+
# don't (orjson, numpy, pandas, pyarrow) stay in dev below.
|
|
223
|
+
test = [
|
|
205
224
|
"fakeredis>=2.21.0",
|
|
206
225
|
"pytest>=7.0.0",
|
|
207
226
|
"pytest-asyncio>=0.21.0",
|
|
@@ -210,6 +229,19 @@ dev = [
|
|
|
210
229
|
"pytest-markdown-docs>=0.6.0",
|
|
211
230
|
"pytest-redis>=3.0.0",
|
|
212
231
|
"pymemcache>=4.0.0",
|
|
232
|
+
# Utilities
|
|
233
|
+
"faker>=20.0.0",
|
|
234
|
+
"httpx>=0.28.1",
|
|
235
|
+
"hypothesis>=6.0.0",
|
|
236
|
+
"requests>=2.33.0; python_version >= '3.10'",
|
|
237
|
+
"psutil>=5.9.0",
|
|
238
|
+
"python-dotenv>=1.0.0",
|
|
239
|
+
"pyyaml>=6.0.3",
|
|
240
|
+
"pytest-xdist>=3.8.0",
|
|
241
|
+
"time-machine>=2.19.0",
|
|
242
|
+
]
|
|
243
|
+
dev = [
|
|
244
|
+
{ include-group = "test" },
|
|
213
245
|
# Competitive comparison suite (tests/competitive/ benchmarks cachekit vs these)
|
|
214
246
|
"cachetools>=5.3.0",
|
|
215
247
|
"aiocache>=0.12.0",
|
|
@@ -218,14 +250,7 @@ dev = [
|
|
|
218
250
|
"ruff>=0.6.0",
|
|
219
251
|
# Utilities
|
|
220
252
|
"bashlex>=0.18",
|
|
221
|
-
"faker>=20.0.0",
|
|
222
|
-
"httpx>=0.28.1",
|
|
223
|
-
"hypothesis>=6.0.0",
|
|
224
253
|
"pip-audit>=2.7.0",
|
|
225
|
-
"requests>=2.33.0; python_version >= '3.10'",
|
|
226
|
-
"psutil>=5.9.0",
|
|
227
|
-
"python-dotenv>=1.0.0",
|
|
228
|
-
"pyyaml>=6.0.3",
|
|
229
254
|
# Data science support (for testing AutoSerializer with numpy/pandas)
|
|
230
255
|
"numpy>=2.0.2",
|
|
231
256
|
"pandas>=1.3.0",
|
|
@@ -233,15 +258,17 @@ dev = [
|
|
|
233
258
|
# OrjsonSerializer support — now the [json] optional extra; kept here so the
|
|
234
259
|
# orjson tests, doctests, and markdown-docs still resolve it in dev/CI.
|
|
235
260
|
"orjson>=3.9.0",
|
|
236
|
-
"pytest-xdist>=3.8.0",
|
|
237
|
-
"time-machine>=2.19.0",
|
|
238
261
|
]
|
|
239
262
|
# Linux CI only - Atheris requires libFuzzer (not available on macOS without building LLVM)
|
|
240
263
|
fuzz = [
|
|
241
264
|
"atheris>=2.3.0",
|
|
242
265
|
]
|
|
243
266
|
|
|
244
|
-
# Override vulnerable transitive dependencies
|
|
267
|
+
# Override vulnerable DEV-ONLY transitive dependencies.
|
|
268
|
+
# This table is uv-local: it constrains resolution of this repo's lockfile and
|
|
269
|
+
# never reaches requires-dist, so a floor placed here does NOT protect anyone who
|
|
270
|
+
# runs `pip install cachekit`. A transitive that reaches users belongs in
|
|
271
|
+
# [project] dependencies instead — see the anyio/h2 entries above.
|
|
245
272
|
[tool.uv]
|
|
246
273
|
constraint-dependencies = [
|
|
247
274
|
"urllib3>=2.7.0",
|
|
@@ -249,6 +276,7 @@ constraint-dependencies = [
|
|
|
249
276
|
"werkzeug>=3.1.4",
|
|
250
277
|
# pip is a dev-only transitive dep (pip-audit -> pip-api -> pip). 26.1.2 fixes
|
|
251
278
|
# PYSEC-2026-196 (entry-point path traversal), GHSA-58qw-9mgm-455v (tar/zip
|
|
252
|
-
# confusion) and GHSA-jp4c-xjxw-mgf9 (self-update import ordering).
|
|
253
|
-
|
|
279
|
+
# confusion) and GHSA-jp4c-xjxw-mgf9 (self-update import ordering); 26.2 fixes
|
|
280
|
+
# PYSEC-2026-3721 (doubly-encoded index URLs install to arbitrary paths).
|
|
281
|
+
"pip>=26.2",
|
|
254
282
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "cachekit-rs"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.19.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
authors = ["cachekit Contributors"]
|
|
6
6
|
description = "High-performance storage engine for caching with compression and encryption"
|
|
@@ -20,11 +20,15 @@ crate-type = ["cdylib", "rlib"]
|
|
|
20
20
|
|
|
21
21
|
[dependencies]
|
|
22
22
|
# Compression, checksums, encryption (https://crates.io/crates/cachekit-core)
|
|
23
|
-
cachekit-core = { version = "0.
|
|
23
|
+
cachekit-core = { version = "0.5.0", features = ["compression", "checksum", "messagepack", "encryption"] }
|
|
24
24
|
|
|
25
25
|
# Python integration - optional for Rust-only builds
|
|
26
26
|
pyo3 = { workspace = true, optional = true }
|
|
27
27
|
|
|
28
|
+
# Wipe the PyO3-side copies of master key material on drop. Only used behind
|
|
29
|
+
# the encryption feature, so gated the same way pyo3 is.
|
|
30
|
+
zeroize = { version = "1", optional = true }
|
|
31
|
+
|
|
28
32
|
# Feature flags
|
|
29
33
|
[features]
|
|
30
34
|
default = ["python", "compression", "checksum", "messagepack", "encryption"]
|
|
@@ -36,7 +40,7 @@ python = ["dep:pyo3"]
|
|
|
36
40
|
compression = []
|
|
37
41
|
checksum = []
|
|
38
42
|
messagepack = []
|
|
39
|
-
encryption = []
|
|
43
|
+
encryption = ["dep:zeroize"]
|
|
40
44
|
|
|
41
45
|
[dev-dependencies]
|
|
42
46
|
criterion = { version = "0.5", features = ["html_reports"] }
|