Skip to content

Commit

Permalink
Support free-threading, __str__ changed to __repr__, and dependen…
Browse files Browse the repository at this point in the history
…cies updated
  • Loading branch information
awolverp committed Nov 18, 2024
1 parent e624506 commit 193fd31
Show file tree
Hide file tree
Showing 20 changed files with 59 additions and 50 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 4.3.1 - 2024-11-18
### Changed
- `__str__` changed to `__repr__`
- Free-threading is supported now
- Dependencies updated

## 4.3.0 - 2024-11-08
### Added
- Add `always_copy` parameter to `cached` and `cachedmethod` decorators
Expand Down
22 changes: 11 additions & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cachebox"
version = "4.3.0"
version = "4.3.1"
edition = "2021"
description = "The fastest memoizing and caching Python library written in Rust"
readme = "README.md"
Expand All @@ -23,14 +23,14 @@ strip = "symbols"
[dependencies]
hashbrown = { version = "^0.14", default-features = false, features=["inline-more", "raw"]}
fastrand = "^2.1"
pyo3 = { version = "0.22.6", default-features = false, features=["macros", "extension-module"] }
pyo3 = { version = "0.23.1", default-features = false, features=["macros", "extension-module"] }
cfg-if = "1.0"
parking_lot_core = { version = "^0.9", default-features = false }
lock_api = { version = "^0.4", default-features = false }
fxhash = {version = "^0.2"}

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

[lints.clippy]
dbg_macro = "warn"
Expand Down
2 changes: 1 addition & 1 deletion cachebox/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def __delitem__(self, key: KT) -> VT:

raise TypeError("This cache is frozen.")

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

def __iter__(self) -> typing.Iterator[KT]:
Expand Down
6 changes: 3 additions & 3 deletions src/bridge/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::util::_KeepForIter;
/// - it supports useful and new methods for managing memory, while `dict` does not.
/// - it does not support `popitem`, while `dict` does.
/// - You can limit the size of [`Cache`], but you cannot for `dict`.
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl)]
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl, frozen)]
pub struct Cache {
// Why [`Box`]? We using [`Box`] here so that there's no need for `&mut self`
// in this struct; so RuntimeError never occurred for using this class in multiple threads.
Expand Down Expand Up @@ -127,8 +127,8 @@ impl Cache {
}
}

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

format!(
Expand Down
6 changes: 3 additions & 3 deletions src/bridge/fifocache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{hashedkey::HashedKey, util::_KeepForIter};
/// FIFO Cache implementation - First-In First-Out Policy (thread-safe).
///
/// In simple terms, the FIFO cache will remove the element that has been in the cache the longest.
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl)]
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl, frozen)]
pub struct FIFOCache {
// Why [`Box`]? We using [`Box`] here so that there's no need for `&mut self`
// in this struct; so RuntimeError never occurred for using this class in multiple threads.
Expand Down Expand Up @@ -119,8 +119,8 @@ impl FIFOCache {
}
}

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

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

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

format!(
Expand Down
6 changes: 3 additions & 3 deletions src/bridge/lrucache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{hashedkey::HashedKey, util::_KeepForIter};
/// LRU Cache implementation - Least recently used policy (thread-safe).
///
/// In simple terms, the LRU cache will remove the element in the cache that has not been accessed in the longest time.
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl)]
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl, frozen)]
pub struct LRUCache {
// Why [`Box`]? We using [`Box`] here so that there's no need for `&mut self`
// in this struct; so RuntimeError never occurred for using this class in multiple threads.
Expand Down Expand Up @@ -120,8 +120,8 @@ impl LRUCache {
}
}

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

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

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

format!(
Expand Down Expand Up @@ -409,7 +409,7 @@ impl RRCache {

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

let hk = HashedKey::from_pyobject(py, key)?;
Expand Down
6 changes: 3 additions & 3 deletions src/bridge/ttlcache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{hashedkey::HashedKey, internal::TTLElement, util::_KeepForIter};
/// TTL Cache implementation - Time-To-Live Policy (thread-safe).
///
/// In simple terms, the TTL cache will automatically remove the element in the cache that has expired::
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl)]
#[pyo3::pyclass(module="cachebox._cachebox", extends=crate::bridge::baseimpl::BaseCacheImpl, frozen)]
pub struct TTLCache {
// Why [`Box`]? We using [`Box`] here so that there's no need for `&mut self`
// in this struct; so RuntimeError never occurred for using this class in multiple threads.
Expand Down Expand Up @@ -138,8 +138,8 @@ impl TTLCache {
}
}

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

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

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

format!(
Expand Down
2 changes: 1 addition & 1 deletion src/internal/fifo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ impl FIFOPolicy {

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

let hk = HashedKey::from_pyobject(py, key)?;
Expand Down
4 changes: 2 additions & 2 deletions src/internal/lfu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ impl LFUPolicy {

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

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

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

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

let hk = HashedKey::from_pyobject(py, key)?;
Expand Down
2 changes: 1 addition & 1 deletion src/internal/lru.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ impl LRUPolicy {

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

let hk = HashedKey::from_pyobject(py, key)?;
Expand Down
2 changes: 1 addition & 1 deletion src/internal/nopolicy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ impl NoPolicy {

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

let hk = HashedKey::from_pyobject(py, key)?;
Expand Down
4 changes: 2 additions & 2 deletions src/internal/ttl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ impl TTLPolicy {

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

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

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

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

Expand Down
4 changes: 2 additions & 2 deletions src/internal/vttl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ impl VTTLPolicy {

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

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

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

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

Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ pub fn version_info() -> (u8, u8, u8, bool) {
#[pymodule]
#[pyo3(name = "_cachebox")]
fn _cachebox(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.gil_used(false)?;

m.add("__version__", CACHEBOX_VERSION)?;
m.add("version_info", version_info())?;
m.add("__author__", "awolverp")?;
Expand Down
4 changes: 2 additions & 2 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#[allow(unused_imports)]
use pyo3::IntoPy;
use pyo3::IntoPyObject;

macro_rules! err {
($type:ty, $val:expr) => {
Expand Down Expand Up @@ -140,7 +140,7 @@ unsafe fn _get_capacity(
) -> pyo3::PyResult<*mut pyo3::ffi::PyObject> {
cfg_if::cfg_if! {
if #[cfg(all(Py_3_9, not(any(Py_LIMITED_API, PyPy, GraalPy))))] {
let m_name: pyo3::Py<pyo3::types::PyString> = "capacity".into_py(py);
let m_name: pyo3::Bound<'_, pyo3::types::PyString> = "capacity".into_pyobject(py)?;
Ok(pyo3::ffi::PyObject_CallMethodNoArgs(ptr, m_name.as_ptr()))
} else {
let capacity_fn =
Expand Down
5 changes: 3 additions & 2 deletions tests/mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,10 @@ def test___setitem__(self):
with pytest.raises(KeyError):
cache[2]

def test___str__(self):
def test___repr__(self):
cache = self.CACHE(2, **self.KWARGS, capacity=2)
assert str(cache) != repr(cache)
assert str(cache) == repr(cache)
assert repr(cache).startswith(self.CACHE.__name__)

def test_insert(self):
cache = self.CACHE(5, **self.KWARGS, capacity=5)
Expand Down

0 comments on commit 193fd31

Please sign in to comment.