diff --git a/guide/src/migration.md b/guide/src/migration.md index 3cfcdbc0f6a..f525a0d81fd 100644 --- a/guide/src/migration.md +++ b/guide/src/migration.md @@ -57,7 +57,7 @@ Before: struct MyWrapper(T); impl<'py, T> FromPyObject<'py> for MyWrapper -where +where T: FromPyObject<'py> { fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult { @@ -66,7 +66,7 @@ where } ``` -After: +After: ```rust # use pyo3::prelude::*; # #[allow(dead_code)] @@ -133,6 +133,12 @@ This is very similar to `serde`s [`Deserialize`] and [`DeserializeOwned`] traits [`DeserializeOwned`]: https://docs.rs/serde/latest/serde/de/trait.DeserializeOwned.html +## `PyTypeCheck` is now an `unsafe trait` + +Because `PyTypeCheck` is the trait used to guard the `.cast()` functions to treat Python objects as specific concrete types, the trait is `unsafe` to implement. + +This should always have been the case, it was an unfortunate omission from its original implementation which is being corrected in this release. + ## from 0.25.* to 0.26 ### Rename of `Python::with_gil`, `Python::allow_threads`, and `pyo3::prepare_freethreaded_python`
diff --git a/newsfragments/5473.changed.md b/newsfragments/5473.changed.md new file mode 100644 index 00000000000..71c54298f55 --- /dev/null +++ b/newsfragments/5473.changed.md @@ -0,0 +1 @@ +Make `PyTypeCheck` an `unsafe trait`. diff --git a/src/type_object.rs b/src/type_object.rs index fd25d519e07..f7f8d4dbfd1 100644 --- a/src/type_object.rs +++ b/src/type_object.rs @@ -35,6 +35,10 @@ pub trait PySizedLayout: PyLayout + Sized {} /// /// Implementations must provide an implementation for `type_object_raw` which infallibly produces a /// non-null pointer to the corresponding Python type object. +/// +/// `is_type_of` must only return true for objects which can safely be treated as instances of `Self`. +/// +/// `is_exact_type_of` must only return true for objects whose type is exactly `Self`. pub unsafe trait PyTypeInfo: Sized { /// Class name. const NAME: &'static str; @@ -85,7 +89,13 @@ pub unsafe trait PyTypeInfo: Sized { } /// Implemented by types which can be used as a concrete Python type inside `Py` smart pointers. -pub trait PyTypeCheck { +/// +/// # Safety +/// +/// This trait is used to determine whether [`Bound::cast`] and similar functions can safely cast +/// to a concrete type. The implementor is responsible for ensuring that `type_check` only returns +/// true for objects which can safely be treated as Python instances of `Self`. +pub unsafe trait PyTypeCheck { /// Name of self. This is used in error messages, for example. #[deprecated( since = "0.27.0", @@ -108,7 +118,7 @@ pub trait PyTypeCheck { fn classinfo_object(py: Python<'_>) -> Bound<'_, PyAny>; } -impl PyTypeCheck for T +unsafe impl PyTypeCheck for T where T: PyTypeInfo, { diff --git a/src/types/weakref/anyref.rs b/src/types/weakref/anyref.rs index 1fcb96a6918..4c5772f98f2 100644 --- a/src/types/weakref/anyref.rs +++ b/src/types/weakref/anyref.rs @@ -18,7 +18,7 @@ pyobject_native_type_named!(PyWeakref); // #[cfg(not(Py_LIMITED_API))] // pyobject_native_type_sized!(PyWeakref, ffi::PyWeakReference); -impl PyTypeCheck for PyWeakref { +unsafe impl PyTypeCheck for PyWeakref { const NAME: &'static str = "weakref"; #[cfg(feature = "experimental-inspect")] diff --git a/src/types/weakref/proxy.rs b/src/types/weakref/proxy.rs index 85823aa1428..6f2bc1d57ac 100644 --- a/src/types/weakref/proxy.rs +++ b/src/types/weakref/proxy.rs @@ -20,7 +20,7 @@ pyobject_native_type_named!(PyWeakrefProxy); // #[cfg(not(Py_LIMITED_API))] // pyobject_native_type_sized!(PyWeakrefProxy, ffi::PyWeakReference); -impl PyTypeCheck for PyWeakrefProxy { +unsafe impl PyTypeCheck for PyWeakrefProxy { const NAME: &'static str = "weakref.ProxyTypes"; #[cfg(feature = "experimental-inspect")]