Skip to content

Commit 193fd31

Browse files
committed
Support free-threading, __str__ changed to __repr__, and dependencies updated
1 parent e624506 commit 193fd31

20 files changed

+59
-50
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## 4.3.1 - 2024-11-18
9+
### Changed
10+
- `__str__` changed to `__repr__`
11+
- Free-threading is supported now
12+
- Dependencies updated
13+
814
## 4.3.0 - 2024-11-08
915
### Added
1016
- Add `always_copy` parameter to `cached` and `cachedmethod` decorators

Cargo.lock

+11-11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cachebox"
3-
version = "4.3.0"
3+
version = "4.3.1"
44
edition = "2021"
55
description = "The fastest memoizing and caching Python library written in Rust"
66
readme = "README.md"
@@ -23,14 +23,14 @@ strip = "symbols"
2323
[dependencies]
2424
hashbrown = { version = "^0.14", default-features = false, features=["inline-more", "raw"]}
2525
fastrand = "^2.1"
26-
pyo3 = { version = "0.22.6", default-features = false, features=["macros", "extension-module"] }
26+
pyo3 = { version = "0.23.1", default-features = false, features=["macros", "extension-module"] }
2727
cfg-if = "1.0"
2828
parking_lot_core = { version = "^0.9", default-features = false }
2929
lock_api = { version = "^0.4", default-features = false }
3030
fxhash = {version = "^0.2"}
3131

3232
[build-dependencies]
33-
pyo3-build-config = { version = "0.22.6", features = ["resolve-config"] }
33+
pyo3-build-config = { version = "0.23.1", features = ["resolve-config"] }
3434

3535
[lints.clippy]
3636
dbg_macro = "warn"

cachebox/utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def __delitem__(self, key: KT) -> VT:
6262

6363
raise TypeError("This cache is frozen.")
6464

65-
def __str__(self) -> str:
65+
def __repr__(self) -> str:
6666
return f"<Frozen: {self.__cache}>"
6767

6868
def __iter__(self) -> typing.Iterator[KT]:

src/bridge/cache.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::util::_KeepForIter;
1111
/// - it supports useful and new methods for managing memory, while `dict` does not.
1212
/// - it does not support `popitem`, while `dict` does.
1313
/// - You can limit the size of [`Cache`], but you cannot for `dict`.
14-
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl)]
14+
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl, frozen)]
1515
pub struct Cache {
1616
// Why [`Box`]? We using [`Box`] here so that there's no need for `&mut self`
1717
// in this struct; so RuntimeError never occurred for using this class in multiple threads.
@@ -127,8 +127,8 @@ impl Cache {
127127
}
128128
}
129129

130-
/// Returns str(self)
131-
pub fn __str__(&self) -> String {
130+
/// Returns repr(self)
131+
pub fn __repr__(&self) -> String {
132132
let lock = self.raw.lock();
133133

134134
format!(

src/bridge/fifocache.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{hashedkey::HashedKey, util::_KeepForIter};
55
/// FIFO Cache implementation - First-In First-Out Policy (thread-safe).
66
///
77
/// In simple terms, the FIFO cache will remove the element that has been in the cache the longest.
8-
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl)]
8+
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl, frozen)]
99
pub struct FIFOCache {
1010
// Why [`Box`]? We using [`Box`] here so that there's no need for `&mut self`
1111
// in this struct; so RuntimeError never occurred for using this class in multiple threads.
@@ -119,8 +119,8 @@ impl FIFOCache {
119119
}
120120
}
121121

122-
/// Returns str(self)
123-
pub fn __str__(&self) -> String {
122+
/// Returns repr(self)
123+
pub fn __repr__(&self) -> String {
124124
let lock = self.raw.lock();
125125

126126
format!(

src/bridge/lfucache.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{hashedkey::HashedKey, util::_KeepForIter};
55
/// LFU Cache implementation - Least frequantly used policy (thread-safe).
66
///
77
/// In simple terms, the LFU cache will remove the element in the cache that has been accessed the least, regardless of time
8-
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl)]
8+
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl, frozen)]
99
pub struct LFUCache {
1010
// Why [`Box`]? We using [`Box`] here so that there's no need for `&mut self`
1111
// in this struct; so RuntimeError never occurred for using this class in multiple threads.
@@ -126,8 +126,8 @@ impl LFUCache {
126126
}
127127
}
128128

