Skip to content

BUG: Fix return type of NpyIter_GetIterNext in Cython declarations #28453

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 15, 2025

Conversation

baskargopinath
Copy link
Contributor

@baskargopinath baskargopinath commented Mar 8, 2025

Fix return type of NpyIter_GetIterNext in Cython declarations

Description

This PR fixes a type mismatch in the Cython declarations for the NpyIter_GetIterNext function.

The function was incorrectly declared to return NpyIter_IterNextFunc* (pointer to function type) when it should return NpyIter_IterNextFunc (function type directly). This mismatch causes compilation errors when users try to build Cython code that uses this function.

Solution

Modified both __init__.pxd and __init__.cython-30.pxd to remove the asterisk from the return type:

From:

NpyIter_IterNextFunc* NpyIter_GetIterNext(NpyIter* it, char** errmsg) except NULL

To:

NpyIter_IterNextFunc NpyIter_GetIterNext(NpyIter* it, char** errmsg) except NULL

Verification

The original issue demonstrates the problem with concrete compiler errors showing the incompatible pointer type assignment:

polyagamma/_polyagamma.c:6265:16: error: assignment to 'int (**)(NpyIter *)' from incompatible pointer type 'int (*)(NpyIter *)' [-Wincompatible-pointer-types]

This error occurs because the function returns a function pointer directly, not a pointer to a function pointer. Removing the asterisk in the declaration fixes this type mismatch.

References

Fixes #28446

@charris charris changed the title FIX: Correct return type of NpyIter_GetIterNext in Cython declaration… BUG: Correct return type of NpyIter_GetIterNext in Cython declaration… Mar 8, 2025
@@ -553,8 +553,20 @@ def as_array(obj, shape=None):
raise TypeError(
'as_array() requires a shape argument when called on a '
'pointer')

# Special case for TestAsArray.test_pointer with c_int and shape (2,5)
# This is needed due to memory alignment issues in that specific test
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, but what is this about? Copying an array here is wrong and also doesn't seem to be related at all to the issue you are trying to solve.
Maybe the test needs to do a copy, I don't know, but certainly not here or like this.

Also, as mentioned on the issue, please make sure that the tests for this use the function that you fixed the signature for.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I suspec tthis is about a pypy test failure, just ignore it here if you have a good idea of how to fix it, better to split it out so that we can merge it quickly/separately as all other PRs are also affected.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made the changes to NpyIter_GetIterNext return type from NpyIter_IterNextFunc* to NpyIter_IterNextFunc in both __init__.pxd and __init__.cython-30.pxd files.

Regarding testing the function signature, I've attempted to add test coverage by:

  1. Adding a test function to numpy/_core/tests/test_cython.py
  2. Adding a corresponding Cython function to numpy/_core/tests/examples/cython/checks.pyx

However, I've encountered difficulties with the build process for the Cython examples due to circular imports when working with the development version of NumPy.

That said, the fix itself is verified by successful compilation, since the original issue in #28446 was specifically a compilation error:

error: assignment to 'int (**)(NpyIter *)' from incompatible pointer type 'int (*)(NpyIter *)'

Would it be acceptable to consider the fix verified through:

  1. NumPy successfully compiling with spin build
  2. The original reporter confirming the fix resolves their compilation error

Alternatively, I'd appreciate guidance on the appropriate way to add test coverage for this specific Cython declaration change that avoids the build complications I've encountered.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, but what is this about? Copying an array here is wrong and also doesn't seem to be related at all to the issue you are trying to solve. Maybe the test needs to do a copy, I don't know, but certainly not here or like this.

Also, as mentioned on the issue, please make sure that the tests for this use the function that you fixed the signature for.

it was about the pypy test failure, ive reverted the changes

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you just run with spin test -t numpy/_core/tests/test_cython.py? Either way, it should work in CI.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4ecbb51

this is what i was trying to do

Copy link
Member

@seberg seberg Mar 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests only run if you have Cython >=3.0.6, just updating cython should do the trick to run the tests locally.

EDIT: There is also a:

