cachekit 0.24.1__tar.gz → 0.25.1__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.
Files changed (90) hide show
  1. {cachekit-0.24.1 → cachekit-0.25.1}/Cargo.lock +9 -182
  2. {cachekit-0.24.1 → cachekit-0.25.1}/PKG-INFO +49 -23
  3. {cachekit-0.24.1 → cachekit-0.25.1}/README.md +46 -19
  4. {cachekit-0.24.1 → cachekit-0.25.1}/pyproject.toml +21 -11
  5. {cachekit-0.24.1 → cachekit-0.25.1}/rust/Cargo.toml +3 -3
  6. {cachekit-0.24.1 → cachekit-0.25.1}/rust/Makefile +12 -12
  7. {cachekit-0.24.1 → cachekit-0.25.1}/rust/README.md +46 -19
  8. cachekit-0.25.1/rust/src/hit_counter.rs +164 -0
  9. {cachekit-0.24.1 → cachekit-0.25.1}/rust/src/lib.rs +19 -10
  10. {cachekit-0.24.1 → cachekit-0.25.1}/rust/src/python_bindings.rs +156 -49
  11. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/__init__.py +12 -1
  12. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/base.py +1 -1
  13. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/cachekitio/backend.py +14 -15
  14. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/errors.py +2 -2
  15. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/file/backend.py +5 -5
  16. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/provider.py +2 -3
  17. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/redis/backend.py +2 -2
  18. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/redis/client.py +3 -3
  19. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/redis/provider.py +110 -44
  20. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/cache_handler.py +254 -66
  21. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/config/decorator.py +19 -7
  22. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/config/nested.py +93 -30
  23. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/config/settings.py +8 -8
  24. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/config/validation.py +4 -7
  25. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/decorators/intent.py +7 -7
  26. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/decorators/local_wrapper.py +3 -3
  27. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/decorators/single_flight.py +17 -8
  28. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/decorators/wrapper.py +781 -315
  29. cachekit-0.25.1/src/cachekit/decorators/write_behind.py +261 -0
  30. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/health.py +40 -36
  31. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/interop.py +5 -18
  32. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/key_generator.py +7 -7
  33. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/l1_cache.py +54 -15
  34. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/logging.py +1 -1
  35. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/monitoring/protocols.py +11 -19
  36. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/object_cache.py +64 -20
  37. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/reliability/async_metrics.py +451 -160
  38. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/reliability/circuit_breaker.py +28 -25
  39. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/serializers/__init__.py +1 -2
  40. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/serializers/arrow_serializer.py +4 -4
  41. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/serializers/auto_serializer.py +15 -14
  42. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/serializers/base.py +16 -14
  43. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/serializers/encryption_wrapper.py +81 -63
  44. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/serializers/orjson_serializer.py +1 -1
  45. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/serializers/standard_serializer.py +59 -8
  46. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/serializers/wrapper.py +2 -2
  47. cachekit-0.24.1/rust/src/msgpack_bounds.rs +0 -87
  48. {cachekit-0.24.1 → cachekit-0.25.1}/Cargo.toml +0 -0
  49. {cachekit-0.24.1 → cachekit-0.25.1}/LICENSE +0 -0
  50. {cachekit-0.24.1 → cachekit-0.25.1}/rust/TEST_EXPANSION_SUMMARY.md +0 -0
  51. {cachekit-0.24.1 → cachekit-0.25.1}/rust/tsan_suppressions.txt +0 -0
  52. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/_fork.py +0 -0
  53. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/__init__.py +0 -0
  54. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/_uninterrupted.py +0 -0
  55. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/base_config.py +0 -0
  56. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/cachekitio/__init__.py +0 -0
  57. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/cachekitio/client.py +0 -0
  58. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/cachekitio/config.py +0 -0
  59. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/cachekitio/error_handler.py +0 -0
  60. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/cachekitio/session.py +0 -0
  61. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/file/__init__.py +0 -0
  62. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/file/config.py +0 -0
  63. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/memcached/__init__.py +0 -0
  64. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/memcached/backend.py +0 -0
  65. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/memcached/config.py +0 -0
  66. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/memcached/error_handler.py +0 -0
  67. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/redis/__init__.py +0 -0
  68. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/redis/config.py +0 -0
  69. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/backends/redis/error_handler.py +0 -0
  70. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/config/__init__.py +0 -0
  71. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/config/singleton.py +0 -0
  72. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/decorators/__init__.py +0 -0
  73. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/decorators/main.py +0 -0
  74. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/decorators/orchestrator.py +0 -0
  75. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/decorators/session.py +0 -0
  76. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/decorators/stats_context.py +0 -0
  77. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/decorators/tenant_context.py +0 -0
  78. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/decorators/utils/__init__.py +0 -0
  79. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/di.py +0 -0
  80. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/hash_utils.py +0 -0
  81. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/hiredis_compat.py +0 -0
  82. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/imports.py +0 -0
  83. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/invalidation.py +0 -0
  84. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/monitoring/__init__.py +0 -0
  85. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/py.typed +0 -0
  86. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/reliability/__init__.py +0 -0
  87. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/reliability/error_classification.py +0 -0
  88. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/reliability/load_control.py +0 -0
  89. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/reliability/metrics_collection.py +0 -0
  90. {cachekit-0.24.1 → cachekit-0.25.1}/src/cachekit/serializers/interop_serializer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  # This file is automatically @generated by Cargo.
