Skip to content

Commit 6ccd7e4

Browse files
Icxolumejrs
andauthored
remove AsPyPointer trait (PyO3#5071)
* remove `AsPyPointer` trait * fix typo Co-authored-by: Bruno Kolenbrander <[email protected]> --------- Co-authored-by: Bruno Kolenbrander <[email protected]>
1 parent 41ba6f9 commit 6ccd7e4

File tree

21 files changed

+84
-145
lines changed

21 files changed

+84
-145
lines changed

guide/src/class/protocols.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -443,9 +443,7 @@ struct ClassWithGCSupport {
443443
#[pymethods]
444444
impl ClassWithGCSupport {
445445
fn __traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError> {
446-
if let Some(obj) = &self.obj {
447-
visit.call(obj)?
448-
}
446+
visit.call(&self.obj)?;
449447
Ok(())
450448
}
451449

guide/src/migration.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@
33
This guide can help you upgrade code through breaking changes from one PyO3 version to the next.
44
For a detailed list of all changes, see the [CHANGELOG](changelog.md).
55

6+
## from 0.24.* to 0.25
7+
### `AsPyPointer` removal
8+
<details open>
9+
<summary><small>Click to expand</small></summary>
10+
The `AsPyPointer` trait is mostly a leftover from the now removed gil-refs API. The last remaining uses were the GC API, namely `PyVisit::call`, and identity comparison (`PyAnyMethods::is` and `Py::is`).
11+
12+
`PyVisit::call` has been updated to take `T: Into<Option<&Py<T>>>`, which allows for arguments of type `&Py<T>`, `&Option<Py<T>>` and `Option<&Py<T>>`. It is unlikely any changes are needed here to migrate.
13+
14+
`PyAnyMethods::is`/`Py::is` has been updated to take `T: AsRef<Py<PyAny>>>`. Additionally `AsRef<Py<PyAny>>>` implementations were added for `Py`, `Bound` and `Borrowed`. Because of the existing `AsRef<Bound<PyAny>> for Bound<T>` implementation this may cause inference issues in non-generic code. This can be easily migrated by switching to `as_any` instead of `as_ref` for these calls.
15+
</details>
16+
617
## from 0.22.* to 0.23
718
<details open>
819
<summary><small>Click to expand</small></summary>

newsfragments/5071.added.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- `AsRef<Py<PyAny>> for Py<T>`
2+
- `AsRef<Py<PyAny>> for Bound<T>`
3+
- `AsRef<Py<PyAny>> for Borrowed<T>`

newsfragments/5071.changed.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- `PyAnyMethods::is` now takes `other: &Bound<T>`
2+
- `Py::is` now takes `other: &Py<T>`
3+
- `PyVisit::call` now takes `T: Into<Option<&Py<T>>>`

newsfragments/5071.removed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
removed `AsPyPointer` trait

src/conversion.rs

Lines changed: 1 addition & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -5,67 +5,9 @@ use crate::inspect::types::TypeInfo;
55
use crate::pyclass::boolean_struct::False;
66
use crate::types::any::PyAnyMethods;
77
use crate::types::PyTuple;
8-
use crate::{
9-
ffi, Borrowed, Bound, BoundObject, Py, PyAny, PyClass, PyErr, PyRef, PyRefMut, Python,
10-
};
8+
use crate::{Borrowed, Bound, BoundObject, Py, PyAny, PyClass, PyErr, PyRef, PyRefMut, Python};
119
use std::convert::Infallible;
1210

13-
/// Returns a borrowed pointer to a Python object.
14-
///
15-
/// The returned pointer will be valid for as long as `self` is. It may be null depending on the
16-
/// implementation.
17-
///
18-
/// # Examples
19-
///
20-
/// ```rust
21-
/// use pyo3::prelude::*;
22-
/// use pyo3::ffi;
23-
///
24-
/// Python::with_gil(|py| {
25-
/// let s = "foo".into_pyobject(py)?;
26-
/// let ptr = s.as_ptr();
27-
///
28-
/// let is_really_a_pystring = unsafe { ffi::PyUnicode_CheckExact(ptr) };
29-
/// assert_eq!(is_really_a_pystring, 1);
30-
/// # Ok::<_, PyErr>(())
31-
/// })
32-
/// # .unwrap();
33-
/// ```
34-
///
35-
/// # Safety
36-
///
37-
/// For callers, it is your responsibility to make sure that the underlying Python object is not dropped too
38-
/// early. For example, the following code will cause undefined behavior:
39-
///
40-
/// ```rust,no_run
41-
/// # use pyo3::prelude::*;
42-
/// # use pyo3::ffi;
43-
/// #
44-
/// Python::with_gil(|py| {
45-
/// // ERROR: calling `.as_ptr()` will throw away the temporary object and leave `ptr` dangling.
46-
/// let ptr: *mut ffi::PyObject = 0xabad1dea_u32.into_pyobject(py)?.as_ptr();
47-
///
48-
/// let isnt_a_pystring = unsafe {
49-
/// // `ptr` is dangling, this is UB
50-
/// ffi::PyUnicode_CheckExact(ptr)
51-
/// };
52-
/// # assert_eq!(isnt_a_pystring, 0);
53-
/// # Ok::<_, PyErr>(())
54-
/// })
55-
/// # .unwrap();
56-
/// ```
57-
///
58-
/// This happens because the pointer returned by `as_ptr` does not carry any lifetime information
59-
/// and the Python object is dropped immediately after the `0xabad1dea_u32.into_pyobject(py).as_ptr()`
60-
/// expression is evaluated. To fix the problem, bind Python object to a local variable like earlier
61-
/// to keep the Python object alive until the end of its scope.
62-
///
63-
/// Implementors must ensure this returns a valid pointer to a Python object, which borrows a reference count from `&self`.
64-
pub unsafe trait AsPyPointer {
65-
/// Returns the underlying FFI pointer as a borrowed pointer.
66-
fn as_ptr(&self) -> *mut ffi::PyObject;
67-
}
68-
6911
/// Defines a conversion from a Rust type to a Python object, which may fail.
7012
///
7113
/// This trait has `#[derive(IntoPyObject)]` to automatically implement it for simple types and

src/conversions/std/option.rs

Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
2-
conversion::IntoPyObject, ffi, types::any::PyAnyMethods, AsPyPointer, Bound, BoundObject,
3-
FromPyObject, PyAny, PyResult, Python,
2+
conversion::IntoPyObject, types::any::PyAnyMethods, Bound, BoundObject, FromPyObject, PyAny,
3+
PyResult, Python,
44
};
55

66
impl<'py, T> IntoPyObject<'py> for Option<T>
@@ -49,38 +49,3 @@ where
4949
}
5050
}
5151
}
52-
53-
/// Convert `None` into a null pointer.
54-
unsafe impl<T> AsPyPointer for Option<T>
55-
where
56-
T: AsPyPointer,
57-
{
58-
#[inline]
59-
fn as_ptr(&self) -> *mut ffi::PyObject {
60-
self.as_ref()
61-
.map_or_else(std::ptr::null_mut, |t| t.as_ptr())
62-
}
63-
}
64-
65-
#[cfg(test)]
66-
mod tests {
67-
use crate::{PyObject, Python};
68-
69-
#[test]
70-
fn test_option_as_ptr() {
71-
Python::with_gil(|py| {
72-
use crate::AsPyPointer;
73-
let mut option: Option<PyObject> = None;
74-
assert_eq!(option.as_ptr(), std::ptr::null_mut());
75-
76-
let none = py.None();
77-
option = Some(none.clone_ref(py));
78-
79-
let ref_cnt = none.get_refcnt(py);
80-
assert_eq!(option.as_ptr(), none.as_ptr());
81-
82-
// Ensure ref count not changed by as_ptr call
83-
assert_eq!(none.get_refcnt(py), ref_cnt);
84-
});
85-
}
86-
}