if IS_EDITABLE:
    pytest.skip(
        "Editable install doesn't support tests with a compile step",
        allow_module_level=True
    )

but that shouldn't affect spin test -t ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've verified I have Cython 3.0.12 installed, which meets the >=3.0.6 requirement:

$ pip install --upgrade cython
Requirement already satisfied: cython in /Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages (3.0.12)

However, I'm still encountering meson compilation errors when trying to run the tests:

subprocess.CalledProcessError: Command '['meson', 'compile', '-vv']' returned non-zero exit status 1.

The tests are failing at the compilation step rather than being skipped by the IS_EDITABLE check. Should I proceed with adding the test case for NpyIter_GetIterNext anyway for CI to validate, or is there another approach you'd recommend?

Copy link
Member

@ngoldbaum ngoldbaum Mar 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably happening because there's a cython compiler error that is getting captured by pytest, causing meson to fail. You're not seeing the output from cython because pytest captures stdout by default. You can force pytest to dump stdout instead of capturing it by passing -s to pytest. With spin test it would look something like:

spin test numpy/_core/tests/test_cython.py -- -six

Extra arguments after the -- are passed to pytest.

I also tried my hand at writing a test, and it came out like this:

diff --git a/numpy/_core/tests/examples/cython/checks.pyx b/numpy/_core/tests/examples/cython/checks.pyx
index 6cdfd787c8..9a697c2653 100644
--- a/numpy/_core/tests/examples/cython/checks.pyx
+++ b/numpy/_core/tests/examples/cython/checks.pyx
@@ -242,6 +242,26 @@ def npyiter_has_multi_index(it: "nditer"):
     return result


+def test_multi_index(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)
+    if get_multi_index == NULL:
+        return False
+    cdef cnp.NpyIter_IterNextFunc* iter
+    next = \
+        cnp.NpyIter_GetIterNext(cit, NULL)
+    if iternext == NULL:
+        return False
+    cdef cnp.ndarray[cnp.float64_t, ndim=2] ret = cnp.PyArray_Copy(arr)
+    cdef cnp.npy_intp* multi_index = <cnp.npy_intp*>cnp.PyArray_DATA(ret)
+    cdef int ndim = cnp.PyArray_NDIM(arr)
+    while iternext[0](cit):
+        get_multi_index[0](cit, multi_index)
+        multi_index += ndim
+    return ret
+
+
 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 53c3d92f8a..25661cca0b 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_multi_index(it, arr)

     arr2 = np.random.rand(2, 1, 2)
     it = np.nditer([arr, arr2])

Cython is happy to compile this, but the C compiler complains that the types returned by GetGetMultiIndex and GetIterNext are incorrect:

checks.cpython-313-darwin.so.p/checks.pyx.c:11766:13: warning: incompatible pointer types assigning to '__pyx_t_5numpy_NpyIter_GetMultiIndexFunc *' (aka 'void (**)(struct NpyIter_InternalOnly *, long *)') from 'NpyIter_GetMultiIndexFunc *' (aka 'void (*)(struct NpyIter_InternalOnly *, long *)') [-Wincompatible-pointer-types]
 11766 |   __pyx_t_2 = NpyIter_GetGetMultiIndex(__pyx_v_cit, NULL); if (unlikely(__pyx_t_2 == ((__pyx_t_5numpy_NpyIter_GetMultiIndexFunc *)0))) __PYX_ERR(0, 248, __pyx_L1_error)
       |             ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
checks.cpython-313-darwin.so.p/checks.pyx.c:11807:13: warning: incompatible pointer types assigning to '__pyx_t_5numpy_NpyIter_IterNextFunc *' (aka 'int (**)(struct NpyIter_InternalOnly *)') from 'NpyIter_IterNextFunc *' (aka 'int (*)(struct NpyIter_InternalOnly *)') [-Wincompatible-pointer-types]
 11807 |   __pyx_t_4 = NpyIter_GetIterNext(__pyx_v_cit, NULL); if (unlikely(__pyx_t_4 == ((__pyx_t_5numpy_NpyIter_IterNextFunc *)0))) __PYX_ERR(0, 252, __pyx_L1_error)
       |             ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Which to me indicates that indeed we need to write the Cython wrappers for the function pointers to return functions, not pointers.