129-
/// Returns str(self)
130-
pub fn __str__(&self) -> String {
129+
/// Returns repr(self)
130+
pub fn __repr__(&self) -> String {
131131
let lock = self.raw.lock();
132132

133133
format!(

src/bridge/lrucache.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{hashedkey::HashedKey, util::_KeepForIter};
55
/// LRU Cache implementation - Least recently used policy (thread-safe).
66
///
77
/// In simple terms, the LRU cache will remove the element in the cache that has not been accessed in the longest time.
8-
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl)]
8+
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl, frozen)]
99
pub struct LRUCache {
1010
// Why [`Box`]? We using [`Box`] here so that there's no need for `&mut self`
1111
// in this struct; so RuntimeError never occurred for using this class in multiple threads.
@@ -120,8 +120,8 @@ impl LRUCache {
120120
}
121121
}
122122

123-
/// Returns str(self)
124-
pub fn __str__(&self) -> String {
123+
/// Returns repr(self)
124+
pub fn __repr__(&self) -> String {
125125
let lock = self.raw.lock();
126126

127127
format!(

src/bridge/rrcache.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ macro_rules! insert_rr {
4242
/// RRCache implementation - Random Replacement policy (thread-safe).
4343
///
4444
/// In simple terms, the RR cache will choice randomly element to remove it to make space when necessary.
45-
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl)]
45+
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl, frozen)]
4646
pub struct RRCache {
4747
// Why [`Box`]? We using [`Box`] here so that there's no need for `&mut self`
4848
// in this struct; so RuntimeError never occurred for using this class in multiple threads.
@@ -156,8 +156,8 @@ impl RRCache {
156156
}
157157
}
158158

159-
/// Returns str(self)
160-
pub fn __str__(&self) -> String {
159+
/// Returns repr(self)
160+
pub fn __repr__(&self) -> String {
161161
let lock = self.raw.lock();
162162

163163
format!(
@@ -409,7 +409,7 @@ impl RRCache {
409409

410410
Ok(())
411411
} else {
412-
for pair in iterable.bind(py).iter()? {
412+
for pair in iterable.bind(py).try_iter()? {
413413
let (key, value) = pair?.extract::<(pyo3::PyObject, pyo3::PyObject)>()?;
414414

415415
let hk = HashedKey::from_pyobject(py, key)?;

src/bridge/ttlcache.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{hashedkey::HashedKey, internal::TTLElement, util::_KeepForIter};
55
/// TTL Cache implementation - Time-To-Live Policy (thread-safe).
66
///
77
/// In simple terms, the TTL cache will automatically remove the element in the cache that has expired::
8-
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl)]
8+
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl, frozen)]
99
pub struct TTLCache {
1010
// Why [`Box`]? We using [`Box`] here so that there's no need for `&mut self`
1111
// in this struct; so RuntimeError never occurred for using this class in multiple threads.
@@ -138,8 +138,8 @@ impl TTLCache {
138138
}
139139
}
140140

141-
/// Returns str(self)
142-
pub fn __str__(&self) -> String {
141+
/// Returns repr(self)
142+
pub fn __repr__(&self) -> String {
143143
let mut lock = self.raw.lock();
144144
lock.expire();
145145

src/bridge/vttlcache.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{hashedkey::HashedKey, internal::VTTLElement, util::_KeepForIter};
55
/// VTTL Cache Implementation - Time-To-Live Per-Key Policy (thread-safe).
66
///
77
/// In simple terms, the TTL cache will automatically remove the element in the cache that has expired when need.
8-
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl)]
8+
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl, frozen)]
99
pub struct VTTLCache {
1010
// Why [`Box`]? We using [`Box`] here so that there's no need for `&mut self`
1111
// in this struct; so RuntimeError never occurred for using this class in multiple threads.
@@ -125,8 +125,8 @@ impl VTTLCache {
125125
}
126126
}
127127

