From e08ea56f4ea7e29cdc7723672df6885d5c44f4ed Mon Sep 17 00:00:00 2001 From: bgopi23 Date: Sat, 8 Mar 2025 20:15:54 +0800 Subject: [PATCH 1/2] FIX: Correct return type of NpyIter_GetIterNext in Cython declarations (#28446) --- numpy/__init__.cython-30.pxd | 2 +- numpy/__init__.pxd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/numpy/__init__.cython-30.pxd b/numpy/__init__.cython-30.pxd index e35cef5fa1a8..54af0e1f8319 100644 --- a/numpy/__init__.cython-30.pxd +++ b/numpy/__init__.cython-30.pxd @@ -1230,7 +1230,7 @@ cdef extern from "numpy/arrayobject.h": npy_intp* outstrides) except NPY_FAIL npy_bool NpyIter_IsFirstVisit(NpyIter* it, int iop) nogil # functions for iterating an NpyIter object - NpyIter_IterNextFunc* NpyIter_GetIterNext(NpyIter* it, char** errmsg) except NULL + NpyIter_IterNextFunc NpyIter_GetIterNext(NpyIter* it, char** errmsg) except NULL NpyIter_GetMultiIndexFunc* NpyIter_GetGetMultiIndex(NpyIter* it, char** errmsg) except NULL char** NpyIter_GetDataPtrArray(NpyIter* it) nogil diff --git a/numpy/__init__.pxd b/numpy/__init__.pxd index 89fe913b9cd3..0822e9c129e5 100644 --- a/numpy/__init__.pxd +++ b/numpy/__init__.pxd @@ -1145,7 +1145,7 @@ cdef extern from "numpy/arrayobject.h": npy_intp* outstrides) except NPY_FAIL npy_bool NpyIter_IsFirstVisit(NpyIter* it, int iop) nogil # functions for iterating an NpyIter object - NpyIter_IterNextFunc* NpyIter_GetIterNext(NpyIter* it, char** errmsg) except NULL + NpyIter_IterNextFunc NpyIter_GetIterNext(NpyIter* it, char** errmsg) except NULL NpyIter_GetMultiIndexFunc* NpyIter_GetGetMultiIndex(NpyIter* it, char** errmsg) except NULL char** NpyIter_GetDataPtrArray(NpyIter* it) nogil From 48e3a43402c8a3c6e0d5b4761d1fbd197d75bd09 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Fri, 14 Mar 2025 11:44:29 -0600 Subject: [PATCH 2/2] MAINT: work around cython limitations, add test --- numpy/__init__.cython-30.pxd | 19 +++++++++++++------ numpy/__init__.pxd | 16 +++++++++++----- numpy/_core/tests/examples/cython/checks.pyx | 9 +++++++++ numpy/_core/tests/test_cython.py | 1 + 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/numpy/__init__.cython-30.pxd b/numpy/__init__.cython-30.pxd index 54af0e1f8319..0728aad4829f 100644 --- a/numpy/__init__.cython-30.pxd +++ b/numpy/__init__.cython-30.pxd @@ -858,6 +858,14 @@ cdef extern from "numpy/ndarraytypes.h": int64_t year int32_t month, day, hour, min, sec, us, ps, as + # Iterator API added in v1.6 + # + # These don't match the definition in the C API because Cython can't wrap + # function pointers that return functions. + # https://github.com/cython/cython/issues/6720 + ctypedef int (*NpyIter_IterNextFunc "NpyIter_IterNextFunc *")(NpyIter* it) noexcept nogil + ctypedef void (*NpyIter_GetMultiIndexFunc "NpyIter_GetMultiIndexFunc *")(NpyIter* it, npy_intp* outcoords) noexcept nogil + cdef extern from "numpy/arrayscalars.h": @@ -1109,10 +1117,6 @@ cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) noexcept nogil: return (obj).obmeta.base -# Iterator API added in v1.6 -ctypedef int (*NpyIter_IterNextFunc)(NpyIter* it) noexcept nogil -ctypedef void (*NpyIter_GetMultiIndexFunc)(NpyIter* it, npy_intp* outcoords) noexcept nogil - cdef extern from "numpy/arrayobject.h": ctypedef struct NpyIter: @@ -1230,9 +1234,12 @@ cdef extern from "numpy/arrayobject.h": npy_intp* outstrides) except NPY_FAIL npy_bool NpyIter_IsFirstVisit(NpyIter* it, int iop) nogil # functions for iterating an NpyIter object + # + # These don't match the definition in the C API because Cython can't wrap + # function pointers that return functions. NpyIter_IterNextFunc NpyIter_GetIterNext(NpyIter* it, char** errmsg) except NULL - NpyIter_GetMultiIndexFunc* NpyIter_GetGetMultiIndex(NpyIter* it, - char** errmsg) except NULL + NpyIter_GetMultiIndexFunc NpyIter_GetGetMultiIndex(NpyIter* it, + char** errmsg) except NULL char** NpyIter_GetDataPtrArray(NpyIter* it) nogil char** NpyIter_GetInitialDataPtrArray(NpyIter* it) nogil npy_intp* NpyIter_GetIndexPtr(NpyIter* it) diff --git a/numpy/__init__.pxd b/numpy/__init__.pxd index 0822e9c129e5..6a62a3820042 100644 --- a/numpy/__init__.pxd +++ b/numpy/__init__.pxd @@ -773,6 +773,13 @@ cdef extern from "numpy/ndarraytypes.h": int64_t year int32_t month, day, hour, min, sec, us, ps, as + # Iterator API added in v1.6 + # + # These don't match the definition in the C API because Cython can't wrap + # function pointers that return functions. + # https://github.com/cython/cython/issues/6720 + ctypedef int (*NpyIter_IterNextFunc "NpyIter_IterNextFunc *")(NpyIter* it) noexcept nogil + ctypedef void (*NpyIter_GetMultiIndexFunc "NpyIter_GetMultiIndexFunc *")(NpyIter* it, npy_intp* outcoords) noexcept nogil cdef extern from "numpy/arrayscalars.h": @@ -1024,10 +1031,6 @@ cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: return (obj).obmeta.base -# Iterator API added in v1.6 -ctypedef int (*NpyIter_IterNextFunc)(NpyIter* it) noexcept nogil -ctypedef void (*NpyIter_GetMultiIndexFunc)(NpyIter* it, npy_intp* outcoords) noexcept nogil - cdef extern from "numpy/arrayobject.h": ctypedef struct NpyIter: @@ -1145,7 +1148,10 @@ cdef extern from "numpy/arrayobject.h": npy_intp* outstrides) except NPY_FAIL npy_bool NpyIter_IsFirstVisit(NpyIter* it, int iop) nogil # functions for iterating an NpyIter object - NpyIter_IterNextFunc NpyIter_GetIterNext(NpyIter* it, char** errmsg) except NULL + # + # These don't match the definition in the C API because Cython can't wrap + # function pointers that return functions. + NpyIter_IterNextFunc* NpyIter_GetIterNext(NpyIter* it, char** errmsg) except NULL NpyIter_GetMultiIndexFunc* NpyIter_GetGetMultiIndex(NpyIter* it, char** errmsg) except NULL char** NpyIter_GetDataPtrArray(NpyIter* it) nogil diff --git a/numpy/_core/tests/examples/cython/checks.pyx b/numpy/_core/tests/examples/cython/checks.pyx index 34359fb42fcb..028dc6a6c9e4 100644 --- a/numpy/_core/tests/examples/cython/checks.pyx +++ b/numpy/_core/tests/examples/cython/checks.pyx @@ -242,6 +242,15 @@ def npyiter_has_multi_index(it: "nditer"): return result +def test_get_multi_index_iter_next(it: "nditer", cnp.ndarray[cnp.float64_t, ndim=2] arr): + cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it) + cdef cnp.NpyIter_GetMultiIndexFunc get_multi_index = \ + cnp.NpyIter_GetGetMultiIndex(cit, NULL) + cdef cnp.NpyIter_IterNextFunc iternext = \ + cnp.NpyIter_GetIterNext(cit, NULL) + return 1 + + def npyiter_has_finished(it: "nditer"): cdef cnp.NpyIter* cit try: diff --git a/numpy/_core/tests/test_cython.py b/numpy/_core/tests/test_cython.py index d7fe28a8f053..ac29a2f7407b 100644 --- a/numpy/_core/tests/test_cython.py +++ b/numpy/_core/tests/test_cython.py @@ -267,6 +267,7 @@ def test_npyiter_api(install_temp): assert checks.get_npyiter_size(it) == it.itersize == np.prod(arr.shape) assert checks.npyiter_has_multi_index(it) == it.has_multi_index == True assert checks.get_npyiter_ndim(it) == it.ndim == 2 + assert checks.test_get_multi_index_iter_next(it, arr) arr2 = np.random.rand(2, 1, 2) it = np.nditer([arr, arr2])