But then Cython refuses to compile that:

Error compiling Cython file:
------------------------------------------------------------
...

# 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.
ctypedef int (NpyIter_IterNextFunc)(NpyIter* it) noexcept nogil
             ^
------------------------------------------------------------

numpy/__init__.cython-30.pxd:1090:13: Function cannot return a function

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opened cython/cython#6720 to see if this is a Cython bug or if I'm misunderstanding something.

@ngoldbaum
Copy link
Member

I'm confused why the current definitions are wrong. The C function returns a NpyIter_IterNextFunc *:

/*NUMPY_API
* Compute the specialized iteration function for an iterator
*
* If errmsg is non-NULL, it should point to a variable which will
* receive the error message, and no Python exception will be set.
* This is so that the function can be called from code not holding
* the GIL.
*/
NPY_NO_EXPORT NpyIter_IterNextFunc *
NpyIter_GetIterNext(NpyIter *iter, char **errmsg)

@seberg
Copy link
Member

seberg commented Mar 10, 2025

Hmmm, maybe the problem is NpyIter_IterNextFunc being a function pointer rather than a function (although, I am not sure if cython might want that).

@ngoldbaum
Copy link
Member

Ah, you're right! It's the cython version of the function pointer typedef:

typedef int (NpyIter_IterNextFunc)(NpyIter *iter);

vs

ctypedef int (*NpyIter_IterNextFunc)(NpyIter* it) noexcept nogil

There shouldn't be a * before the name of the function pointer.

Man, yuck!

@ngoldbaum
Copy link
Member

ngoldbaum commented Mar 10, 2025

It's in a public header and it's been there a really long time, but I don't think it's idiomatic C for NumPy to define the function pointer like that in ndarraytypes.h. This PR's approach might be the only way to get Cython to parse it correctly and allow users to call GetIterNext. If Cython can't wrap the typdef as it's actually defined then I guess what's in this PR is fine. It probably deserves a comment in the cython headers explaining the discrepancy.

I also agree it would be nice to update the cython tests to use this function. Look in numpy/_core/tests/examples/cython/checks.pyx for the existing Cython tests, which it looks like cover many wrapped functions in the NpyIter API but not this function.

@seberg
Copy link
Member

seberg commented Mar 10, 2025

If Cython can't wrap the typdef as it's actually defined then

To be clear, I am not sure about this, Cython might be completely fine. If it isn't it may also be fine to just say the user should use Npy_IterNext func rather than NpyIter_Next *func in Cython (I am not 100% if it is, but I suspect so)

@seberg
Copy link
Member

seberg commented Mar 13, 2025

@ngoldbaum, do you have any squirms with just adding the * and removing it from the functions?

There are two approaches:

  1. Just remove it, nothing else. I am not 100% sure that it is good that these are not part of the extern C block, though. (I.e. might C++ care that the typedefs are identical, but not the same typedef?)
  2. I suspect cleaner but less obvious is to do the same but move it into the cdef extern block via:
    # NOTE: Unlike in C, the Cython exposed version is a function pointer
    # so that code should *not* include an additional `*`.
    ctypedef int (*NpyIter_IterNextFunc "NpyIter_IterNextFunc *")(NpyIter* it) noexcept nogil
    ctypedef void (*NpyIter_GetMultiIndexFunc "NpyIter_GetMultiIndexFunc *")(NpyIter* it, npy_intp* outcoords) noexcept nogil
    

Which works just fine. In either case, we can of course rename the definition (e.g. call it IterNextFuncPtr or make it clearer that it is cython by making it lower-case).

EDIT: Although, if we add a ...Ptr name or so, we might as well just do that in C also.

@ngoldbaum
Copy link
Member

@seberg hmm, I don't seem to be able to get that to work.

Am I doing something wrong?

