From 2ae701e82539ee346c3721e5ed9d7b8b6c69e08c Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers <7943856+bschoenmaeckers@users.noreply.github.com> Date: Wed, 21 Oct 2026 05:02:11 +0200 Subject: [PATCH] Add a test for `PyType_FromSpec` (#9258) --- crates/capi/src/object/pytype.rs | 32 +++++++++++++++++++++++++++++++- crates/capi/src/slots.rs | 2 ++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/crates/capi/src/object/pytype.rs b/crates/capi/src/object/pytype.rs index 44d3ff2f2..8d05ef0bf 100644 --- a/crates/capi/src/object/pytype.rs +++ b/crates/capi/src/object/pytype.rs @@ -128,7 +128,9 @@ pub unsafe extern "C" fn PyType_FromSlots(slots: *const PySlot) -> *mut PyObject })?; type_slots.flags = AtomicPyTypeFlags::from_plain(flags); } - PySlotType::BasicSize(size) | PySlotType::ExtraBasicSize(size) => { + PySlotType::BasicSize(size) + | PySlotType::ExtraBasicSize(size) + | PySlotType::ItemSize(size) => { if size != 0 { return Err(vm.new_not_implemented_error( "PyType_FromSlots with non-zero size is not yet supported", @@ -323,6 +325,7 @@ pub extern "C" fn PyType_Freeze(_ty: *mut PyTypeObject) -> c_int { #[cfg(test)] mod tests { use pyo3::IntoPyObjectExt; + use pyo3::ffi; use pyo3::prelude::*; use pyo3::types::{PyDict, PyInt, PyList, PyString, PyType, PyTypeMethods}; @@ -512,4 +515,31 @@ mod tests { ); }); } + + #[test] + fn type_from_spec() { + Python::attach(|py| { + let mut slots = [ffi::PyType_Slot { + slot: 0, + pfunc: core::ptr::null_mut(), + }]; + let mut spec = ffi::PyType_Spec { + name: c"somemodule.MySpecClass".as_ptr(), + basicsize: 0, + itemsize: 0, + flags: ffi::Py_TPFLAGS_DEFAULT as _, + slots: slots.as_mut_ptr(), + }; + + let type_ptr = unsafe { ffi::PyType_FromSpec(&mut spec) }; + let type_obj = unsafe { + Bound::from_borrowed_ptr_or_err(py, type_ptr) + .unwrap() + .cast_into::() + .unwrap() + }; + + assert_eq!(type_obj.qualname().unwrap(), "somemodule.MySpecClass"); + }); + } } diff --git a/crates/capi/src/slots.rs b/crates/capi/src/slots.rs index 7e6ed3899..590ffcf3b 100644 --- a/crates/capi/src/slots.rs +++ b/crates/capi/src/slots.rs @@ -158,6 +158,7 @@ impl PySlot { })), 96 => PySlotKind::Type(PySlotType::BasicSize(unsafe { self.value.sl_size })), 97 => PySlotKind::Type(PySlotType::ExtraBasicSize(unsafe { self.value.sl_size })), + 98 => PySlotKind::Type(PySlotType::ItemSize(unsafe { self.value.sl_size })), 99 => PySlotKind::Type(PySlotType::Flags(unsafe { self.value.sl_uint64 })), 100 => PySlotKind::Module(PySlotModule::Name(unsafe { value_ptr.cast::().try_as_str(vm)? @@ -239,6 +240,7 @@ pub(crate) enum PySlotType<'a> { Flags(u64), BasicSize(isize), ExtraBasicSize(isize), + ItemSize(isize), Metaclass(&'a Py), Module(&'a Py), }