Skip to content

Commit f71feec

Browse files
committed
Avoids panic on class initialization when adding a class to the module
1 parent 0b7fdd4 commit f71feec

File tree

5 files changed

+20
-4
lines changed

5 files changed

+20
-4
lines changed

pyo3-macros-backend/src/pyclass.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1290,6 +1290,16 @@ fn impl_pytypeinfo(
12901290
.get_or_init(py)
12911291
.as_type_ptr()
12921292
}
1293+
1294+
#[inline]
1295+
fn try_type_object_bound(py: _pyo3::Python<'_>) -> _pyo3::PyResult<_pyo3::Bound<'_, _pyo3::types::PyType>> {
1296+
use ::std::borrow::ToOwned;
1297+
#deprecations
1298+
1299+
<#cls as _pyo3::impl_::pyclass::PyClassImpl>::lazy_type_object()
1300+
.get_or_try_init(py)
1301+
.map(|t| t.to_owned())
1302+
}
12931303
}
12941304
}
12951305
}

src/impl_/pyclass/lazy_type_object.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ impl<T: PyClass> LazyTypeObject<T> {
5454
}
5555

5656
/// Fallible version of the above.
57-
pub(crate) fn get_or_try_init<'py>(&self, py: Python<'py>) -> PyResult<&Bound<'py, PyType>> {
57+
pub fn get_or_try_init<'py>(&self, py: Python<'py>) -> PyResult<&Bound<'py, PyType>> {
5858
self.0
5959
.get_or_try_init(py, create_type_object::<T>, T::NAME, T::items_iter())
6060
}

src/impl_/pymodule.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ pub trait PyAddToModule {
143143

144144
impl<T: PyTypeInfo> PyAddToModule for T {
145145
fn add_to_module(module: &Bound<'_, PyModule>) -> PyResult<()> {
146-
module.add(Self::NAME, Self::type_object_bound(module.py()))
146+
module.add(Self::NAME, Self::try_type_object_bound(module.py())?)
147147
}
148148
}
149149

src/type_object.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::ffi_ptr_ext::FfiPtrExt;
44
use crate::types::any::PyAnyMethods;
55
use crate::types::{PyAny, PyType};
6-
use crate::{ffi, Bound, PyNativeType, Python};
6+
use crate::{ffi, Bound, PyNativeType, PyResult, Python};
77

88
/// `T: PyLayout<U>` represents that `T` is a concrete representation of `U` in the Python heap.
99
/// E.g., `PyCell` is a concrete representation of all `pyclass`es, and `ffi::PyObject`
@@ -96,6 +96,12 @@ pub unsafe trait PyTypeInfo: Sized + HasPyGilRef {
9696
}
9797
}
9898

99+
/// Returns the safe abstraction over the type object or an error if initialization fails
100+
#[inline]
101+
fn try_type_object_bound(py: Python<'_>) -> PyResult<Bound<'_, PyType>> {
102+
Ok(Self::type_object_bound(py))
103+
}
104+
99105
/// Checks if `object` is an instance of this type or a subclass of this type.
100106
#[inline]
101107
#[cfg_attr(

src/types/module.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ impl<'py> PyModuleMethods<'py> for Bound<'py, PyModule> {
633633
T: PyClass,
634634
{
635635
let py = self.py();
636-
self.add(T::NAME, T::lazy_type_object().get_or_try_init(py)?)
636+
self.add(T::NAME, T::try_type_object_bound(py)?)
637637
}
638638

639639
fn add_wrapped<T>(&self, wrapper: &impl Fn(Python<'py>) -> T) -> PyResult<()>

0 commit comments

Comments
 (0)