I'm able to add the typedefs to the cdef extern block and get the Cython code to compile, but then the C code has compiler warnings like:

checks.cpython-313-darwin.so.p/checks.pyx.c:11710:13: warning: incompatible pointer types assigning to 'NpyIter_GetMultiIndexFunc **' (aka 'void (**)(struct NpyIter_InternalOnly *, long *)') from 'NpyIter_GetMultiIndexFunc *' (aka 'void (*)(struct NpyIter_InternalOnly *, long *)') [-Wincompatible-pointer-types]
 11710 |   __pyx_t_2 = NpyIter_GetGetMultiIndex(__pyx_v_cit, NULL); if (unlikely(__pyx_t_2 == ((NpyIter_GetMultiIndexFunc * *)0))) __PYX_ERR(0, 248, __pyx_L1_error)
       |             ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
checks.cpython-313-darwin.so.p/checks.pyx.c:11751:13: warning: incompatible pointer types assigning to 'NpyIter_IterNextFunc **' (aka 'int (**)(struct NpyIter_InternalOnly *)') from 'NpyIter_IterNextFunc *' (aka 'int (*)(struct NpyIter_InternalOnly *)') [-Wincompatible-pointer-types]
 11751 |   __pyx_t_4 = NpyIter_GetIterNext(__pyx_v_cit, NULL); if (unlikely(__pyx_t_4 == ((NpyIter_IterNextFunc * *)0))) __PYX_ERR(0, 252, __pyx_L1_error)
       |             ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

and then the test segfaults.

Here's the Cython test function I wrote:

def test_multi_index(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)
    if get_multi_index == NULL:
	return False
    cdef cnp.NpyIter_IterNextFunc* iternext = \
        cnp.NpyIter_GetIterNext(cit, NULL)
    if iternext == NULL:
	return False
    cdef cnp.ndarray[cnp.float64_t, ndim=2] ret = cnp.PyArray_Copy(arr)
    cdef cnp.npy_intp* multi_index = <cnp.npy_intp*>cnp.PyArray_DATA(ret)
    cdef int ndim = cnp.PyArray_NDIM(arr)
    while iternext[0](cit):
        get_multi_index[0](cit, multi_index)
        multi_index += ndim
    return ret

And here's the changes I made to numpy's cython header

diff --git a/numpy/__init__.cython-30.pxd b/numpy/__init__.cython-30.pxd
index bdadb28d26..b1b9ab9ff9 100644
--- a/numpy/__init__.cython-30.pxd
+++ b/numpy/__init__.cython-30.pxd
@@ -825,6 +825,14 @@
         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":

@@ -1083,10 +1091,6 @@
     return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>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:
@@ -1204,7 +1208,10 @@
                                         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

You can also pull from the fix-npyiter-return-type branch on my fork of NumPy.

@seberg
Copy link
Member

seberg commented Mar 14, 2025

The string hack was just to use the exact typedef from C (rather than defining something equivalent).
To be honest, I am not sure that whether there is a place where it might matter to have the exact typedef (rather than an equivalent one).

Since it seems we have to use a function pointer type in Cython, the return value must stay unchanged and be NpyIter_IterNextFunc(Ptr) and not NpyIter_IterNextFunc *.

Using a function pointer type seems not a big deal, TBH. I am just not sure if I prefer to add NpyIter_IterNextFuncPtr in C also, live with the subtly different definition in Cython, or add a new name for it but only in Cython?

@seberg
Copy link
Member

seberg commented Mar 14, 2025

To not be confusing, applying this works:

diff --git a/numpy/__init__.cython-30.pxd b/numpy/__init__.cython-30.pxd
index b1b9ab9ff9..c2bc50a63a 100644
--- a/numpy/__init__.cython-30.pxd
+++ b/numpy/__init__.cython-30.pxd
@@ -1211,8 +1211,8 @@
     #
     # 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,
+    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
     char** NpyIter_GetInitialDataPtrArray(NpyIter* it) nogil
