Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -968,8 +968,8 @@ fn increment_then_print_field(my_class: &Bound<'_, MyClass>) {
// When the Python object smart pointer needs to be stored elsewhere prefer `Py<T>` over `Bound<'py, T>`
// to avoid the lifetime restrictions.
#[pyfunction]
fn print_refcnt(my_class: Py<MyClass>, py: Python<'_>) {
println!("{}", my_class.get_refcnt(py));
fn print_is_none(my_class: Py<MyClass>, py: Python<'_>) {
println!("{}", my_class.is_none(py));
}
```

Expand Down
2 changes: 1 addition & 1 deletion guide/src/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2493,7 +2493,7 @@ py.None().get_refcnt();

After:

```rust
```rust,ignore
# pyo3::Python::attach(|py| {
py.None().get_refcnt(py);
# })
Expand Down
2 changes: 2 additions & 0 deletions newsfragments/5797.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Deprecate `Py<T>::get_refcnt` and `PyAnyMethods::get_refcnt` in favor of `pyo3::ffi::Py_REFCNT(obj.as_ptr())`

16 changes: 9 additions & 7 deletions src/ffi/tests.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::ffi::*;
use crate::types::any::PyAnyMethods;
use crate::Python;

#[cfg(not(Py_LIMITED_API))]
use crate::types::any::PyAnyMethods;

#[cfg(all(not(Py_LIMITED_API), any(not(any(PyPy, GraalPy)), feature = "macros")))]
use crate::types::PyString;

Expand Down Expand Up @@ -304,16 +306,16 @@ fn test_inc_dec_ref() {
Python::attach(|py| {
let obj = py.eval(c"object()", None, None).unwrap();

let ref_count = obj.get_refcnt();
let ref_count = obj._get_refcnt();
let ptr = obj.as_ptr();

unsafe { Py_INCREF(ptr) };

assert_eq!(obj.get_refcnt(), ref_count + 1);
assert_eq!(obj._get_refcnt(), ref_count + 1);

unsafe { Py_DECREF(ptr) };

assert_eq!(obj.get_refcnt(), ref_count);
assert_eq!(obj._get_refcnt(), ref_count);
})
}

Expand All @@ -323,15 +325,15 @@ fn test_inc_dec_ref_immortal() {
Python::attach(|py| {
let obj = py.None();

let ref_count = obj.get_refcnt(py);
let ref_count = obj._get_refcnt(py);
let ptr = obj.as_ptr();

unsafe { Py_INCREF(ptr) };

assert_eq!(obj.get_refcnt(py), ref_count);
assert_eq!(obj._get_refcnt(py), ref_count);

unsafe { Py_DECREF(ptr) };

assert_eq!(obj.get_refcnt(py), ref_count);
assert_eq!(obj._get_refcnt(py), ref_count);
})
}
21 changes: 15 additions & 6 deletions src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1728,7 +1728,16 @@ impl<T> Py<T> {

/// Gets the reference count of the `ffi::PyObject` pointer.
#[inline]
pub fn get_refcnt(&self, _py: Python<'_>) -> isize {
#[deprecated(
since = "0.29.0",
note = "use `pyo3::ffi::Py_REFCNT(obj.as_ptr())` instead"
)]
pub fn get_refcnt(&self, py: Python<'_>) -> isize {
self._get_refcnt(py)
}

#[inline]
pub(crate) fn _get_refcnt(&self, _py: Python<'_>) -> isize {
// SAFETY: Self is a valid pointer to a PyObject
unsafe { ffi::Py_REFCNT(self.0.as_ptr()) }
}
Expand Down Expand Up @@ -2542,17 +2551,17 @@ mod tests {
});

Python::attach(move |py| {
assert_eq!(dict.get_refcnt(py), 1);
assert_eq!(dict._get_refcnt(py), 1);
});
}

#[test]
fn pyobject_from_py() {
Python::attach(|py| {
let dict: Py<PyDict> = PyDict::new(py).unbind();
let cnt = dict.get_refcnt(py);
let cnt = dict._get_refcnt(py);
let p: Py<PyAny> = dict.into();
assert_eq!(p.get_refcnt(py), cnt);
assert_eq!(p._get_refcnt(py), cnt);
});
}

Expand Down Expand Up @@ -2786,11 +2795,11 @@ a = A()
let object2 = object.clone_ref(py);

assert_eq!(object.as_ptr(), object2.as_ptr());
assert_eq!(object.get_refcnt(py), 2);
assert_eq!(object._get_refcnt(py), 2);

object.drop_ref(py);

assert_eq!(object2.get_refcnt(py), 1);
assert_eq!(object2._get_refcnt(py), 1);

object2.drop_ref(py);
});
Expand Down
20 changes: 10 additions & 10 deletions src/internal/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ fn decrement_attach_count() {
mod tests {
use super::*;

use crate::{types::PyAnyMethods, Py, PyAny, Python};
use crate::{Py, PyAny, Python};

fn get_object(py: Python<'_>) -> Py<PyAny> {
py.eval(c"object()", None, None).unwrap().unbind()
Expand Down Expand Up @@ -396,14 +396,14 @@ mod tests {
// Create a reference to drop while attached.
let reference = obj.clone_ref(py);

assert_eq!(obj.get_refcnt(py), 2);
assert_eq!(obj._get_refcnt(py), 2);
#[cfg(not(pyo3_disable_reference_pool))]
assert!(pool_dec_refs_does_not_contain(&obj));

// While attached, reference count will be decreased immediately.
drop(reference);

assert_eq!(obj.get_refcnt(py), 1);
assert_eq!(obj._get_refcnt(py), 1);
#[cfg(not(any(pyo3_disable_reference_pool)))]
assert!(pool_dec_refs_does_not_contain(&obj));
});
Expand All @@ -417,15 +417,15 @@ mod tests {
// Create a reference to drop while detached.
let reference = obj.clone_ref(py);

assert_eq!(obj.get_refcnt(py), 2);
assert_eq!(obj._get_refcnt(py), 2);
assert!(pool_dec_refs_does_not_contain(&obj));

// Drop reference in a separate (detached) thread.
std::thread::spawn(move || drop(reference)).join().unwrap();

// The reference count should not have changed, it is remembered
// to release later.
assert_eq!(obj.get_refcnt(py), 2);
assert_eq!(obj._get_refcnt(py), 2);
#[cfg(not(Py_GIL_DISABLED))]
assert!(pool_dec_refs_contains(&obj));
obj
Expand All @@ -438,7 +438,7 @@ mod tests {
// DECREFs after releasing the lock on the POOL, so the
// refcnt could still be 2 when this assert happens
#[cfg(not(Py_GIL_DISABLED))]
assert_eq!(obj.get_refcnt(py), 1);
assert_eq!(obj._get_refcnt(py), 1);
assert!(pool_dec_refs_does_not_contain(&obj));
});
}
Expand Down Expand Up @@ -501,7 +501,7 @@ mod tests {
Python::attach(|py| {
// Make a simple object with 1 reference
let obj = get_object(py);
assert_eq!(obj.get_refcnt(py), 1);
assert_eq!(obj._get_refcnt(py), 1);
// Cloning the object when detached should panic
py.detach(|| obj.clone());
});
Expand All @@ -511,7 +511,7 @@ mod tests {
fn recursive_attach_ok() {
Python::attach(|py| {
let obj = Python::attach(|_| py.eval(c"object()", None, None).unwrap());
assert_eq!(obj.get_refcnt(), 1);
assert_eq!(obj._get_refcnt(), 1);
})
}

Expand All @@ -520,12 +520,12 @@ mod tests {
fn test_clone_attached() {
Python::attach(|py| {
let obj = get_object(py);
let count = obj.get_refcnt(py);
let count = obj._get_refcnt(py);

// Cloning when attached should increase reference count immediately
#[expect(clippy::redundant_clone)]
let c = obj.clone();
assert_eq!(count + 1, c.get_refcnt(py));
assert_eq!(count + 1, c._get_refcnt(py));
})
}

Expand Down
11 changes: 10 additions & 1 deletion src/types/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,10 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
T: FromPyObject<'a, 'py>;

/// Returns the reference count for the Python object.
#[deprecated(
since = "0.29.0",
note = "use `pyo3::ffi::Py_REFCNT(obj.as_ptr())` instead"
)]
fn get_refcnt(&self) -> isize;

/// Computes the "repr" representation of self.
Expand Down Expand Up @@ -1531,7 +1535,7 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
}

fn get_refcnt(&self) -> isize {
unsafe { ffi::Py_REFCNT(self.as_ptr()) }
self._get_refcnt()
}

fn repr(&self) -> PyResult<Bound<'py, PyString>> {
Expand Down Expand Up @@ -1652,6 +1656,11 @@ impl<'py> Bound<'py, PyAny> {
Ok(Some(attr))
}
}

#[inline]
pub(crate) fn _get_refcnt(&self) -> isize {
unsafe { ffi::Py_REFCNT(self.as_ptr()) }
}
}

#[cfg(test)]
Expand Down
4 changes: 2 additions & 2 deletions src/types/dict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1022,11 +1022,11 @@ mod tests {
let cnt;
let obj = py.eval(c"object()", None, None).unwrap();
{
cnt = obj.get_refcnt();
cnt = obj._get_refcnt();
let _dict = [(10, &obj)].into_py_dict(py);
}
{
assert_eq!(cnt, obj.get_refcnt());
assert_eq!(cnt, obj._get_refcnt());
}
});
}
Expand Down
8 changes: 4 additions & 4 deletions src/types/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ mod tests {
fn iter_refcnt() {
let (obj, count) = Python::attach(|py| {
let obj = vec![10, 20].into_pyobject(py).unwrap();
let count = obj.get_refcnt();
let count = obj._get_refcnt();
(obj.unbind(), count)
});

Expand All @@ -206,7 +206,7 @@ mod tests {
});

Python::attach(move |py| {
assert_eq!(count, obj.get_refcnt(py));
assert_eq!(count, obj._get_refcnt(py));
});
}

Expand All @@ -219,7 +219,7 @@ mod tests {
let list = PyList::empty(py);
list.append(10).unwrap();
list.append(&obj).unwrap();
count = obj.get_refcnt();
count = obj._get_refcnt();
list
};

Expand All @@ -230,7 +230,7 @@ mod tests {
assert!(it.next().unwrap().is(&obj));
assert!(it.next().is_none());
}
assert_eq!(count, obj.get_refcnt());
assert_eq!(count, obj._get_refcnt());
});
}

Expand Down
12 changes: 6 additions & 6 deletions src/types/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1029,11 +1029,11 @@ mod tests {
let v = vec![2];
let ob = v.into_pyobject(py).unwrap();
let list = ob.cast::<PyList>().unwrap();
cnt = obj.get_refcnt();
cnt = obj._get_refcnt();
list.set_item(0, &obj).unwrap();
}

assert_eq!(cnt, obj.get_refcnt());
assert_eq!(cnt, obj._get_refcnt());
});
}

Expand Down Expand Up @@ -1061,11 +1061,11 @@ mod tests {
let obj = py.eval(c"object()", None, None).unwrap();
{
let list = PyList::empty(py);
cnt = obj.get_refcnt();
cnt = obj._get_refcnt();
list.insert(0, &obj).unwrap();
}

assert_eq!(cnt, obj.get_refcnt());
assert_eq!(cnt, obj._get_refcnt());
});
}

Expand All @@ -1086,10 +1086,10 @@ mod tests {
let obj = py.eval(c"object()", None, None).unwrap();
{
let list = PyList::empty(py);
cnt = obj.get_refcnt();
cnt = obj._get_refcnt();
list.append(&obj).unwrap();
}
assert_eq!(cnt, obj.get_refcnt());
assert_eq!(cnt, obj._get_refcnt());
});
}

Expand Down
4 changes: 2 additions & 2 deletions src/types/mappingproxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,12 @@ mod tests {
let cnt;
{
let none = py.None();
cnt = none.get_refcnt(py);
cnt = none._get_refcnt(py);
let dict = [(10, none)].into_py_dict(py).unwrap();
let _mappingproxy = PyMappingProxy::new(py, dict.as_mapping());
}
{
assert_eq!(cnt, py.None().get_refcnt(py));
assert_eq!(cnt, py.None()._get_refcnt(py));
}
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/types/sequence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ mod tests {
});

Python::attach(move |py| {
assert_eq!(1, obj.get_refcnt(py));
assert_eq!(1, obj._get_refcnt(py));
});
}

Expand Down
2 changes: 0 additions & 2 deletions tests/test_gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,7 @@ impl CycleWithClear {
}

fn __clear__(slf: &Bound<'_, Self>) {
println!("clear run, refcount before {}", slf.get_refcnt());
slf.borrow_mut().cycle = None;
println!("clear run, refcount after {}", slf.get_refcnt());
}
}

Expand Down
Loading
Loading