Fix some pyo3 testcase against the c-api (#8349)

This commit is contained in:
Bas Schoenmaeckers authored and GitHub committed 2026-07-25 20:07:44 +09:00
1 parent 1ee695e9a2
commit 0dc8f0fcad
5 files changed
+67 -3

No files matched your search

+13 -1
View File
@@ -8,7 +8,11 @@ use rustpython_vm::import::import_code_obj;
pub unsafe extern "C" fn PyImport_Import(name: *mut PyObject) -> *mut PyObject {
with_vm(|vm| {
let name = unsafe { (&*name).try_downcast_ref::<PyStr>(vm)? };
vm.import(name, 0)
let _ = vm.import(name, 0)?;
vm.sys_module
.get_attr(rustpython_vm::identifier!(vm, modules), vm)?
.get_item(name, vm)
})
}
@@ -74,4 +78,12 @@ mod tests {
let _module = py.import("types").unwrap();
})
}
#[test]
fn import_sub_module() {
Python::attach(|py| {
let module = py.import("collections.abc").unwrap();
module.getattr("Sequence").unwrap();
})
}
}
+14
View File
@@ -53,6 +53,7 @@ pub(crate) fn build_method_def(
let flags = PyMethodFlags::from_bits(ml.ml_flags as u32)
.ok_or_else(|| vm.new_system_error("PyMethodDef contains unknown flags"))?;
let has_self = has_self && !flags.contains(PyMethodFlags::STATIC);
let method = ml.ml_meth;
@@ -359,4 +360,17 @@ mod tests {
);
})
}
#[test]
fn wrap_static_no_args_function() {
#[pyfunction()]
fn f() {}
Python::attach(|py| {
let module = PyModule::new(py, "test_wrap_pyfunction_forms").unwrap();
let func = wrap_pyfunction!(f, &module).unwrap();
func.call0().unwrap();
});
}
}
+14 -2
View File
@@ -217,7 +217,7 @@ pub unsafe extern "C" fn PyObject_HasAttrWithError(
with_vm(|vm| {
let obj = unsafe { &*obj };
let name = unsafe { &*attr_name }.try_downcast_ref::<PyStr>(vm)?;
obj.has_attr(name, vm)
Ok(vm.get_attribute_opt(obj.to_owned(), name)?.is_some())
})
}
@@ -272,7 +272,7 @@ pub unsafe extern "C" fn PyObject_HasAttrStringWithError(
with_vm(|vm| {
let obj = unsafe { &*obj };
let name = unsafe { attr_name.try_as_str(vm) }?;
obj.has_attr(name, vm)
Ok(vm.get_attribute_opt(obj.to_owned(), name)?.is_some())
})
}
@@ -591,4 +591,16 @@ mod tests {
assert!(dict.get_item("foo").is_ok());
})
}
#[test]
fn hasattr() {
Python::attach(|py| {
let x = 5i32.into_pyobject(py).unwrap();
assert!(x.is_instance_of::<PyInt>());
// spell-checker:ignore bbbbbbytes
assert!(x.hasattr("to_bytes").unwrap());
assert!(!x.hasattr("bbbbbbytes").unwrap());
})
}
}
+23
View File
@@ -48,6 +48,11 @@ pub unsafe extern "C" fn PyCapsule_GetContext(capsule: *mut PyObject) -> *mut c_
let capsule = unsafe { &*capsule }
.downcast_ref_if_exact::<PyCapsule>(vm)
.ok_or_else(|| vm.new_value_error("Invalid capsule"))?;
if capsule.pointer().is_null() {
return Err(vm.new_value_error("Capsule has null pointer"));
}
Ok(capsule.context())
})
}
@@ -143,6 +148,7 @@ fn checked_capsule<'a>(
#[cfg(test)]
mod tests {
use pyo3::ffi;
use pyo3::prelude::*;
use pyo3::types::PyCapsule;
@@ -156,4 +162,21 @@ mod tests {
assert_eq!(unsafe { ptr.cast::<String>().as_ref() }, "Some data");
})
}
#[test]
fn capsule_context_on_invalid_capsule() {
Python::attach(|py| {
let cap = PyCapsule::new_with_value(py, 123u32, c"name").unwrap();
// Invalidate the capsule
// SAFETY: intentionally breaking the capsule for testing
unsafe {
ffi::PyCapsule_SetPointer(cap.as_ptr(), core::ptr::null_mut());
}
// context() on invalid capsule should fail
let result = cap.context();
assert!(result.is_err());
});
}
}
+3
View File
@@ -76,6 +76,9 @@ impl Representable for PyCapsule {
impl Destructor for PyCapsule {
fn del(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<()> {
if zelf.pointer().is_null() {
return Ok(());
}
if let Some(destructor) = zelf.destructor() {
unsafe { destructor(zelf.as_object().as_raw().cast_mut()) };
}