2
2
  # It is not intended for manual editing.
3
- version = 3
3
+ version = 4
4
4
 
5
5
  [[package]]
6
6
  name = "addr2line"
@@ -100,56 +100,12 @@ version = "0.1.6"
100
100
  source = "registry+https://github.com/rust-lang/crates.io-index"
101
101
  checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
102
102
 
103
- [[package]]
104
- name = "anstream"
105
- version = "1.0.0"
106
- source = "registry+https://github.com/rust-lang/crates.io-index"
107
- checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
108
- dependencies = [
109
- "anstyle",
110
- "anstyle-parse",
111
- "anstyle-query",
112
- "anstyle-wincon",
113
- "colorchoice",
114
- "is_terminal_polyfill",
115
- "utf8parse",
116
- ]
117
-
118
103
  [[package]]
119
104
  name = "anstyle"
120
105
  version = "1.0.14"
121
106
  source = "registry+https://github.com/rust-lang/crates.io-index"
122
107
  checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
123
108
 
124
- [[package]]
125
- name = "anstyle-parse"
126
- version = "1.0.0"
127
- source = "registry+https://github.com/rust-lang/crates.io-index"
128
- checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
129
- dependencies = [
130
- "utf8parse",
131
- ]
132
-
133
- [[package]]
134
- name = "anstyle-query"
135
- version = "1.1.5"
136
- source = "registry+https://github.com/rust-lang/crates.io-index"
137
- checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
138
- dependencies = [
139
- "windows-sys 0.60.2",
140
- ]
141
-
142
- [[package]]
143
- name = "anstyle-wincon"
144
- version = "3.0.11"
145
- source = "registry+https://github.com/rust-lang/crates.io-index"
146
- checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
147
- dependencies = [
148
- "anstyle",
149
- "once_cell_polyfill",
150
- "windows-sys 0.60.2",
151
- ]
152
-
153
109
  [[package]]
154
110
  name = "anyhow"
155
111
  version = "1.0.102"
@@ -240,29 +196,14 @@ version = "1.25.0"
240
196
  source = "registry+https://github.com/rust-lang/crates.io-index"
241
197
  checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
242
198
 
243
- [[package]]
244
- name = "byteorder"
245
- version = "1.5.0"
246
- source = "registry+https://github.com/rust-lang/crates.io-index"
247
- checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
248
-
249
- [[package]]
250
- name = "bytes"
251
- version = "1.11.1"
252
- source = "registry+https://github.com/rust-lang/crates.io-index"
253
- checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
254
-
255
199
  [[package]]
256
200
  name = "cachekit-core"
257
- version = "0.6.0"
201
+ version = "0.7.2"
258
202
  source = "registry+https://github.com/rust-lang/crates.io-index"
