cachebox 6.2.5__tar.gz → 6.2.7__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 (88) hide show
  1. {cachebox-6.2.5 → cachebox-6.2.7}/.github/workflows/CI.yml +29 -21
  2. {cachebox-6.2.5 → cachebox-6.2.7}/.github/workflows/docs.yml +1 -1
  3. {cachebox-6.2.5 → cachebox-6.2.7}/.github/workflows/python-test.yml +3 -3
  4. {cachebox-6.2.5 → cachebox-6.2.7}/Cargo.lock +13 -13
  5. {cachebox-6.2.5 → cachebox-6.2.7}/Cargo.toml +1 -1
  6. {cachebox-6.2.5 → cachebox-6.2.7}/PKG-INFO +1 -1
  7. {cachebox-6.2.5 → cachebox-6.2.7}/cachebox/_cachebox.py +18 -16
  8. {cachebox-6.2.5 → cachebox-6.2.7}/cachebox/_wrappers.py +20 -18
  9. {cachebox-6.2.5 → cachebox-6.2.7}/cachebox/utils.py +22 -30
  10. cachebox-6.2.7/docs/docs/algorithms.md +280 -0
  11. {cachebox-6.2.5 → cachebox-6.2.7}/docs/docs/api/impls.md +10 -2
  12. cachebox-6.2.7/docs/docs/api/index.md +71 -0
  13. {cachebox-6.2.5 → cachebox-6.2.7}/docs/docs/api/utils.md +20 -0
  14. cachebox-6.2.7/docs/docs/faq.md +164 -0
  15. cachebox-6.2.7/docs/docs/getting-started.md +421 -0
  16. cachebox-6.2.7/docs/docs/index.md +94 -0
  17. cachebox-6.2.7/docs/docs/installation.md +58 -0
  18. cachebox-6.2.7/docs/docs/migration.md +156 -0
  19. cachebox-6.2.7/docs/docs/tips.md +361 -0
  20. {cachebox-6.2.5 → cachebox-6.2.7}/docs/mkdocs.yml +4 -2
  21. {cachebox-6.2.5 → cachebox-6.2.7}/src/policies/fifopolicy.rs +2 -2
  22. {cachebox-6.2.5 → cachebox-6.2.7}/src/policies/lfupolicy.rs +2 -2
  23. {cachebox-6.2.5 → cachebox-6.2.7}/src/policies/lrupolicy.rs +2 -2
  24. {cachebox-6.2.5 → cachebox-6.2.7}/src/policies/nopolicy.rs +2 -2
  25. {cachebox-6.2.5 → cachebox-6.2.7}/src/policies/rrpolicy.rs +2 -2
  26. {cachebox-6.2.5 → cachebox-6.2.7}/src/policies/traits.rs +1 -1
  27. {cachebox-6.2.5 → cachebox-6.2.7}/src/policies/ttlpolicy.rs +2 -2
  28. {cachebox-6.2.5 → cachebox-6.2.7}/src/policies/vttlpolicy.rs +2 -2
  29. {cachebox-6.2.5 → cachebox-6.2.7}/src/policies/wrapped.rs +12 -2
  30. {cachebox-6.2.5 → cachebox-6.2.7}/src/pyclasses/cache.rs +3 -1
  31. {cachebox-6.2.5 → cachebox-6.2.7}/src/pyclasses/fifocache.rs +3 -1
  32. {cachebox-6.2.5 → cachebox-6.2.7}/src/pyclasses/lfucache.rs +3 -1
  33. {cachebox-6.2.5 → cachebox-6.2.7}/src/pyclasses/lrucache.rs +3 -1
  34. {cachebox-6.2.5 → cachebox-6.2.7}/src/pyclasses/rrcache.rs +3 -1
  35. {cachebox-6.2.5 → cachebox-6.2.7}/src/pyclasses/ttlcache.rs +3 -1
  36. {cachebox-6.2.5 → cachebox-6.2.7}/src/pyclasses/vttlcache.rs +3 -1
  37. cachebox-6.2.7/tests/__init__.py +0 -0
  38. {cachebox-6.2.5 → cachebox-6.2.7}/tests/mixins.py +92 -10
  39. {cachebox-6.2.5 → cachebox-6.2.7}/typos.toml +1 -7
  40. cachebox-6.2.5/docs/docs/api/index.md +0 -4
  41. cachebox-6.2.5/docs/docs/getting-started.md +0 -322
  42. cachebox-6.2.5/docs/docs/index.md +0 -76
  43. cachebox-6.2.5/docs/docs/installation.md +0 -32
  44. cachebox-6.2.5/docs/docs/migration.md +0 -140
  45. cachebox-6.2.5/docs/docs/tips.md +0 -310
  46. {cachebox-6.2.5 → cachebox-6.2.7}/.github/dependabot.yaml +0 -0
  47. {cachebox-6.2.5 → cachebox-6.2.7}/.gitignore +0 -0
  48. {cachebox-6.2.5 → cachebox-6.2.7}/LICENSE +0 -0
  49. {cachebox-6.2.5 → cachebox-6.2.7}/LICENSE-THIRD-PARTY +0 -0
  50. {cachebox-6.2.5 → cachebox-6.2.7}/README.md +0 -0
  51. {cachebox-6.2.5 → cachebox-6.2.7}/build.rs +0 -0
  52. {cachebox-6.2.5 → cachebox-6.2.7}/cachebox/__init__.py +0 -0
  53. {cachebox-6.2.5 → cachebox-6.2.7}/cachebox/_core.pyi +0 -0
  54. /cachebox-6.2.5/tests/__init__.py → /cachebox-6.2.7/cachebox/py.typed +0 -0
  55. {cachebox-6.2.5 → cachebox-6.2.7}/pyproject.toml +0 -0
  56. {cachebox-6.2.5 → cachebox-6.2.7}/rust-toolchain.toml +0 -0
  57. {cachebox-6.2.5 → cachebox-6.2.7}/rustfmt.toml +0 -0
  58. {cachebox-6.2.5 → cachebox-6.2.7}/src/hashbrown/alloc.rs +0 -0
  59. {cachebox-6.2.5 → cachebox-6.2.7}/src/hashbrown/control/bitmask.rs +0 -0
  60. {cachebox-6.2.5 → cachebox-6.2.7}/src/hashbrown/control/group/generic.rs +0 -0
  61. {cachebox-6.2.5 → cachebox-6.2.7}/src/hashbrown/control/group/lsx.rs +0 -0
  62. {cachebox-6.2.5 → cachebox-6.2.7}/src/hashbrown/control/group/mod.rs +0 -0
  63. {cachebox-6.2.5 → cachebox-6.2.7}/src/hashbrown/control/group/neon.rs +0 -0
  64. {cachebox-6.2.5 → cachebox-6.2.7}/src/hashbrown/control/group/sse2.rs +0 -0
  65. {cachebox-6.2.5 → cachebox-6.2.7}/src/hashbrown/control/mod.rs +0 -0
  66. {cachebox-6.2.5 → cachebox-6.2.7}/src/hashbrown/control/tag.rs +0 -0
  67. {cachebox-6.2.5 → cachebox-6.2.7}/src/hashbrown/mod.rs +0 -0
  68. {cachebox-6.2.5 → cachebox-6.2.7}/src/hashbrown/raw.rs +0 -0
  69. {cachebox-6.2.5 → cachebox-6.2.7}/src/hashbrown/scopeguard.rs +0 -0
  70. {cachebox-6.2.5 → cachebox-6.2.7}/src/hashbrown/util.rs +0 -0
  71. {cachebox-6.2.5 → cachebox-6.2.7}/src/internal/alias.rs +0 -0
  72. {cachebox-6.2.5 → cachebox-6.2.7}/src/internal/lazyheap.rs +0 -0
  73. {cachebox-6.2.5 → cachebox-6.2.7}/src/internal/linked_list.rs +0 -0
  74. {cachebox-6.2.5 → cachebox-6.2.7}/src/internal/mod.rs +0 -0
  75. {cachebox-6.2.5 → cachebox-6.2.7}/src/internal/onceinit.rs +0 -0
  76. {cachebox-6.2.5 → cachebox-6.2.7}/src/internal/pickle.rs +0 -0
  77. {cachebox-6.2.5 → cachebox-6.2.7}/src/internal/utils.rs +0 -0
  78. {cachebox-6.2.5 → cachebox-6.2.7}/src/lib.rs +0 -0
  79. {cachebox-6.2.5 → cachebox-6.2.7}/src/macro_rules.rs +0 -0
  80. {cachebox-6.2.5 → cachebox-6.2.7}/src/policies/common.rs +0 -0
  81. {cachebox-6.2.5 → cachebox-6.2.7}/src/policies/mod.rs +0 -0
  82. {cachebox-6.2.5 → cachebox-6.2.7}/src/pyclasses/base.rs +0 -0
  83. {cachebox-6.2.5 → cachebox-6.2.7}/src/pyclasses/mod.rs +0 -0
  84. {cachebox-6.2.5 → cachebox-6.2.7}/src/typeref.rs +0 -0
  85. {cachebox-6.2.5 → cachebox-6.2.7}/tests/conftest.py +0 -0
  86. {cachebox-6.2.5 → cachebox-6.2.7}/tests/test_impls.py +0 -0
  87. {cachebox-6.2.5 → cachebox-6.2.7}/tests/test_utils.py +0 -0
  88. {cachebox-6.2.5 → cachebox-6.2.7}/uv.lock +0 -0
