Skip to content

Commit 86c48d3

Browse files
authored
deprecate get_refcnt (#3357) (#5797)
* deprecate get_refcnt (#3357) * add private _get_refcnt * add changelog entry * remove allow(deprecated) tags
1 parent 09cf30c commit 86c48d3

14 files changed

Lines changed: 83 additions & 54 deletions

File tree

guide/src/class.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -969,8 +969,8 @@ fn increment_then_print_field(my_class: &Bound<'_, MyClass>) {
969969
// When the Python object smart pointer needs to be stored elsewhere prefer `Py<T>` over `Bound<'py, T>`
970970
// to avoid the lifetime restrictions.
971971
#[pyfunction]
972-
fn print_refcnt(my_class: Py<MyClass>, py: Python<'_>) {
973-
println!("{}", my_class.get_refcnt(py));
972+
fn print_is_none(my_class: Py<MyClass>, py: Python<'_>) {
973+
println!("{}", my_class.is_none(py));
974974
}
975975
```
976976

guide/src/migration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2525,7 +2525,7 @@ py.None().get_refcnt();
25252525

25262526
After:
25272527

2528-
```rust
2528+
```rust,ignore
25292529
# pyo3::Python::attach(|py| {
25302530
py.None().get_refcnt(py);
25312531
# })

newsfragments/5797.changed.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Deprecate `Py<T>::get_refcnt` and `PyAnyMethods::get_refcnt` in favor of `pyo3::ffi::Py_REFCNT(obj.as_ptr())`
2+

src/ffi/tests.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::ffi::*;
2-
use crate::types::any::PyAnyMethods;
32
use crate::Python;
43

4+
#[cfg(not(Py_LIMITED_API))]
5+
use crate::types::any::PyAnyMethods;
6+
57
#[cfg(all(not(Py_LIMITED_API), any(not(any(PyPy, GraalPy)), feature = "macros")))]
68
use crate::types::PyString;
79

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

307-
let ref_count = obj.get_refcnt();
309+
let ref_count = obj._get_refcnt();
308310
let ptr = obj.as_ptr();
309311

310312
unsafe { Py_INCREF(ptr) };
311313

312-
assert_eq!(obj.get_refcnt(), ref_count + 1);
314+
assert_eq!(obj._get_refcnt(), ref_count + 1);
313315

314316
unsafe { Py_DECREF(ptr) };
315317

316-
assert_eq!(obj.get_refcnt(), ref_count);
318+
assert_eq!(obj._get_refcnt(), ref_count);
317319
})
318320
}
319321

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

326-
let ref_count = obj.get_refcnt(py);
328+
let ref_count = obj._get_refcnt(py);
327329
let ptr = obj.as_ptr();
328330

329331
unsafe { Py_INCREF(ptr) };
330332

331-
assert_eq!(obj.get_refcnt(py), ref_count);
333+
assert_eq!(obj._get_refcnt(py), ref_count);
332334

333335
unsafe { Py_DECREF(ptr) };
334336

335-
assert_eq!(obj.get_refcnt(py), ref_count);
337+
assert_eq!(obj._get_refcnt(py), ref_count);
336338
})
337339
}

src/instance.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1728,7 +1728,16 @@ impl<T> Py<T> {
17281728

17291729
/// Gets the reference count of the `ffi::PyObject` pointer.
17301730
#[inline]
1731-
pub fn get_refcnt(&self, _py: Python<'_>) -> isize {
1731+
#[deprecated(
1732+
since = "0.29.0",
1733+
note = "use `pyo3::ffi::Py_REFCNT(obj.as_ptr())` instead"
1734+
)]
1735+
pub fn get_refcnt(&self, py: Python<'_>) -> isize {
1736+
self._get_refcnt(py)
1737+
}
1738+
1739+
#[inline]
1740+
pub(crate) fn _get_refcnt(&self, _py: Python<'_>) -> isize {
17321741
// SAFETY: Self is a valid pointer to a PyObject
17331742
unsafe { ffi::Py_REFCNT(self.0.as_ptr()) }
17341743
}
@@ -2542,17 +2551,17 @@ mod tests {
25422551
});
25432552

25442553
Python::attach(move |py| {
2545-
assert_eq!(dict.get_refcnt(py), 1);
2554+
assert_eq!(dict._get_refcnt(py), 1);
25462555
});
25472556
}
25482557

25492558
#[test]
25502559
fn pyobject_from_py() {
25512560
Python::attach(|py| {
25522561
let dict: Py<PyDict> = PyDict::new(py).unbind();
2553-
let cnt = dict.get_refcnt(py);
2562+
let cnt = dict._get_refcnt(py);
25542563
let p: Py<PyAny> = dict.into();
2555-
assert_eq!(p.get_refcnt(py), cnt);
2564+
assert_eq!(p._get_refcnt(py), cnt);
25562565
});
25572566
}
25582567

@@ -2786,11 +2795,11 @@ a = A()
27862795
let object2 = object.clone_ref(py);
27872796

27882797
assert_eq!(object.as_ptr(), object2.as_ptr());
2789-
assert_eq!(object.get_refcnt(py), 2);
2798+
assert_eq!(object._get_refcnt(py), 2);
27902799

27912800
object.drop_ref(py);
27922801

2793-
assert_eq!(object2.get_refcnt(py), 1);
2802+
assert_eq!(object2._get_refcnt(py), 1);
27942803

27952804
object2.drop_ref(py);
27962805
});

src/internal/state.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ fn decrement_attach_count() {
362362
mod tests {
363363
use super::*;
364364

365-
use crate::{types::PyAnyMethods, Py, PyAny, Python};
365+
use crate::{Py, PyAny, Python};
366366

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

399-
assert_eq!(obj.get_refcnt(py), 2);
399+
assert_eq!(obj._get_refcnt(py), 2);
400400
#[cfg(not(pyo3_disable_reference_pool))]
401401
assert!(pool_dec_refs_does_not_contain(&obj));
402402

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

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

420-
assert_eq!(obj.get_refcnt(py), 2);
420+
assert_eq!(obj._get_refcnt(py), 2);
421421
assert!(pool_dec_refs_does_not_contain(&obj));
422422

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

426426
// The reference count should not have changed, it is remembered
427427
// to release later.
428-
assert_eq!(obj.get_refcnt(py), 2);
428+
assert_eq!(obj._get_refcnt(py), 2);
429429
#[cfg(not(Py_GIL_DISABLED))]
430430
assert!(pool_dec_refs_contains(&obj));
431431
obj
@@ -438,7 +438,7 @@ mod tests {
438438
// DECREFs after releasing the lock on the POOL, so the
439439
// refcnt could still be 2 when this assert happens
440440
#[cfg(not(Py_GIL_DISABLED))]
441-
assert_eq!(obj.get_refcnt(py), 1);
441+
assert_eq!(obj._get_refcnt(py), 1);
442442
assert!(pool_dec_refs_does_not_contain(&obj));
443443
});
444444
}
@@ -501,7 +501,7 @@ mod tests {
501501
Python::attach(|py| {
502502
// Make a simple object with 1 reference
503503
let obj = get_object(py);
504-
assert_eq!(obj.get_refcnt(py), 1);
504+
assert_eq!(obj._get_refcnt(py), 1);
505505
// Cloning the object when detached should panic
506506
py.detach(|| obj.clone());
507507
});
@@ -511,7 +511,7 @@ mod tests {
511511
fn recursive_attach_ok() {
512512
Python::attach(|py| {
513513
let obj = Python::attach(|_| py.eval(c"object()", None, None).unwrap());
514-
assert_eq!(obj.get_refcnt(), 1);
514+
assert_eq!(obj._get_refcnt(), 1);
515515
})
516516
}
517517

@@ -520,12 +520,12 @@ mod tests {
520520
fn test_clone_attached() {
521521
Python::attach(|py| {
522522
let obj = get_object(py);
523-
let count = obj.get_refcnt(py);
523+
let count = obj._get_refcnt(py);
524524

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

src/types/any.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,10 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
881881
T: FromPyObject<'a, 'py>;
882882

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

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

15331537
fn get_refcnt(&self) -> isize {
1534-
unsafe { ffi::Py_REFCNT(self.as_ptr()) }
1538+
self._get_refcnt()
15351539
}
15361540

15371541
fn repr(&self) -> PyResult<Bound<'py, PyString>> {
@@ -1652,6 +1656,11 @@ impl<'py> Bound<'py, PyAny> {
16521656
Ok(Some(attr))
16531657
}
16541658
}
1659+
1660+
#[inline]
1661+
pub(crate) fn _get_refcnt(&self) -> isize {
1662+
unsafe { ffi::Py_REFCNT(self.as_ptr()) }
1663+
}
16551664
}
16561665

16571666
#[cfg(test)]

src/types/dict.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,11 +1022,11 @@ mod tests {
10221022
let cnt;
10231023
let obj = py.eval(c"object()", None, None).unwrap();
10241024
{
1025-
cnt = obj.get_refcnt();
1025+
cnt = obj._get_refcnt();
10261026
let _dict = [(10, &obj)].into_py_dict(py);
10271027
}
10281028
{
1029-
assert_eq!(cnt, obj.get_refcnt());
1029+
assert_eq!(cnt, obj._get_refcnt());
10301030
}
10311031
});
10321032
}

src/types/iterator.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ mod tests {
191191
fn iter_refcnt() {
192192
let (obj, count) = Python::attach(|py| {
193193
let obj = vec![10, 20].into_pyobject(py).unwrap();
194-
let count = obj.get_refcnt();
194+
let count = obj._get_refcnt();
195195
(obj.unbind(), count)
196196
});
197197

@@ -206,7 +206,7 @@ mod tests {
206206
});
207207

208208
Python::attach(move |py| {
209-
assert_eq!(count, obj.get_refcnt(py));
209+
assert_eq!(count, obj._get_refcnt(py));
210210
});
211211
}
212212

@@ -219,7 +219,7 @@ mod tests {
219219
let list = PyList::empty(py);
220220
list.append(10).unwrap();
221221
list.append(&obj).unwrap();
222-
count = obj.get_refcnt();
222+
count = obj._get_refcnt();
223223
list
224224
};
225225

@@ -230,7 +230,7 @@ mod tests {
230230
assert!(it.next().unwrap().is(&obj));
231231
assert!(it.next().is_none());
232232
}
233-
assert_eq!(count, obj.get_refcnt());
233+
assert_eq!(count, obj._get_refcnt());
234234
});
235235
}
236236

src/types/list.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,11 +1011,11 @@ mod tests {
10111011
let v = vec![2];
10121012
let ob = v.into_pyobject(py).unwrap();
10131013
let list = ob.cast::<PyList>().unwrap();
1014-
cnt = obj.get_refcnt();
1014+
cnt = obj._get_refcnt();
10151015
list.set_item(0, &obj).unwrap();
10161016
}
10171017

1018-
assert_eq!(cnt, obj.get_refcnt());
1018+
assert_eq!(cnt, obj._get_refcnt());
10191019
});
10201020
}
10211021

@@ -1043,11 +1043,11 @@ mod tests {
10431043
let obj = py.eval(c"object()", None, None).unwrap();
10441044
{
10451045
let list = PyList::empty(py);
1046-
cnt = obj.get_refcnt();
1046+
cnt = obj._get_refcnt();
10471047
list.insert(0, &obj).unwrap();
10481048
}
10491049

1050-
assert_eq!(cnt, obj.get_refcnt());
1050+
assert_eq!(cnt, obj._get_refcnt());
10511051
});
10521052
}
10531053

@@ -1068,10 +1068,10 @@ mod tests {
10681068
let obj = py.eval(c"object()", None, None).unwrap();
10691069
{
10701070
let list = PyList::empty(py);
1071-
cnt = obj.get_refcnt();
1071+
cnt = obj._get_refcnt();
10721072
list.append(&obj).unwrap();
10731073
}
1074-
assert_eq!(cnt, obj.get_refcnt());
1074+
assert_eq!(cnt, obj._get_refcnt());
10751075
});
10761076
}
10771077

0 commit comments

Comments
 (0)