src/impl_/extract_argument.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ pub fn from_py_with_with_default<'a, 'py, T>(
200200
#[doc(hidden)]
201201
#[cold]
202202
pub fn argument_extraction_error(py: Python<'_>, arg_name: &str, error: PyErr) -> PyErr {
203-
if error.get_type(py).is(&py.get_type::<PyTypeError>()) {
203+
if error.get_type(py).is(py.get_type::<PyTypeError>()) {
204204
let remapped_error =
205205
PyTypeError::new_err(format!("argument '{}': {}", arg_name, error.value(py)));
206206
remapped_error.set_cause(py, error.cause(py));

src/instance.rs

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use crate::pyclass::boolean_struct::{False, True};
77
use crate::types::{any::PyAnyMethods, string::PyStringMethods, typeobject::PyTypeMethods};
88
use crate::types::{DerefToPyAny, PyDict, PyString, PyTuple};
99
use crate::{
10-
ffi, AsPyPointer, DowncastError, FromPyObject, PyAny, PyClass, PyClassInitializer, PyRef,
11-
PyRefMut, PyTypeInfo, Python,
10+
ffi, DowncastError, FromPyObject, PyAny, PyClass, PyClassInitializer, PyRef, PyRefMut,
11+
PyTypeInfo, Python,
1212
};
1313
use crate::{gil, PyTypeCheck};
1414
use std::marker::PhantomData;
@@ -524,6 +524,13 @@ impl<'py, T> AsRef<Bound<'py, PyAny>> for Bound<'py, T> {
524524
}
525525
}
526526

527+
impl<T> AsRef<Py<PyAny>> for Bound<'_, T> {
528+
#[inline]
529+
fn as_ref(&self) -> &Py<PyAny> {
530+
self.as_any().as_unbound()
531+
}
532+
}
533+
527534
impl<T> Clone for Bound<'_, T> {
528535
#[inline]
529536
fn clone(&self) -> Self {
@@ -612,13 +619,6 @@ impl<'py, T> Bound<'py, T> {
612619
}
613620
}
614621

615-
unsafe impl<T> AsPyPointer for Bound<'_, T> {
616-
#[inline]
617-
fn as_ptr(&self) -> *mut ffi::PyObject {
618-
self.1.as_ptr()
619-
}
620-
}
621-
622622
impl<'py, T> BoundObject<'py, T> for Bound<'py, T> {
623623
type Any = Bound<'py, PyAny>;
624624