@@ -16,6 +16,7 @@ concurrency:
16
16
  env:
17
17
  (^_^): &interpreters "3.10 3.11 3.12 3.13 3.14 3.14t 3.15 3.15t pypy3.11"
18
18
  ○_○: &interpreters_without_pypy "3.10 3.11 3.12 3.13 3.14 3.14t 3.15 3.15t"
19
+ (o_o): &interpreters_win_arm64 "3.11 3.12 3.13 3.14 3.14t 3.15 3.15t"
19
20
 
20
21
  jobs:
21
22
  tools:
@@ -41,7 +42,7 @@ jobs:
41
42
  python-version: "3.14"
42
43
 
43
44
  - name: "Install uv"
44
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
45
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
45
46
  with:
46
47
  # zizmor: ignore[cache-poisoning]
47
48
  enable-cache: ${{ github.event_name == 'pull_request' }}
@@ -57,21 +58,24 @@ jobs:
57
58
  strategy:
58
59
  matrix:
59
60
  platform:
60
- - { target: x86_64, interpreter: *interpreters }
61
- - { target: x86, interpreter: *interpreters }
62
- - { target: aarch64, interpreter: *interpreters }
63
- - { target: armv7, interpreter: *interpreters }
64
- - { target: s390x, interpreter: *interpreters }
65
- - { target: ppc64le, interpreter: *interpreters }
61
+ - { target: x86_64-unknown-linux-gnu, arch: x86_64, interpreter: *interpreters }
62
+ - { target: i686-unknown-linux-gnu, arch: x86, interpreter: *interpreters }
63
+ - { target: aarch64-unknown-linux-gnu, arch: aarch64, interpreter: *interpreters }
64
+ - { target: armv7-unknown-linux-gnueabihf, arch: armv7, interpreter: *interpreters }
65
+ - { target: s390x-unknown-linux-gnu, arch: s390x, interpreter: *interpreters }
66
+ - { target: powerpc64le-unknown-linux-gnu, arch: ppc64le, interpreter: *interpreters }
67
+ - { target: riscv64gc-unknown-linux-gnu, arch: riscv64, interpreter: *interpreters }
66
68
 
