Skip to content

Commit 4f08cdf

Browse files
committed
introduce PyType bound constructors
1 parent e28ea8e commit 4f08cdf

File tree

6 files changed

+49
-20
lines changed

6 files changed

+49
-20
lines changed

pyo3-macros-backend/src/method.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl FnType {
126126
let py = syn::Ident::new("py", Span::call_site());
127127
let slf: Ident = syn::Ident::new("_slf", Span::call_site());
128128
quote_spanned! { *span =>
129-
#[allow(clippy::useless_conversion)]
129+
#[allow(clippy::useless_conversion, deprecated)]
130130
::std::convert::Into::into(_pyo3::types::PyType::from_type_ptr(#py, #slf.cast())),
131131
}
132132
}

src/err/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::instance::Bound;
22
use crate::panic::PanicException;
33
use crate::type_object::PyTypeInfo;
44
use crate::types::any::PyAnyMethods;
5-
use crate::types::{PyTraceback, PyType};
5+
use crate::types::{typeobject::PyTypeMethods, PyTraceback, PyType};
66
use crate::{
77
exceptions::{self, PyBaseException},
88
ffi,
@@ -202,7 +202,7 @@ impl PyErr {
202202
/// assert_eq!(err.to_string(), "TypeError: some type error");
203203
///
204204
/// // Case #2: Exception type
205-
/// let err = PyErr::from_value(PyType::new::<PyTypeError>(py));
205+
/// let err = PyErr::from_value(PyType::new_bound::<PyTypeError>(py).as_gil_ref());
206206
/// assert_eq!(err.to_string(), "TypeError: ");
207207
///
208208
/// // Case #3: Invalid exception value
@@ -233,7 +233,7 @@ impl PyErr {
233233
///
234234
/// Python::with_gil(|py| {
235235
/// let err: PyErr = PyTypeError::new_err(("some type error",));
236-
/// assert!(err.get_type(py).is(PyType::new::<PyTypeError>(py)));
236+
/// assert!(err.get_type(py).is(&PyType::new_bound::<PyTypeError>(py)));
237237
/// });
238238
/// ```
239239
pub fn get_type<'py>(&'py self, py: Python<'py>) -> &'py PyType {

src/instance.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ use crate::err::{self, PyDowncastError, PyErr, PyResult};
22
use crate::pycell::{PyBorrowError, PyBorrowMutError, PyCell};
33
use crate::pyclass::boolean_struct::{False, True};
44
use crate::type_object::HasPyGilRef;
5-
use crate::types::any::PyAnyMethods;
6-
use crate::types::string::PyStringMethods;
5+
use crate::types::{any::PyAnyMethods, string::PyStringMethods, typeobject::PyTypeMethods};
76
use crate::types::{PyDict, PyString, PyTuple};
87
use crate::{
98
ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyClass, PyClassInitializer, PyRef, PyRefMut,
@@ -312,6 +311,10 @@ impl<'a, 'py> Borrowed<'a, 'py, PyAny> {
312311
pub(crate) unsafe fn from_ptr_unchecked(py: Python<'py>, ptr: *mut ffi::PyObject) -> Self {
313312
Self(NonNull::new_unchecked(ptr), PhantomData, py)
314313
}
314+
315+
pub(crate) unsafe fn downcast_into_unchecked<T>(self) -> Borrowed<'a, 'py, T> {
316+
Borrowed(self.0, PhantomData, self.py())
317+
}
315318
}
316319

317320
impl<'a, 'py, T> From<&'a Bound<'py, T>> for Borrowed<'a, 'py, T> {
@@ -325,10 +328,10 @@ impl<'py, T> Borrowed<'py, 'py, T>
325328
where
326329
T: HasPyGilRef,
327330
{
328-
// pub(crate) fn into_gil_ref(self) -> &'py T::AsRefTarget {
329-
// // Safety: self is a borrow over `'py`.
330-
// unsafe { self.py().from_borrowed_ptr(self.0.as_ptr()) }
331-
// }
331+
pub(crate) fn into_gil_ref(self) -> &'py T::AsRefTarget {
332+
// Safety: self is a borrow over `'py`.
333+
unsafe { self.py().from_borrowed_ptr(self.0.as_ptr()) }
334+
}
332335
}
333336

334337
impl<T> std::fmt::Debug for Borrowed<'_, '_, T> {

src/types/any.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,7 @@ impl PyAny {
712712

713713
/// Returns the Python type object for this object's type.
714714
pub fn get_type(&self) -> &PyType {
715-
self.as_borrowed().get_type()
715+
self.as_borrowed().get_type().into_gil_ref()
716716
}
717717

718718
/// Returns the Python type pointer for this object.
@@ -1490,7 +1490,7 @@ pub trait PyAnyMethods<'py> {
14901490
fn iter(&self) -> PyResult<Bound<'py, PyIterator>>;
14911491

14921492
/// Returns the Python type object for this object's type.
1493-
fn get_type(&self) -> &'py PyType;
1493+
fn get_type(&self) -> Bound<'py, PyType>;
14941494

14951495
/// Returns the Python type pointer for this object.
14961496
fn get_type_ptr(&self) -> *mut ffi::PyTypeObject;
@@ -2021,8 +2021,8 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
20212021
PyIterator::from_object2(self)
20222022
}
20232023

2024-
fn get_type(&self) -> &'py PyType {
2025-
unsafe { PyType::from_type_ptr(self.py(), ffi::Py_TYPE(self.as_ptr())) }
2024+
fn get_type(&self) -> Bound<'py, PyType> {
2025+
unsafe { PyType::from_type_ptr_borrowed(self.py(), ffi::Py_TYPE(self.as_ptr())) }.to_owned()
20262026
}
20272027

20282028
#[inline]
@@ -2179,7 +2179,7 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
21792179

21802180
#[cfg(not(PyPy))]
21812181
fn py_super(&self) -> PyResult<Bound<'py, PySuper>> {
2182-
PySuper::new_bound(&self.get_type().as_borrowed(), self)
2182+
PySuper::new_bound(&self.get_type(), self)
21832183
}
21842184
}
21852185

src/types/typeobject.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,52 @@ pub struct PyType(PyAny);
1414
pyobject_native_type_core!(PyType, pyobject_native_static_type_object!(ffi::PyType_Type), #checkfunction=ffi::PyType_Check);
1515

1616
impl PyType {
17-
/// Creates a new type object.
17+
/// Deprecated form of [`PyType::new_bound`].
1818
#[inline]
19+
#[deprecated(
20+
since = "0.21.0",
21+
note = "`new` will be replaced by `new_bound` in a future PyO3 version"
22+
)]
1923
pub fn new<T: PyTypeInfo>(py: Python<'_>) -> &PyType {
2024
T::type_object(py)
2125
}
2226

27+
/// Creates a new type object.
28+
#[inline]
29+
pub fn new_bound<T: PyTypeInfo>(py: Python<'_>) -> Bound<'_, PyType> {
30+
T::type_object(py).as_borrowed().to_owned()
31+
}
32+
2333
/// Retrieves the underlying FFI pointer associated with this Python object.
2434
#[inline]
2535
pub fn as_type_ptr(&self) -> *mut ffi::PyTypeObject {
2636
self.as_borrowed().as_type_ptr()
2737
}
2838

39+
/// Deprecated form of [`PyType::from_type_ptr_borrowed`].
40+
#[inline]
41+
#[deprecated(
42+
since = "0.21.0",
43+
note = "`from_type_ptr` will be replaced by `from_type_ptr_borrowed` in a future PyO3 version"
44+
)]
45+
pub unsafe fn from_type_ptr(py: Python<'_>, p: *mut ffi::PyTypeObject) -> &PyType {
46+
Self::from_type_ptr_borrowed(py, p).into_gil_ref()
47+
}
48+
2949
/// Retrieves the `PyType` instance for the given FFI pointer.
3050
///
3151
/// # Safety
3252
/// - The pointer must be non-null.
33-
/// - The pointer must be valid for the entire of the lifetime for which the reference is used.
53+
/// - The pointer must be valid for the entire of the lifetime 'a for which the reference is used,
54+
/// as with `std::slice::from_raw_parts`.
3455
#[inline]
35-
pub unsafe fn from_type_ptr(py: Python<'_>, p: *mut ffi::PyTypeObject) -> &PyType {
36-
py.from_borrowed_ptr(p as *mut ffi::PyObject)
56+
pub unsafe fn from_type_ptr_borrowed<'a>(
57+
py: Python<'_>,
58+
p: *mut ffi::PyTypeObject,
59+
) -> Borrowed<'a, '_, PyType> {
60+
(p as *mut ffi::PyObject)
61+
.assume_borrowed_unchecked(py)
62+
.downcast_into_unchecked()
3763
}
3864

3965
/// Gets the [qualified name](https://docs.python.org/3/glossary.html#term-qualified-name) of the `PyType`.

tests/test_class_basics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ impl UnsendableChild {
230230

231231
fn test_unsendable<T: PyClass + 'static>() -> PyResult<()> {
232232
let obj = Python::with_gil(|py| -> PyResult<_> {
233-
let obj: Py<T> = PyType::new::<T>(py).call1((5,))?.extract()?;
233+
let obj: Py<T> = PyType::new_bound::<T>(py).call1((5,))?.extract()?;
234234

235235
// Accessing the value inside this thread should not panic
236236
let caught_panic =

0 commit comments

Comments
 (0)