@@ -801,6 +801,13 @@ impl<'a, 'py, T> From<&'a Bound<'py, T>> for Borrowed<'a, 'py, T> {
801801
}
802802
}
803803

804+
impl<T> AsRef<Py<PyAny>> for Borrowed<'_, '_, T> {
805+
#[inline]
806+
fn as_ref(&self) -> &Py<PyAny> {
807+
self.as_any().as_unbound()
808+
}
809+
}
810+
804811
impl<T> std::fmt::Debug for Borrowed<'_, '_, T> {
805812
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
806813
Bound::fmt(self, f)
@@ -1315,8 +1322,8 @@ impl<T> Py<T> {
13151322
///
13161323
/// This is equivalent to the Python expression `self is other`.
13171324
#[inline]
1318-
pub fn is<U: AsPyPointer>(&self, o: &U) -> bool {
1319-
ptr::eq(self.as_ptr(), o.as_ptr())
1325+
pub fn is<U: AsRef<Py<PyAny>>>(&self, o: U) -> bool {
1326+
ptr::eq(self.as_ptr(), o.as_ref().as_ptr())
13201327
}
13211328

13221329
/// Gets the reference count of the `ffi::PyObject` pointer.
@@ -1692,11 +1699,10 @@ impl<T> Py<T> {
16921699
}
16931700
}
16941701

1695-
unsafe impl<T> crate::AsPyPointer for Py<T> {
1696-
/// Gets the underlying FFI pointer, returns a borrowed pointer.
1702+
impl<T> AsRef<Py<PyAny>> for Py<T> {
16971703
#[inline]
1698-
fn as_ptr(&self) -> *mut ffi::PyObject {
1699-
self.0.as_ptr()
1704+
fn as_ref(&self) -> &Py<PyAny> {
1705+
self.as_any()
17001706
}
17011707
}
17021708

@@ -2146,6 +2152,17 @@ a = A()
21462152
});
21472153
}
21482154

2155+
#[test]
2156+
fn test_borrowed_identity() {
2157+
Python::with_gil(|py| {
2158+
let yes = true.into_pyobject(py).unwrap();
2159+
let no = false.into_pyobject(py).unwrap();
2160+
2161+
assert!(yes.is(yes));
2162+
assert!(!yes.is(no));
2163+
});
2164+
}
2165+
21492166
#[test]
21502167
fn bound_from_borrowed_ptr_constructors() {
21512168
// More detailed tests of the underlying semantics in pycell.rs

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@
338338
#![doc = concat!("[Features chapter of the guide]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/features.html#features-reference \"Features Reference - PyO3 user guide\"")]
339339
//! [`Ungil`]: crate::marker::Ungil
340340
pub use crate::class::*;
341-
pub use crate::conversion::{AsPyPointer, FromPyObject, IntoPyObject, IntoPyObjectExt};
341+
pub use crate::conversion::{FromPyObject, IntoPyObject, IntoPyObjectExt};
342342
pub use crate::err::{DowncastError, DowncastIntoError, PyErr, PyErrArguments, PyResult, ToPyErr};
343343
#[cfg(not(any(PyPy, GraalPy)))]
344344
pub use crate::gil::{prepare_freethreaded_python, with_embedded_python_interpreter};

0 commit comments

Comments
 (0)