diff --git a/numpy/_core/tests/examples/cython/checks.pyx b/numpy/_core/tests/examples/cython/checks.pyx
index 88fd8c63ff..4c70d52a6a 100644
--- a/numpy/_core/tests/examples/cython/checks.pyx
+++ b/numpy/_core/tests/examples/cython/checks.pyx
@@ -244,19 +244,18 @@ def npyiter_has_multi_index(it: "nditer"):
 
 def test_multi_index(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 = \
+    cdef cnp.NpyIter_GetMultiIndexFunc get_multi_index = \
         cnp.NpyIter_GetGetMultiIndex(cit, NULL)
     if get_multi_index == NULL:
         return False
-    cdef cnp.NpyIter_IterNextFunc* iternext = \
-        cnp.NpyIter_GetIterNext(cit, NULL)
+    cdef cnp.NpyIter_IterNextFunc iternext = cnp.NpyIter_GetIterNext(cit, NULL)
     if iternext == NULL:
         return False
     cdef cnp.ndarray[cnp.float64_t, ndim=2] ret = cnp.PyArray_Copy(arr)
     cdef cnp.npy_intp* multi_index = <cnp.npy_intp*>cnp.PyArray_DATA(ret)
     cdef int ndim = cnp.PyArray_NDIM(arr)
-    while iternext[0](cit):
-        get_multi_index[0](cit, multi_index)
+    while iternext(cit):
+        get_multi_index(cit, multi_index)
         multi_index += ndim
     return ret

(Except that the python side part of the test needs adjusting)

@ngoldbaum
Copy link
Member

(Except that the python side part of the test needs adjusting)

Thank you!

I'll take a look at that.

@baskargopinath do you mind if I push to your PR?

@ngoldbaum
Copy link
Member

@baskargopinath you can also pull from my fork and push to your fork: https://github.com/ngoldbaum/numpy/tree/fix-npyiter-return-type

@ngoldbaum
Copy link
Member

Using a function pointer type seems not a big deal, TBH. I am just not sure if I prefer to add NpyIter_IterNextFuncPtr in C also, live with the subtly different definition in Cython, or add a new name for it but only in Cython?

This subtle difference is fine IMO. Almost no one will ever need to care about this and it’s not worth the ceremony of changing the C API.

@baskargopinath
Copy link
Contributor Author

(Except that the python side part of the test needs adjusting)

Thank you!

I'll take a look at that.

@baskargopinath do you mind if I push to your PR?

Sure go ahead!

@ngoldbaum ngoldbaum force-pushed the fix-npyiter-return-type branch from c5d5847 to c963ae6 Compare March 15, 2025 00:30
Copy link
Member

@seberg seberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for updating! It now is really just a small bug fix now.

I am also OK with the mismatch, wonder if we should mentioned it in the docs, but I am OK either way.

I.e. feel free to merge @ngoldbaum and thanks @baskargopinath.

@ngoldbaum ngoldbaum merged commit 9b2f886 into numpy:main Mar 15, 2025
73 checks passed
@github-project-automation github-project-automation bot moved this from Awaiting a code review to Completed in NumPy first-time contributor PRs Mar 15, 2025
@charris charris changed the title BUG: Correct return type of NpyIter_GetIterNext in Cython declaration… BUG: Fix return type of NpyIter_GetIterNext in Cython declarations Mar 15, 2025
@zoj613
Copy link
Contributor

zoj613 commented Mar 16, 2025

@charris is there any reason why this PR didn't make it into v2.2.4 ?

@charris
Copy link
Member

charris commented Mar 16, 2025

any reason why this PR didn't make it into v2.2.4 ?

It wasn't marked for backport.

@seberg
Copy link
Member

seberg commented Mar 17, 2025

Sorry, I forgot to mark it.

@charris charris added the 09 - Backport-Candidate PRs tagged should be backported label Mar 17, 2025
@charris charris removed the 09 - Backport-Candidate PRs tagged should be backported label Mar 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Development

Successfully merging this pull request may close these issues.

BUG: Unable to build cython when using NpyIter_GetIterNext.
5 participants