128-
/// Returns str(self)
129-
pub fn __str__(&self) -> String {
128+
/// Returns repr(self)
129+
pub fn __repr__(&self) -> String {
130130
let lock = self.raw.lock();
131131

132132
format!(

src/internal/fifo.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ impl FIFOPolicy {
203203

204204
Ok(())
205205
} else {
206-
for pair in iterable.bind(py).iter()? {
206+
for pair in iterable.bind(py).try_iter()? {
207207
let (key, value) = pair?.extract::<(pyo3::PyObject, pyo3::PyObject)>()?;
208208

209209
let hk = HashedKey::from_pyobject(py, key)?;

src/internal/lfu.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ impl LFUPolicy {
169169

170170
Ok(())
171171
} else {
172-
for pair in iterable.bind(py).iter()? {
172+
for pair in iterable.bind(py).try_iter()? {
173173
let (key, value) = pair?.extract::<(pyo3::PyObject, pyo3::PyObject)>()?;
174174

175175
let hk = HashedKey::from_pyobject(py, key)?;
@@ -267,7 +267,7 @@ impl LFUPolicy {
267267

268268
let mut new = Self::new(maxsize, capacity)?;
269269

270-
for pair in iterable.bind(py).iter()? {
270+
for pair in iterable.bind(py).try_iter()? {
271271
let (key, value, fr) = pair?.extract::<(pyo3::PyObject, pyo3::PyObject, usize)>()?;
272272

273273
let hk = HashedKey::from_pyobject(py, key)?;

src/internal/lru.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ impl LRUPolicy {
162162

163163
Ok(())
164164
} else {
165-
for pair in iterable.bind(py).iter()? {
165+
for pair in iterable.bind(py).try_iter()? {
166166
let (key, value) = pair?.extract::<(pyo3::PyObject, pyo3::PyObject)>()?;
167167

168168
let hk = HashedKey::from_pyobject(py, key)?;

src/internal/nopolicy.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ impl NoPolicy {
9797

9898
Ok(())
9999
} else {
100-
for pair in iterable.bind(py).iter()? {
100+
for pair in iterable.bind(py).try_iter()? {
101101
let (key, value) = pair?.extract::<(pyo3::PyObject, pyo3::PyObject)>()?;
102102

103103
let hk = HashedKey::from_pyobject(py, key)?;

src/internal/ttl.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ impl TTLPolicy {
233233

234234
Ok(())
235235
} else {
236-
for pair in iterable.bind(py).iter()? {
236+
for pair in iterable.bind(py).try_iter()? {
237237
let (key, value) = pair?.extract::<(pyo3::PyObject, pyo3::PyObject)>()?;
238238

239239
let hk = HashedKey::from_pyobject(py, key)?;
@@ -344,7 +344,7 @@ impl TTLPolicy {
344344

345345
let mut new = Self::new(maxsize, capacity, ttl)?;
346346

347-
for pair in iterable.bind(py).iter()? {
347+
for pair in iterable.bind(py).try_iter()? {
348348
let (key, value, timestamp) =
349349
pair?.extract::<(pyo3::PyObject, pyo3::PyObject, f64)>()?;
350350

src/internal/vttl.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ impl VTTLPolicy {
261261

262262
Ok(())
263263
} else {
264-
for pair in iterable.bind(py).iter()? {
264+
for pair in iterable.bind(py).try_iter()? {
265265
let (key, value) = pair?.extract::<(pyo3::PyObject, pyo3::PyObject)>()?;
266266

267267
let hk = HashedKey::from_pyobject(py, key)?;
@@ -362,7 +362,7 @@ impl VTTLPolicy {
362362

363363
let mut new = Self::new(maxsize, capacity)?;
364364

365-
for pair in iterable.bind(py).iter()? {
365+
for pair in iterable.bind(py).try_iter()? {
366366
let (key, value, timestamp) =
367367
pair?.extract::<(pyo3::PyObject, pyo3::PyObject, f64)>()?;
368368

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ pub fn version_info() -> (u8, u8, u8, bool) {
4141
#[pymodule]
4242
#[pyo3(name = "_cachebox")]
4343
fn _cachebox(m: &Bound<'_, PyModule>) -> PyResult<()> {
44+
m.gil_used(false)?;
45+
4446
m.add("__version__", CACHEBOX_VERSION)?;
4547
m.add("version_info", version_info())?;
4648
m.add("__author__", "awolverp")?;

src/util.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#[allow(unused_imports)]
2-
use pyo3::IntoPy;
2+
use pyo3::IntoPyObject;
33

44
macro_rules! err {
55
($type:ty, $val:expr) => {
@@ -140,7 +140,7 @@ unsafe fn _get_capacity(
140140
) -> pyo3::PyResult<*mut pyo3::ffi::PyObject> {
141141
cfg_if::cfg_if! {
142142
if #[cfg(all(Py_3_9, not(any(Py_LIMITED_API, PyPy, GraalPy))))] {
143-
let m_name: pyo3::Py<pyo3::types::PyString> = "capacity".into_py(py);
143+
let m_name: pyo3::Bound<'_, pyo3::types::PyString> = "capacity".into_pyobject(py)?;
144144
Ok(pyo3::ffi::PyObject_CallMethodNoArgs(ptr, m_name.as_ptr()))
145145
} else {
146146
let capacity_fn =

tests/mixin.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,10 @@ def test___setitem__(self):
151151
with pytest.raises(KeyError):
152152
cache[2]
153153

154-
def test___str__(self):
154+
def test___repr__(self):
155155
cache = self.CACHE(2, **self.KWARGS, capacity=2)
156-
assert str(cache) != repr(cache)
156+
assert str(cache) == repr(cache)
157+
assert repr(cache).startswith(self.CACHE.__name__)
157158

158159
def test_insert(self):
159160
cache = self.CACHE(5, **self.KWARGS, capacity=5)

0 commit comments

Comments
 (0)