67
69
  steps:
68
70
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
69
71
  with:
70
72
  persist-credentials: false
71
73
 
72
- - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
74
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
73
75
  with:
74
- python-version: "3.x"
76
+ activate-environment: true
77
+ enable-cache: false
78
+ python-version: "3"
75
79
 
76
80
  - uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0
77
81
  # zizmor: ignore[cache-poisoning]
@@ -87,7 +91,7 @@ jobs:
87
91
 
88
92
  - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
89
93
  with:
90
- name: wheels-linux-${{ matrix.platform.target }}
94
+ name: wheels-linux-${{ matrix.platform.arch }}
91
95
  path: dist
92
96
 
93
97
  build-musllinux:
@@ -95,19 +99,22 @@ jobs:
95
99
  strategy:
96
100
  matrix:
97
101
  platform:
98
- - { target: x86_64, interpreter: *interpreters }
99
- - { target: x86, interpreter: *interpreters }
100
- - { target: aarch64, interpreter: *interpreters }
101
- - { target: armv7, interpreter: *interpreters }
102
+ - { target: x86_64-unknown-linux-musl, arch: x86_64, interpreter: *interpreters }
103
+ - { target: i686-unknown-linux-musl, arch: x86, interpreter: *interpreters }
104
+ - { target: aarch64-unknown-linux-musl, arch: aarch64, interpreter: *interpreters }
105
+ - { target: armv7-unknown-linux-musleabihf, arch: armv7, interpreter: *interpreters }
106
+ - { target: riscv64gc-unknown-linux-musl, arch: riscv64, interpreter: *interpreters }
102
107
 