259
- checksum = "93adc5646956ba8da140f4179a02e60a2cc7a401b83ebb1270cc4d03748e1fac"
203
+ checksum = "101672176881ef05b17e8399476eb6fc2082e6a5c33788c84c9bb4d1a8d512d7"
260
204
  dependencies = [
261
205
  "aes",
262
206
  "aes-gcm",
263
- "byteorder",
264
- "bytes",
265
- "cbindgen",
266
207
  "generic-array",
267
208
  "getrandom 0.2.17",
268
209
  "hkdf",
@@ -280,7 +221,7 @@ dependencies = [
280
221
 
281
222
  [[package]]
282
223
  name = "cachekit-rs"
283
- version = "0.24.1"
224
+ version = "0.25.1"
284
225
  dependencies = [
285
226
  "cachekit-core",
286
227
  "criterion 0.8.2",
@@ -300,25 +241,6 @@ version = "0.3.0"
300
241
  source = "registry+https://github.com/rust-lang/crates.io-index"
301
242
  checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
302
243
 
303
- [[package]]
304
- name = "cbindgen"
305
- version = "0.29.2"
306
- source = "registry+https://github.com/rust-lang/crates.io-index"
307
- checksum = "befbfd072a8e81c02f8c507aefce431fe5e7d051f83d48a23ffc9b9fe5a11799"
308
- dependencies = [
309
- "clap",
310
- "heck",
311
- "indexmap",
312
- "log",
313
- "proc-macro2",
314
- "quote",
315
- "serde",
316
- "serde_json",
317
- "syn",
318
- "tempfile",
319
- "toml",
320
- ]
321
-
322
244
  [[package]]
323
245
  name = "cc"
324
246
  version = "1.2.57"
@@ -387,10 +309,8 @@ version = "4.6.0"
387
309
  source = "registry+https://github.com/rust-lang/crates.io-index"
388
310
  checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
389
311
  dependencies = [
390
- "anstream",
391
312
  "anstyle",
392
313
  "clap_lex",
393
- "strsim",
394
314
  "terminal_size",
395
315
  ]
396
316
 
@@ -400,12 +320,6 @@ version = "1.1.0"
400
320
  source = "registry+https://github.com/rust-lang/crates.io-index"
401
321
  checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
402
322
 
403
- [[package]]
404
- name = "colorchoice"
405
- version = "1.0.5"
406
- source = "registry+https://github.com/rust-lang/crates.io-index"
407
- checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
408
-
409
323
  [[package]]
410
324
  name = "condtype"
411
325
  version = "1.3.0"
@@ -667,7 +581,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
667
581
  checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
668
582
  dependencies = [
669
583
  "libc",
670
- "windows-sys 0.52.0",
584
+ "windows-sys 0.61.2",
671
585
  ]
672
586
 
673
587
  [[package]]
@@ -888,15 +802,9 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
888
802
  dependencies = [
889
803
  "hermit-abi",
890
804
  "libc",
891
- "windows-sys 0.52.0",
805
+ "windows-sys 0.61.2",
892
806
  ]
893
807
 
894
- [[package]]
895
- name = "is_terminal_polyfill"
896
- version = "1.70.2"
897
- source = "registry+https://github.com/rust-lang/crates.io-index"
898
- checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
899
-
900
808
  [[package]]
901
809
  name = "itertools"
902
810
  version = "0.10.5"
@@ -987,9 +895,6 @@ name = "lz4_flex"
987
895
  version = "0.12.2"
988
896
  source = "registry+https://github.com/rust-lang/crates.io-index"
989
897
  checksum = "90071f8077f8e40adfc4b7fe9cd495ce316263f19e75c2211eeff3fdf475a3d9"
990
- dependencies = [
991
- "twox-hash",
992
- ]
993
898
 
994
899
  [[package]]
995
900
  name = "memchr"
@@ -1060,12 +965,6 @@ version = "1.21.4"
1060
965
  source = "registry+https://github.com/rust-lang/crates.io-index"
1061
966
  checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
1062
967
 
1063
- [[package]]
1064
- name = "once_cell_polyfill"
1065
- version = "1.70.2"
1066
- source = "registry+https://github.com/rust-lang/crates.io-index"
1067
- checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
1068
-
1069
968
  [[package]]
1070
969
  name = "oorandom"
1071
970
  version = "11.1.5"
@@ -1538,7 +1437,7 @@ dependencies = [
1538
1437
  "errno",
1539
1438
  "libc",
1540
1439
  "linux-raw-sys 0.12.1",
1541
- "windows-sys 0.52.0",
1440
+ "windows-sys 0.61.2",
1542
1441
  ]
1543
1442
 
1544
1443
  [[package]]
@@ -1633,15 +1532,6 @@ dependencies = [
1633
1532
  "zmij",
1634
1533
  ]
1635
1534
 
1636
- [[package]]
1637
- name = "serde_spanned"
1638
- version = "1.0.4"
1639
- source = "registry+https://github.com/rust-lang/crates.io-index"
1640
- checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776"
1641
- dependencies = [
1642
- "serde_core",
1643
- ]
1644
-
1645
1535
  [[package]]
1646
1536
  name = "sha2"
1647
1537
  version = "0.10.9"
@@ -1686,12 +1576,6 @@ version = "0.1.0"
1686
1576
  source = "registry+https://github.com/rust-lang/crates.io-index"
1687
1577
  checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb"
1688
1578
 
1689
- [[package]]
1690
- name = "strsim"
1691
- version = "0.11.1"
1692
- source = "registry+https://github.com/rust-lang/crates.io-index"
1693
- checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
1694
-
1695
1579
  [[package]]
1696
1580
  name = "subtle"
1697
1581
  version = "2.6.1"
@@ -1748,7 +1632,7 @@ dependencies = [
1748
1632
  "getrandom 0.3.4",
1749
1633
  "once_cell",
1750
1634
  "rustix 1.1.4",
1751
- "windows-sys 0.52.0",
1635
+ "windows-sys 0.61.2",
1752
1636
  ]
1753
1637
 
1754
1638
  [[package]]
@@ -1811,51 +1695,6 @@ dependencies = [
1811
1695
  "serde_json",
1812
1696
  ]
1813
1697
 
1814
- [[package]]
1815
- name = "toml"
1816
- version = "0.9.12+spec-1.1.0"
1817
- source = "registry+https://github.com/rust-lang/crates.io-index"
1818
- checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
1819
- dependencies = [
1820
- "indexmap",
1821
- "serde_core",
1822
- "serde_spanned",
1823
- "toml_datetime",
1824
- "toml_parser",
1825
- "toml_writer",
1826
- "winnow",
1827
- ]
1828
-
1829
- [[package]]
1830
- name = "toml_datetime"
1831
- version = "0.7.5+spec-1.1.0"
1832
- source = "registry+https://github.com/rust-lang/crates.io-index"
1833
- checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
1834
- dependencies = [
1835
- "serde_core",
1836
- ]
1837
-
1838
- [[package]]
1839
- name = "toml_parser"
1840
- version = "1.0.9+spec-1.1.0"
1841
- source = "registry+https://github.com/rust-lang/crates.io-index"
1842
- checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4"
1843
- dependencies = [
1844
- "winnow",
1845
- ]
1846
-
1847
- [[package]]
1848
- name = "toml_writer"
1849
- version = "1.0.6+spec-1.1.0"
1850
- source = "registry+https://github.com/rust-lang/crates.io-index"
1851
- checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607"
1852
-
1853
- [[package]]
1854
- name = "twox-hash"
1855
- version = "2.1.2"
1856
- source = "registry+https://github.com/rust-lang/crates.io-index"
1857
- checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c"
1858
-
1859
1698
  [[package]]
1860
1699
  name = "typenum"
1861
1700
  version = "1.19.0"
@@ -1890,12 +1729,6 @@ version = "0.9.0"
1890
1729
  source = "registry+https://github.com/rust-lang/crates.io-index"
1891
1730
  checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
1892
1731
 
1893
- [[package]]
1894
- name = "utf8parse"
1895
- version = "0.2.2"
1896
- source = "registry+https://github.com/rust-lang/crates.io-index"
1897
- checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
1898
-
1899
1732
  [[package]]
1900
1733
  name = "uuid"
1901
1734
  version = "1.22.0"
@@ -2035,7 +1868,7 @@ version = "0.1.11"
2035
1868
  source = "registry+https://github.com/rust-lang/crates.io-index"
2036
1869
  checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
2037
1870
  dependencies = [
2038
- "windows-sys 0.52.0",
1871
+ "windows-sys 0.61.2",
2039
1872
  ]
2040
1873
 
2041
1874
  [[package]]
@@ -2215,12 +2048,6 @@ version = "0.53.1"
2215
2048
  source = "registry+https://github.com/rust-lang/crates.io-index"
2216
2049
  checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
2217
2050
 
2218
- [[package]]
2219
- name = "winnow"
2220
- version = "0.7.15"
2221
- source = "registry+https://github.com/rust-lang/crates.io-index"
2222
- checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
2223
-
2224
2051
  [[package]]
2225
2052
  name = "wit-bindgen"
2226
2053
  version = "0.51.0"
@@ -1,16 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cachekit
3
- Version: 0.24.1
3
+ Version: 0.25.1
4
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
8
8
  Classifier: Programming Language :: Python :: 3
9
- Classifier: Programming Language :: Python :: 3.10
10
9
  Classifier: Programming Language :: Python :: 3.11
11
10
  Classifier: Programming Language :: Python :: 3.12
12
11
  Classifier: Programming Language :: Python :: 3.13
13
12
  Classifier: Programming Language :: Python :: 3.14
13
+ Classifier: Programming Language :: Python :: 3.15
14
14
  Classifier: Programming Language :: Python :: Implementation :: CPython
15
15
  Classifier: Programming Language :: Rust
16
16
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
@@ -24,7 +24,6 @@ Requires-Dist: redis[hiredis]>=4.6.0
24
24
  Requires-Dist: pydantic>=2.0.0
25
25
  Requires-Dist: pydantic-settings>=2.13.0
26
26
  Requires-Dist: prometheus-client>=0.22.1
27
- Requires-Dist: psutil>=7.0.0
28
27
  Requires-Dist: blake3>=1.0.5
29
28
  Requires-Dist: msgpack>=1.2.1
30
29
  Requires-Dist: xxhash>=3.5.0
@@ -44,7 +43,7 @@ Home-Page: https://github.com/cachekit-io/cachekit-py
44
43
  Author-email: cachekit Contributors <noreply@cachekit.io>
45
44
  Maintainer-email: cachekit Contributors <noreply@cachekit.io>
46
45
  License: MIT
47
- Requires-Python: >=3.10
46
+ Requires-Python: >=3.11
48
47
  Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
49
48
  Project-URL: Changelog, https://github.com/cachekit-io/cachekit-py/blob/main/CHANGELOG.md
50
49
  Project-URL: Documentation, https://github.com/cachekit-io/cachekit-py#readme
@@ -297,9 +296,9 @@ def test_cached_function():
297
296
  │ │ Breaker │ │ Timeouts │ │ Locking │ │
298
297
  │ └─────────────┘ └─────────────┘ └─────────────────────┘ │
299
298
  ├─────────────────────────────────────────────────────────────┤
300
- │ L1 Cache (In-Memory) │ L2 Cache (Pluggable Backend) │
301
- │ ~50ns │ Redis / CachekitIO / File / │
302
- │ │ Memcached ~2-50ms │
299
+ │ L1 Cache (In-Memory) │ L2 Cache (Pluggable Backend) │
300
+ │ in-process │ Redis / CachekitIO / File / │
301
+ │ │ Memcached: one backend round trip │
303
302
  ├─────────────────────────────────────────────────────────────┤
304
303
  │ Rust Core (PyO3) │
305
304
  │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
@@ -314,12 +313,31 @@ def test_cached_function():
314
313
 
315
314
  ---
316
315
 
316
+ ## Performance
317
+
318
+ What a call costs inside your process, from the wall-clock guards in `tests/performance/` run on a GitHub-hosted `ubuntu-latest` runner (AMD EPYC 7763, 4 vCPUs) with CPython 3.14.7. Each figure is the mean of five run medians with its 95% band.
319
+
320
+ | Path | Time per call |
321
+ |:-----|--------------:|
322
+ | `@cache(backend=None)` L1 hit, 100-user nested dict (23.5 KB as MessagePack) | 0.906 ± 0.007 µs |
323
+ | `@cache(backend=None)` L1 hit, 10K-row DataFrame | 0.91 ± 0.01 µs |
324
+ | L1 hit with an L2 backend configured, same dict | 310 ± 20 µs |
325
+ | Redis L2 hit with L1 disabled, same dict, Redis in a container on the same machine | 551 ± 18 µs |
326
+
327
+ - With no backend, L1 keeps the returned object itself, whatever the payload's size, and a repeat call with a few short scalar arguments finds its cache key in a per-function memo instead of building it again ([which calls](https://github.com/cachekit-io/cachekit-py/blob/main/docs/performance.md#decorator--l1-hit-hot-path)). Any other call builds its key every time, as does every call to a function with a backend.
328
+ - With an L2 backend, L1 holds the serialized bytes and every hit deserializes them: for this dict, about 340 times the L1-only hit. Encryption adds a decrypt to each such hit; on this run that added 10 ± 21 µs, inside the noise.
329
+ - An L2 hit adds the backend's round trip. A Redis on another machine adds its network latency to the last row.
330
+
331
+ Hosted runners come with other CPU models too: in a run of an earlier commit, an EPYC 9V45 runner took about half as long on every row, and other machines give other figures. The [Performance Guide](https://github.com/cachekit-io/cachekit-py/blob/main/docs/performance.md#github-hosted-runner) names the guard behind each figure and how to run it, and the repository's `Bench` workflow repeats the run.
332
+
333
+ ---
334
+
317
335
  ## Features
318
336
 
319
337
  ### Production Hardened
320
338
 
321
339
  - Circuit breaker with graceful degradation
322
- - Connection pooling with thread affinity (+28% throughput)
340
+ - Connection pooling with thread affinity
323
341
  - CachekitIO keeps idle connections pooled until the server closes them, with TCP keepalive probes, so a request after a pause skips a new TLS handshake
324
342
  - Distributed locking prevents cache stampedes
325
343
  - Pluggable backend abstraction (Redis, CachekitIO, File, Memcached, custom)
@@ -333,7 +351,7 @@ def test_cached_function():
333
351
  | Serializer | Speed | Use Case |
334
352
  |:-----------|:-----:|:---------|
335
353
  | **StandardSerializer** | ★★★★☆ | General Python types; not NumPy arrays or pandas objects |
336
- | **OrjsonSerializer** | ★★★★★ | JSON APIs (2-5x faster than stdlib) — requires `cachekit[json]` |
354
+ | **OrjsonSerializer** | ★★★★★ | JSON APIs — requires `cachekit[json]` |
337
355
  | **ArrowSerializer** | — | pandas DataFrames (columnar, exact round trip) |
338
356
  | **+ Encryption** | ★★★★☆ | Any serializer above, AES-256-GCM encrypted: `@cache.secure(master_key=..., serializer=...)` |
339
357
 
@@ -383,15 +401,18 @@ assert calls == 1
383
401
  ### Integrity Checking
384
402
 
385
403
  > [!IMPORTANT]
386
- > All serializers support **configurable checksums** for corruption detection using xxHash3-64 (8 bytes). Enabled by default in `@cache.production` and `@cache.secure`.
404
+ > Serializers detect corrupted entries with an xxHash3-64 checksum. It is on by default. `@cache.minimal` and `@cache.test` turn it off where the serializer allows it (`ArrowSerializer` always checks); `@cache.secure` refuses to turn it off.
405
+
406
+ Each checksum is an 8-byte digest, plus one pass over the payload on each write and read. What `enable_integrity_checking=False` changes depends on the serializer, and for `AutoSerializer` on the value:
387
407
 
388
- **Performance Impact** (benchmark-proven):
408
+ | Serializer | Checking on (default) | Checking off |
409
+ |:-----------|:----------------------|:-------------|
410
+ | `StandardSerializer`, and `AutoSerializer` for values other than the two below | MessagePack in an LZ4 envelope that carries the checksum | Plain MessagePack: no checksum, no LZ4 |
411
+ | `AutoSerializer`, NumPy arrays | The checksum, then the raw array bytes (never compressed) | The raw array bytes |
412
+ | `AutoSerializer`, pandas DataFrames with pyarrow installed, and `ArrowSerializer` | The checksum, then the Arrow IPC data | No change: Arrow always checks |
413
+ | `OrjsonSerializer` | The checksum, then the JSON | Plain JSON |
389
414
 
390
- | Data Type | Latency Reduction (disabled) | Size Overhead |
391
- |:----------|:----------------------------:|:-------------:|
392
- | MessagePack (default) | 60-90% | 8 bytes |
393
- | Arrow DataFrames | 35-49% | 8 bytes |
394
- | JSON (orjson) | 37-68% | 8 bytes |
415
+ Where the switch drops the LZ4 envelope, an entry gets larger only when LZ4 saved more than the envelope's overhead of about 25 to 30 bytes; otherwise it stays the same size or gets smaller. Measure on your own payloads before you trade that.
395
416
 
396
417
  ### Security
397
418
 
@@ -428,7 +449,7 @@ make security-fast # Run fast checks (< 3 min)
428
449
  | Tier | Time | Coverage |
429
450
  |:-----|:----:|:---------|
430
451
  | Fast | < 3 min | Vulnerability scanning, license checks, linting |
431
- | Medium | < 15 min | Unsafe code analysis, API stability, Miri subset |
452
+ | Medium | < 15 min | Unsafe code analysis (cargo-geiger) |
432
453
  | Deep | < 2 hours | Formal verification, extended fuzzing, full sanitizers |
433
454
 
434
455
  See [SECURITY.md][security-url] for vulnerability reporting and detailed documentation.
@@ -470,11 +491,14 @@ exposition setup.
470
491
  <details>
471
492
  <summary><strong>Thread Safety Details</strong></summary>
472
493
 
473
- **Free-threaded CPython (3.14t):** the core suites run green on
474
- free-threaded 3.14 with the GIL verified disabled (CI job
494
+ **Free-threaded CPython (3.15t, 3.14t):** the core suites run green on
495
+ free-threaded 3.14 and 3.15 with the GIL verified disabled (CI job
475
496
  `test-freethreaded`), and the Rust extension declares free-threaded safety
476
- (`gil_used = false`). Free-threaded wheels are **not yet published** and
477
- free-threaded builds are not officially supported — blocked upstream on
497
+ (`gil_used = false`). **From the release after 0.24.1, 3.15t has a wheel**:
498
+ the 3.15+ wheel is `abi3t`, so it installs on 3.15t without a Rust toolchain
499
+ (pip 26.1+ or uv 0.11.3+). **3.14t is tested
500
+ but has no wheel** (it builds from source). Free-threaded builds are not
501
+ officially supported yet — blocked upstream on
478
502
  orjson (no free-threaded wheels) and hiredis (re-enables the GIL on import;
479
503
  cachekit loads redis-py only for its Redis backend, and keeps hiredis out there,
480
504
  so redis-py uses its pure-Python parser). See
@@ -483,7 +507,7 @@ full concurrency audit: [docs/free-threading.md](docs/free-threading.md).
483
507
 
484
508
  **Per-Function Statistics:**
485
509
  - Statistics tracked per function identity (`module.qualname`), shared across all calls and across re-decorations of the same function
486
- - Thread-safe via RLock (all methods safe for concurrent access)
510
+ - Thread-safe: every count is exact (L1 hits on an atomic counter, everything else under an RLock), and all methods are safe for concurrent access
487
511
  - Fork-safe: a forked child starts with zeroed counters and its own session ID
488
512
 
489
513
  ```python
@@ -532,6 +556,7 @@ info = expensive_func.cache_info()
532
556
  | [Reference Caching][reference-caching-url] | `@cache.local()` for non-serializable objects |
533
557
  | [Rust Serialization][rust-serialization-url] | ByteStorage layer: LZ4, xxHash3, AES-256-GCM |
534
558
  | [SSRF Protection][ssrf-url] | URL allowlisting for the CachekitIO backend |
559
+ | [Write-Behind][write-behind-url] | Opt-in `write_behind=True`: a miss returns before its L2 write lands |
535
560
 
536
561
  ---
537
562
 
@@ -585,7 +610,7 @@ See [CONTRIBUTING.md][contributing-url] for full development guidelines.
585
610
 
586
611
  | Component | Version |
587
612
  |:----------|:--------|
588
- | Python | 3.10+ |
613
+ | Python | 3.11+ |
589
614
 
590
615
  ---
591
616
 
@@ -623,6 +648,7 @@ MIT License - see [LICENSE][license-file-url] for details.
623
648
  [reference-caching-url]: docs/features/reference-caching.md
624
649
  [rust-serialization-url]: docs/features/rust-serialization.md
625
650
  [ssrf-url]: docs/features/ssrf-protection.md
651
+ [write-behind-url]: docs/features/write-behind.md
626
652
  [contributing-url]: CONTRIBUTING.md
627
653
  [license-file-url]: LICENSE
628
654
  [github-url]: https://github.com/cachekit-io/cachekit-py
@@ -243,9 +243,9 @@ def test_cached_function():
243
243
  │ │ Breaker │ │ Timeouts │ │ Locking │ │
244
244
  │ └─────────────┘ └─────────────┘ └─────────────────────┘ │
245
245
  ├─────────────────────────────────────────────────────────────┤
246
- │ L1 Cache (In-Memory) │ L2 Cache (Pluggable Backend) │
247
- │ ~50ns │ Redis / CachekitIO / File / │
248
- │ │ Memcached ~2-50ms │
246
+ │ L1 Cache (In-Memory) │ L2 Cache (Pluggable Backend) │
247
+ │ in-process │ Redis / CachekitIO / File / │
248
+ │ │ Memcached: one backend round trip │
249
249
  ├─────────────────────────────────────────────────────────────┤
250
250
  │ Rust Core (PyO3) │
251
251
  │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
@@ -260,12 +260,31 @@ def test_cached_function():
260
260
 
261
261
  ---
262
262
 
263
+ ## Performance
264
+
265
+ What a call costs inside your process, from the wall-clock guards in `tests/performance/` run on a GitHub-hosted `ubuntu-latest` runner (AMD EPYC 7763, 4 vCPUs) with CPython 3.14.7. Each figure is the mean of five run medians with its 95% band.
266
+
267
+ | Path | Time per call |
268
+ |:-----|--------------:|
269
+ | `@cache(backend=None)` L1 hit, 100-user nested dict (23.5 KB as MessagePack) | 0.906 ± 0.007 µs |
270
+ | `@cache(backend=None)` L1 hit, 10K-row DataFrame | 0.91 ± 0.01 µs |
271
+ | L1 hit with an L2 backend configured, same dict | 310 ± 20 µs |
272
+ | Redis L2 hit with L1 disabled, same dict, Redis in a container on the same machine | 551 ± 18 µs |
273
+
274
+ - With no backend, L1 keeps the returned object itself, whatever the payload's size, and a repeat call with a few short scalar arguments finds its cache key in a per-function memo instead of building it again ([which calls](https://github.com/cachekit-io/cachekit-py/blob/main/docs/performance.md#decorator--l1-hit-hot-path)). Any other call builds its key every time, as does every call to a function with a backend.
275
+ - With an L2 backend, L1 holds the serialized bytes and every hit deserializes them: for this dict, about 340 times the L1-only hit. Encryption adds a decrypt to each such hit; on this run that added 10 ± 21 µs, inside the noise.
276
+ - An L2 hit adds the backend's round trip. A Redis on another machine adds its network latency to the last row.
277
+
278
+ Hosted runners come with other CPU models too: in a run of an earlier commit, an EPYC 9V45 runner took about half as long on every row, and other machines give other figures. The [Performance Guide](https://github.com/cachekit-io/cachekit-py/blob/main/docs/performance.md#github-hosted-runner) names the guard behind each figure and how to run it, and the repository's `Bench` workflow repeats the run.
279
+
280
+ ---
281
+
263
282
  ## Features
264
283
 
265
284
  ### Production Hardened
266
285
 
267
286
  - Circuit breaker with graceful degradation
268
- - Connection pooling with thread affinity (+28% throughput)
287
+ - Connection pooling with thread affinity
269
288
  - CachekitIO keeps idle connections pooled until the server closes them, with TCP keepalive probes, so a request after a pause skips a new TLS handshake
270
289
  - Distributed locking prevents cache stampedes
271
290
  - Pluggable backend abstraction (Redis, CachekitIO, File, Memcached, custom)
@@ -279,7 +298,7 @@ def test_cached_function():
279
298
  | Serializer | Speed | Use Case |
280
299
  |:-----------|:-----:|:---------|
281
300
  | **StandardSerializer** | ★★★★☆ | General Python types; not NumPy arrays or pandas objects |
282
- | **OrjsonSerializer** | ★★★★★ | JSON APIs (2-5x faster than stdlib) — requires `cachekit[json]` |
301
+ | **OrjsonSerializer** | ★★★★★ | JSON APIs — requires `cachekit[json]` |
283
302
  | **ArrowSerializer** | — | pandas DataFrames (columnar, exact round trip) |
284
303
  | **+ Encryption** | ★★★★☆ | Any serializer above, AES-256-GCM encrypted: `@cache.secure(master_key=..., serializer=...)` |
285
304
 
@@ -329,15 +348,18 @@ assert calls == 1
329
348
  ### Integrity Checking
330
349
 
331
350
  > [!IMPORTANT]
332
- > All serializers support **configurable checksums** for corruption detection using xxHash3-64 (8 bytes). Enabled by default in `@cache.production` and `@cache.secure`.
351
+ > Serializers detect corrupted entries with an xxHash3-64 checksum. It is on by default. `@cache.minimal` and `@cache.test` turn it off where the serializer allows it (`ArrowSerializer` always checks); `@cache.secure` refuses to turn it off.
352
+
353
+ Each checksum is an 8-byte digest, plus one pass over the payload on each write and read. What `enable_integrity_checking=False` changes depends on the serializer, and for `AutoSerializer` on the value:
333
354
 
334
- **Performance Impact** (benchmark-proven):
355
+ | Serializer | Checking on (default) | Checking off |
356
+ |:-----------|:----------------------|:-------------|
357
+ | `StandardSerializer`, and `AutoSerializer` for values other than the two below | MessagePack in an LZ4 envelope that carries the checksum | Plain MessagePack: no checksum, no LZ4 |
358
+ | `AutoSerializer`, NumPy arrays | The checksum, then the raw array bytes (never compressed) | The raw array bytes |
359
+ | `AutoSerializer`, pandas DataFrames with pyarrow installed, and `ArrowSerializer` | The checksum, then the Arrow IPC data | No change: Arrow always checks |
360
+ | `OrjsonSerializer` | The checksum, then the JSON | Plain JSON |
335
361
 
336
- | Data Type | Latency Reduction (disabled) | Size Overhead |
337
- |:----------|:----------------------------:|:-------------:|
338
- | MessagePack (default) | 60-90% | 8 bytes |
339
- | Arrow DataFrames | 35-49% | 8 bytes |
340
- | JSON (orjson) | 37-68% | 8 bytes |
362
+ Where the switch drops the LZ4 envelope, an entry gets larger only when LZ4 saved more than the envelope's overhead of about 25 to 30 bytes; otherwise it stays the same size or gets smaller. Measure on your own payloads before you trade that.
341
363
 
342
364
  ### Security
343
365
 
@@ -374,7 +396,7 @@ make security-fast # Run fast checks (< 3 min)
374
396
  | Tier | Time | Coverage |
375
397
  |:-----|:----:|:---------|
376
398
  | Fast | < 3 min | Vulnerability scanning, license checks, linting |
377
- | Medium | < 15 min | Unsafe code analysis, API stability, Miri subset |
399
+ | Medium | < 15 min | Unsafe code analysis (cargo-geiger) |
378
400
  | Deep | < 2 hours | Formal verification, extended fuzzing, full sanitizers |
379
401
 
380
402
  See [SECURITY.md][security-url] for vulnerability reporting and detailed documentation.
@@ -416,11 +438,14 @@ exposition setup.
416
438
  <details>
417
439
  <summary><strong>Thread Safety Details</strong></summary>
418
440
 
419
- **Free-threaded CPython (3.14t):** the core suites run green on
420
- free-threaded 3.14 with the GIL verified disabled (CI job
441
+ **Free-threaded CPython (3.15t, 3.14t):** the core suites run green on
442
+ free-threaded 3.14 and 3.15 with the GIL verified disabled (CI job
421
443
  `test-freethreaded`), and the Rust extension declares free-threaded safety
422
- (`gil_used = false`). Free-threaded wheels are **not yet published** and
423
- free-threaded builds are not officially supported — blocked upstream on
444
+ (`gil_used = false`). **From the release after 0.24.1, 3.15t has a wheel**:
445
+ the 3.15+ wheel is `abi3t`, so it installs on 3.15t without a Rust toolchain
446
+ (pip 26.1+ or uv 0.11.3+). **3.14t is tested
447
+ but has no wheel** (it builds from source). Free-threaded builds are not
448
+ officially supported yet — blocked upstream on
424
449
  orjson (no free-threaded wheels) and hiredis (re-enables the GIL on import;
425
450
  cachekit loads redis-py only for its Redis backend, and keeps hiredis out there,
426
451
  so redis-py uses its pure-Python parser). See
@@ -429,7 +454,7 @@ full concurrency audit: [docs/free-threading.md](docs/free-threading.md).
429
454
 
430
455
  **Per-Function Statistics:**
431
456
  - Statistics tracked per function identity (`module.qualname`), shared across all calls and across re-decorations of the same function
432
- - Thread-safe via RLock (all methods safe for concurrent access)
457
+ - Thread-safe: every count is exact (L1 hits on an atomic counter, everything else under an RLock), and all methods are safe for concurrent access
433
458
  - Fork-safe: a forked child starts with zeroed counters and its own session ID
434
459
 
435
460
  ```python
@@ -478,6 +503,7 @@ info = expensive_func.cache_info()
478
503
  | [Reference Caching][reference-caching-url] | `@cache.local()` for non-serializable objects |
479
504
  | [Rust Serialization][rust-serialization-url] | ByteStorage layer: LZ4, xxHash3, AES-256-GCM |
480
505
  | [SSRF Protection][ssrf-url] | URL allowlisting for the CachekitIO backend |
506
+ | [Write-Behind][write-behind-url] | Opt-in `write_behind=True`: a miss returns before its L2 write lands |
481
507
 
482
508
  ---
483
509
 
@@ -531,7 +557,7 @@ See [CONTRIBUTING.md][contributing-url] for full development guidelines.
531
557
 
532
558
  | Component | Version |
533
559
  |:----------|:--------|
534
- | Python | 3.10+ |
560
+ | Python | 3.11+ |
535
561
 
536
562
  ---
537
563
 
@@ -569,6 +595,7 @@ MIT License - see [LICENSE][license-file-url] for details.
569
595
  [reference-caching-url]: docs/features/reference-caching.md
570
596
  [rust-serialization-url]: docs/features/rust-serialization.md
571
597
  [ssrf-url]: docs/features/ssrf-protection.md
598
+ [write-behind-url]: docs/features/write-behind.md
572
599
  [contributing-url]: CONTRIBUTING.md
573
600
  [license-file-url]: LICENSE
574
601
  [github-url]: https://github.com/cachekit-io/cachekit-py