use simplified PyIter_Check on CPython 3.7

This commit is contained in:
David Hewitt 2023-02-03 07:53:38 +00:00
parent f4953224d8
commit 5bab0e9409
3 changed files with 10 additions and 16 deletions

View File

@ -0,0 +1 @@
FFI definition `PyIter_Check` on CPython 3.7 now does the equivalent for `hasattr(type(obj), "__next__")`, which works correctly on all platforms and adds support for `abi3`.

View File

@ -92,19 +92,17 @@ extern "C" {
} }
// Before 3.8 PyIter_Check was defined in CPython as a macro, // Before 3.8 PyIter_Check was defined in CPython as a macro,
// which uses Py_TYPE so cannot work on the limited ABI. // but the implementation of that in PyO3 did not work, see
// https://github.com/PyO3/pyo3/pull/2914
// //
// From 3.10 onwards CPython removed the macro completely, // This is a slow implementation which should function equivalently.
// so PyO3 only uses this on 3.7 unlimited API. #[cfg(not(any(Py_3_8, PyPy)))]
#[cfg(not(any(Py_3_8, Py_LIMITED_API, PyPy)))]
#[inline] #[inline]
pub unsafe fn PyIter_Check(o: *mut PyObject) -> c_int { pub unsafe fn PyIter_Check(o: *mut PyObject) -> c_int {
(match (*crate::Py_TYPE(o)).tp_iternext { crate::PyObject_HasAttrString(
Some(tp_iternext) => { crate::Py_TYPE(o).cast(),
tp_iternext as *const std::os::raw::c_void != crate::_PyObject_NextNotImplemented as _ "__next__\0".as_ptr() as *const c_char,
} )
None => false,
}) as c_int
} }
extern "C" { extern "C" {

View File

@ -3,7 +3,6 @@
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
use crate::{ffi, AsPyPointer, IntoPyPointer, Py, PyAny, PyErr, PyNativeType, PyResult, Python}; use crate::{ffi, AsPyPointer, IntoPyPointer, Py, PyAny, PyErr, PyNativeType, PyResult, Python};
#[cfg(any(not(Py_LIMITED_API), Py_3_8))]
use crate::{PyDowncastError, PyTryFrom}; use crate::{PyDowncastError, PyTryFrom};
/// A Python iterator object. /// A Python iterator object.
@ -29,7 +28,6 @@ use crate::{PyDowncastError, PyTryFrom};
#[repr(transparent)] #[repr(transparent)]
pub struct PyIterator(PyAny); pub struct PyIterator(PyAny);
pyobject_native_type_named!(PyIterator); pyobject_native_type_named!(PyIterator);
#[cfg(any(not(Py_LIMITED_API), Py_3_8))]
pyobject_native_type_extract!(PyIterator); pyobject_native_type_extract!(PyIterator);
impl PyIterator { impl PyIterator {
@ -64,7 +62,6 @@ impl<'p> Iterator for &'p PyIterator {
} }
// PyIter_Check does not exist in the limited API until 3.8 // PyIter_Check does not exist in the limited API until 3.8
#[cfg(any(not(Py_LIMITED_API), Py_3_8))]
impl<'v> PyTryFrom<'v> for PyIterator { impl<'v> PyTryFrom<'v> for PyIterator {
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v PyIterator, PyDowncastError<'v>> { fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v PyIterator, PyDowncastError<'v>> {
let value = value.into(); let value = value.into();
@ -218,7 +215,7 @@ def fibonacci(target):
} }
#[test] #[test]
#[cfg(any(not(Py_LIMITED_API), Py_3_8))]
fn iterator_try_from() { fn iterator_try_from() {
Python::with_gil(|py| { Python::with_gil(|py| {
let obj: Py<PyAny> = vec![10, 20].to_object(py).as_ref(py).iter().unwrap().into(); let obj: Py<PyAny> = vec![10, 20].to_object(py).as_ref(py).iter().unwrap().into();
@ -250,7 +247,6 @@ def fibonacci(target):
} }
#[test] #[test]
#[cfg(any(not(Py_LIMITED_API), Py_3_8))]
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
fn python_class_not_iterator() { fn python_class_not_iterator() {
use crate::PyErr; use crate::PyErr;
@ -298,7 +294,6 @@ def fibonacci(target):
} }
#[test] #[test]
#[cfg(any(not(Py_LIMITED_API), Py_3_8))]
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
fn python_class_iterator() { fn python_class_iterator() {
#[crate::pyfunction(crate = "crate")] #[crate::pyfunction(crate = "crate")]