103
108
  steps:
104
109
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
105
110
  with:
106
111
  persist-credentials: false
107
112
 
108
- - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
113
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
109
114
  with:
110
- python-version: "3.x"
115
+ activate-environment: true
116
+ enable-cache: false
117
+ python-version: "3"
111
118
 
112
119
  - uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0
113
120
  # zizmor: ignore[cache-poisoning]
@@ -123,16 +130,17 @@ jobs:
123
130
 
124
131
  - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
125
132
  with:
126
- name: wheels-musllinux-${{ matrix.platform.target }}
133
+ name: wheels-musllinux-${{ matrix.platform.arch }}
127
134
  path: dist
128
135
 
129
136
  build-windows:
130
- runs-on: windows-latest
137
+ runs-on: ${{ matrix.platform.runner }}
131
138
  strategy:
132
139
  matrix:
133
140
  platform:
134
- - { target: x64, interpreter: *interpreters }
135
- - { target: x86, interpreter: *interpreters_without_pypy }
141
+ - { runner: windows-latest, target: x64, arch: x64, interpreter: *interpreters }
142
+ - { runner: windows-latest, target: x86, arch: x86, interpreter: *interpreters_without_pypy }
143
+ - { runner: windows-11-arm, target: aarch64, arch: arm64, interpreter: *interpreters_win_arm64 }
136
144
 
137
145
  steps:
138
146
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -142,7 +150,7 @@ jobs:
142
150
  - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
143
151
  with:
144
152
  python-version: "3.x"
145
- architecture: ${{ matrix.platform.target }}
153
+ architecture: ${{ matrix.platform.arch }}
146
154
 
147
155
  - uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0
148
156
  # zizmor: ignore[cache-poisoning]
@@ -20,7 +20,7 @@ jobs:
20
20
  python-version: 3.14
21
21
 
22
22
  - name: "Install uv"
23
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
23
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
24
24
  with:
25
25
  enable-cache: false
26
26
 
@@ -40,7 +40,7 @@ jobs:
40
40
 
41
41
  - uses: dtolnay/rust-toolchain@stable # zizmor: ignore[unpinned-uses]
42
42
 
43
- - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
43
+ - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
44
44
  if: github.event_name == 'pull_request' && github.run_attempt == 1
45
45
  with:
46
46
  lookup-only: false # zizmor: ignore[cache-poisoning]
@@ -52,7 +52,7 @@ jobs:
52
52
  allow-prereleases: true
53
53
 
54
54
  - name: "Install uv"
55
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
55
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
56
56
  with:
57
57
  enable-cache: false
58
58
 
@@ -93,7 +93,7 @@ jobs:
93
93
  python-version: "3.13"
94
94
 
95
95
  - name: "Install uv"
96
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
96
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
97
97
  with:
98
98
  enable-cache: false
99
99
 
@@ -37,7 +37,7 @@ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
37
37
 
38
38
  [[package]]
39
39
  name = "cachebox"
40
- version = "6.2.5"
40
+ version = "6.2.7"
41
41
  dependencies = [
42
42
  "allocator-api2",
43
43
  "cfg-if",
@@ -50,9 +50,9 @@ dependencies = [
50
50
 
51
51
  [[package]]
52
52
  name = "cc"
53
- version = "1.4.2"
53
+ version = "1.4.4"
54
54
  source = "registry+https://github.com/rust-lang/crates.io-index"
55
- checksum = "5d262e149917187838d5b42777c8253bcb64500067342904e7d429499a6f277e"
55
+ checksum = "0ad534f4357a5264cce5019c989cf66a4f0dc4e0d1b1d15f8aacec0ff7360273"
56
56
  dependencies = [
57
57
  "find-msvc-tools",
58
58
  "shlex",
@@ -91,27 +91,27 @@ checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
91
91
 
92
92
  [[package]]
93
93
  name = "find-msvc-tools"
94
- version = "0.1.10"
94
+ version = "0.1.11"
95
95
  source = "registry+https://github.com/rust-lang/crates.io-index"
96
- checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de"
96
+ checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890"
97
97
 
98
98
  [[package]]
99
99
  name = "futures-core"
100
- version = "0.3.33"
100
+ version = "0.3.34"
101
101
  source = "registry+https://github.com/rust-lang/crates.io-index"
102
- checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7"
102
+ checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
103
103
 
104
104
  [[package]]
105
105
  name = "futures-task"
106
- version = "0.3.33"
106
+ version = "0.3.34"
107
107
  source = "registry+https://github.com/rust-lang/crates.io-index"
108
- checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109"
108
+ checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"
109
109
 
110
110
  [[package]]
111
111
  name = "futures-util"
112
- version = "0.3.33"
112
+ version = "0.3.34"
113
113
  source = "registry+https://github.com/rust-lang/crates.io-index"
114
- checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa"
114
+ checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
115
115
  dependencies = [
116
116
  "futures-core",
117
117
  "futures-task",
@@ -177,9 +177,9 @@ dependencies = [
177
177
 
178
178
  [[package]]
179
179
  name = "log"
180
- version = "0.4.33"
180
+ version = "0.4.34"
181
181
  source = "registry+https://github.com/rust-lang/crates.io-index"
182
- checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
182
+ checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
183
183
 
184
184
  [[package]]
185
185
  name = "num-traits"
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "cachebox"
3
- version = "6.2.5"
3
+ version = "6.2.7"
4
4
  edition = "2021"
5
5
  description = "The fastest memoizing and caching Python library written in Rust"
6
6
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cachebox
3
- Version: 6.2.5
3
+ Version: 6.2.7
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python
6
6
  Classifier: Programming Language :: Python :: 3
@@ -161,16 +161,15 @@ class TTLCache(_CoreTTLCache[KT, VT]):
161
161
  )
162
162
 
163
163
  self._thread: threading.Thread | None = None
164
- self._thread_is_running: bool = False
164
+ self._stop_event = threading.Event()
165
165
 
166
166
  if sweep_interval is not None:
167
167
  if isinstance(sweep_interval, timedelta):
168
168
  sweep_interval = sweep_interval.total_seconds()
169
169
 
170
170
  if sweep_interval < 1:
171
- raise ValueError("sweep_interval must be more than 1 seconds.")
171
+ raise ValueError("sweep_interval must be at least 1 second.")
172
172
 
173
- self._thread_is_running = True
174
173
  self._thread = threading.Thread(
175
174
  target=self._sweeper_thread,
176
175
  args=(sweep_interval,),
@@ -185,17 +184,19 @@ class TTLCache(_CoreTTLCache[KT, VT]):
185
184
  """The configured ``sweep_interval`` in seconds."""
186
185
  return self._sweep_interval
187
186
 
188
- def _sweeper_thread(self, interval: float):
189
- while self._thread_is_running:
190
- time.sleep(interval)
187
+ def _sweeper_thread(self, interval: float) -> None:
188
+ while not self._stop_event.wait(interval):
191
189
  self.expire()
192
190
 
193
191
  def stop_sweeper(self) -> None:
194
192
  """Signals the background sweeper thread to stop, if one is active."""
195
- self._thread_is_running = False
193
+ self._stop_event.set()
196
194
 
197
195
  def __del__(self) -> None:
198
- self.stop_sweeper()
196
+ # If super().__init__ raises for any reason (bad arguments, type error, ...),
197
+ # the assignment to self._stop_event never happens.
198
+ if hasattr(self, "_stop_event"):
199
+ self.stop_sweeper()
199
200
 
200
201
 
201
202
  class VTTLCache(_CoreVTTLCache[KT, VT]):
@@ -333,16 +334,15 @@ class VTTLCache(_CoreVTTLCache[KT, VT]):
333
334
  )
334
335
 
335
336
  self._thread: threading.Thread | None = None
336
- self._thread_is_running: bool = False
337
+ self._stop_event = threading.Event()
337
338
 
338
339
  if sweep_interval is not None:
339
340
  if isinstance(sweep_interval, timedelta):
340
341
  sweep_interval = sweep_interval.total_seconds()
341
342
 
342
343
  if sweep_interval < 1:
343
- raise ValueError("sweep_interval must be more than 1 seconds.")
344
+ raise ValueError("sweep_interval must be at least 1 second.")
344
345
 
345
- self._thread_is_running = True
346
346
  self._thread = threading.Thread(
347
347
  target=self._sweeper_thread,
348
348
  args=(sweep_interval,),
@@ -357,14 +357,16 @@ class VTTLCache(_CoreVTTLCache[KT, VT]):
357
357
  """The configured ``sweep_interval`` in seconds."""
358
358
  return self._sweep_interval
359
359
 
360
- def _sweeper_thread(self, interval: float):
361
- while self._thread_is_running:
362
- time.sleep(interval)
360
+ def _sweeper_thread(self, interval: float) -> None:
361
+ while not self._stop_event.wait(interval):
363
362
  self.expire()
364
363
 
365
364
  def stop_sweeper(self) -> None:
366
365
  """Signals the background sweeper thread to stop, if one is active."""
367
- self._thread_is_running = False
366
+ self._stop_event.set()
368
367
 
369
368
  def __del__(self) -> None:
370
- self.stop_sweeper()
369
+ # If super().__init__ raises for any reason (bad arguments, type error, ...),
370
+ # the assignment to self._stop_event never happens.
371
+ if hasattr(self, "_stop_event"):
372
+ self.stop_sweeper()
@@ -2,12 +2,14 @@ import inspect
2
2
  import typing
3
3
  from collections import namedtuple
4
4
  from contextlib import AbstractAsyncContextManager, AbstractContextManager
5
+ from collections.abc import Callable, Hashable
5
6
 
6
7
  from cachebox._core import BaseCacheImpl, Cache
7
8
 
8
- _PostProcess: typing.TypeAlias = typing.Callable[[typing.Any], typing.Any]
9
- _Callback: typing.TypeAlias = typing.Callable[[int, typing.Any, typing.Any], typing.Any]
10
-
9
+ _PostProcess: typing.TypeAlias = Callable[[typing.Any], typing.Any]
10
+ _Callback: typing.TypeAlias = Callable[
11
+ [int, typing.Any, typing.Any], typing.Any
12
+ ]
11
13
 
12
14
  class _Lock:
13
15
  __slots__ = ("_lock", "waiters")
@@ -65,10 +67,10 @@ def _create_cache_info(cache, hits, misses) -> CacheInfo:
65
67
 
66
68
  def _cached_wrapper_without_lock(
67
69
  func,
68
- cache: BaseCacheImpl | typing.Callable,
69
- key_maker: typing.Callable[[tuple, dict], typing.Hashable],
70
+ cache: BaseCacheImpl | Callable,
71
+ key_maker: Callable[[tuple, dict], Hashable],
70
72
  clear_reuse: bool,
71
- callback: typing.Callable[[int, typing.Any, typing.Any], None] | None,
73
+ callback: Callable[[int, typing.Any, typing.Any], None] | None,
72
74
  postprocess: _PostProcess | None,
73
75
  ):
74
76
  cache_is_fn = callable(cache)
@@ -139,10 +141,10 @@ async def _call_async_callback(callback, event, key, result):
139
141
 
140
142
  def _async_cached_wrapper_without_lock(
141
143
  func,
142
- cache: BaseCacheImpl | typing.Callable,
143
- key_maker: typing.Callable[[tuple, dict], typing.Hashable],
144
+ cache: BaseCacheImpl | Callable,
145
+ key_maker: Callable[[tuple, dict], Hashable],
144
146
  clear_reuse: bool,
145
- callback: typing.Callable[[int, typing.Any, typing.Any], None] | None,
147
+ callback: Callable[[int, typing.Any, typing.Any], None] | None,
146
148
  postprocess: _PostProcess | None,
147
149
  ):
148
150
  cache_is_fn = callable(cache)
@@ -179,7 +181,7 @@ def _async_cached_wrapper_without_lock(
179
181
 
180
182
  result = await func(*args, **kwds)
181
183
  _cache.insert(key, result)
182
- hits += 1
184
+ misses += 1
183
185
  await _call_async_callback(callback, EVENT_MISS, key, result)
184
186
 
185
187
  return postprocess(result) if postprocess is not None else result
@@ -202,12 +204,12 @@ def _async_cached_wrapper_without_lock(
202
204
 
203
205
  def _cached_wrapper(
204
206
  func,
205
- cache: BaseCacheImpl | typing.Callable,
206
- key_maker: typing.Callable[[tuple, dict], typing.Hashable],
207
+ cache: BaseCacheImpl | Callable,
208
+ key_maker: Callable[[tuple, dict], Hashable],
207
209
  clear_reuse: bool,
208
- callback: typing.Callable[[int, typing.Any, typing.Any], None] | None,
210
+ callback: Callable[[int, typing.Any, typing.Any], None] | None,
209
211
  postprocess: _PostProcess | None,
210
- lock_type: typing.Type[AbstractContextManager],
212
+ lock_type: type[AbstractContextManager],
211
213
  ):
212
214
  cache_is_fn = callable(cache)
213
215
 
@@ -221,8 +223,8 @@ def _cached_wrapper(
221
223
  hits = 0
222
224
  misses = 0
223
225
 
224
- locks: Cache[typing.Hashable, _Lock] = Cache(0)
225
- pending_errors: dict[typing.Hashable, BaseException] = {}
226
+ locks: Cache[Hashable, _Lock] = Cache(0)
227
+ pending_errors: dict[Hashable, BaseException] = {}
226
228
 
227
229
  def _wrapped(*args, **kwds):
228
230
  nonlocal hits, misses
@@ -308,12 +310,12 @@ def _cached_wrapper(
308
310
 
309
311
  def _async_cached_wrapper(
310
312
  func,
311
- cache: BaseCacheImpl | typing.Callable,
313
+ cache: BaseCacheImpl | Callable,
312
314
  key_maker: typing.Callable[..., typing.Hashable],
313
315
  clear_reuse: bool,
314
316
  callback: _Callback | None,
315
317
  postprocess: _PostProcess | None,
316
- lock_type: typing.Type[AbstractAsyncContextManager],
318
+ lock_type: type[AbstractAsyncContextManager],
317
319
  ):
318
320
  cache_is_fn = callable(cache)
319
321
  _make_key = (
@@ -1,13 +1,16 @@
1
+ import _thread
2
+ import asyncio
1
3
  import functools
2
4
  import inspect
5
+ import threading
3
6
  import typing
7
+ from collections.abc import Callable, Hashable
8
+ from contextlib import AbstractAsyncContextManager, AbstractContextManager
4
9
  from copy import copy as _shallow_copy
5
10
  from copy import deepcopy as _deep_copy
6
11
 
7
12
  from ._cachebox import BaseCacheImpl, LRUCache
8
13
  from ._wrappers import (
9
- AbstractAsyncContextManager,
10
- AbstractContextManager,
11
14
  CacheInfo,
12
15
  _async_cached_wrapper,
13
16
  _async_cached_wrapper_without_lock,
@@ -23,7 +26,7 @@ if typing.TYPE_CHECKING:
23
26
  KT = typing.TypeVar("KT")
24
27
  VT = typing.TypeVar("VT")
25
28
  DT = typing.TypeVar("DT")
26
- FT = typing.TypeVar("FT", bound=typing.Callable[..., typing.Any])
29
+ FT = typing.TypeVar("FT", bound=Callable[..., typing.Any])
27
30
 
28
31
 
29
32
  _COPY_TYPES = frozenset((dict, list, set))
@@ -63,7 +66,7 @@ _KWDS_MARK = object()
63
66
  _FAST_TYPES = frozenset((int, str))
64
67
 
65
68
 
66
- def make_key(*args, **kwds) -> typing.Hashable:
69
+ def make_key(*args: typing.Any, **kwds: typing.Any) -> Hashable:
67
70
  """
68
71
  Default cache key.
69
72
 
@@ -83,7 +86,7 @@ def make_key(*args, **kwds) -> typing.Hashable:
83
86
  return key
84
87
 
85
88
 
86
- def make_hash_key(*args, **kwds) -> int:
89
+ def make_hash_key(*args: typing.Any, **kwds: typing.Any) -> int:
87
90
  """
88
91
  Key as the hash of all positional and keyword arguments.
89
92
 
@@ -98,7 +101,7 @@ def make_hash_key(*args, **kwds) -> int:
98
101
  return hash(key)
99
102
 
100
103
 
101
- def make_typed_key(*args, **kwds) -> tuple:
104
+ def make_typed_key(*args: typing.Any, **kwds: typing.Any) -> tuple[typing.Any, ...]:
102
105
  """
103
106
  Key that includes the runtime type of every argument.
104
107
 
@@ -183,7 +186,7 @@ class Frozen(BaseCacheImpl[KT, VT]): # pragma: no cover
183
186
  return self.__cache.maxsize
184
187
 
185
188
  @property
186
- def getsizeof(self) -> typing.Callable[[KT, VT], int] | None:
189
+ def getsizeof(self) -> Callable[[KT, VT], int] | None:
187
190
  """Callable or None: The configured ``getsizeof`` function."""
188
191
  return self.__cache.getsizeof
189
192
 
@@ -271,7 +274,7 @@ class Frozen(BaseCacheImpl[KT, VT]): # pragma: no cover
271
274
  value: VT,
272
275
  *args: typing.Any,
273
276
  **kwargs: typing.Any,
274
- ) -> typing.Optional[VT]:
277
+ ) -> VT | None:
275
278
  return self._guard()
276
279
 
277
280
  def __setitem__(self, key: KT, value: VT) -> None:
@@ -285,7 +288,7 @@ class Frozen(BaseCacheImpl[KT, VT]): # pragma: no cover
285
288
  ) -> None:
286
289
  return self._guard()
287
290
 
288
- def get(self, key: KT, default: typing.Optional[DT] = None) -> typing.Union[VT, DT]:
291
+ def get(self, key: KT, default: DT | None = None) -> VT | DT:
289
292
  return self.__cache.get(key, default)
290
293
 
291
294
  def __getitem__(self, key: KT) -> VT:
@@ -294,13 +297,13 @@ class Frozen(BaseCacheImpl[KT, VT]): # pragma: no cover
294
297
  def setdefault(
295
298
  self,
296
299
  key: KT,
297
- default: typing.Optional[DT] = None,
300
+ default: DT | None = None,
298
301
  *args: typing.Any,
299
302
  **kwargs: typing.Any,
300
- ) -> typing.Optional[VT | DT]:
303
+ ) -> VT | DT | None:
301
304
  return self._guard()
302
305
 
303
- def pop(self, key: KT, default: DT = None) -> typing.Union[VT, DT]:
306
+ def pop(self, key: KT, default: DT | None = None) -> VT | DT:
304
307
  """
305
308
  Removes the specified key and returns the corresponding value.
306
309
 
@@ -319,7 +322,7 @@ class Frozen(BaseCacheImpl[KT, VT]): # pragma: no cover
319
322
  def __delitem__(self, key: KT) -> None:
320
323
  return self._guard()
321
324
 
322
- def popitem(self) -> typing.Tuple[KT, VT]:
325
+ def popitem(self) -> tuple[KT, VT]:
323
326
  return self._guard() # type: ignore[return-value]
324
327
 
325
328
  def drain(self, n: int) -> int:
@@ -348,7 +351,7 @@ class Frozen(BaseCacheImpl[KT, VT]): # pragma: no cover
348
351
  """
349
352
  return self._guard()
350
353
 
351
- def items(self) -> typing.Iterable[typing.Tuple[KT, VT]]:
354
+ def items(self) -> typing.Iterable[tuple[KT, VT]]:
352
355
  return self.__cache.items()
353
356
 
354
357
  def values(self) -> typing.Iterable[VT]:
@@ -373,20 +376,9 @@ class Frozen(BaseCacheImpl[KT, VT]): # pragma: no cover
373
376
  def _cast_lock(
374
377
  iscoroutinefunction: bool,
375
378
  lock: (
376
- typing.Type[AbstractContextManager]
377
- | typing.Type[AbstractAsyncContextManager]
378
- | bool
379
- | None
379
+ type[AbstractContextManager] | type[AbstractAsyncContextManager] | bool | None
380
380
  ) = True,
381
- ) -> (
382
- typing.Type[AbstractContextManager]
383
- | typing.Type[AbstractAsyncContextManager]
384
- | None
385
- ):
386
- import _thread
387
- import asyncio
388
- import threading
389
-
381
+ ) -> type[AbstractContextManager] | type[AbstractAsyncContextManager] | None:
390
382
  if lock is None or lock is False:
391
383
  return None
392
384
 
@@ -416,8 +408,8 @@ def _cast_lock(
416
408
 
417
409
 
418
410
  def cached(
419
- cache: BaseCacheImpl | dict | typing.Callable[..., BaseCacheImpl] | None = None,
420
- key_maker: typing.Callable[..., typing.Hashable] = make_key,
411
+ cache: BaseCacheImpl | dict | Callable[..., BaseCacheImpl] | None = None,
412
+ key_maker: Callable[..., Hashable] = make_key,
421
413
  clear_reuse: bool = False,
422
414
  callback: _Callback | None = None,
423
415
  copy_level: int = 1,
@@ -428,7 +420,7 @@ def cached(
428
420
  | bool
429
421
  | None
430
422
  ) = True,
431
- ) -> typing.Callable[[FT], FT]:
423
+ ) -> Callable[[FT], FT]:
432
424
  """
433
425
  Decorator to memoize function/method results.
434
426