Skip to content

Commit 64a832f

Browse files
FrancescAltedclaude
andcommitted
Self-contained NpyString declarations in utf8_ext.pyx for older numpy pxds
The NpyString C API has been in the NumPy headers since 2.0, but its Cython declarations only appear in the numpy/__init__.pxd of newer NumPy versions. The Pyodide cross-build pins an older NumPy (2.1's pxd has none of them), so cythonizing utf8_ext.pyx failed on wasm32 with "'npy_string_allocator' is not a type identifier". Declare the four symbols locally instead of via `cimport numpy`; they resolve through the API table populated by cnp.import_array(), so no behavior changes. Verified by reproducing the failure with numpy 2.1.3 + Cython 3.2.8, then cythonizing, compiling, and running the kernel in that same env. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 1feab86 commit 64a832f

1 file changed

Lines changed: 31 additions & 5 deletions

File tree

src/blosc2/utf8_ext.pyx

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,32 @@ from libc.stdint cimport int64_t, uint8_t
2424
cnp.import_array()
2525

2626

27+
# Declared here instead of relying on `cimport numpy`: the NpyString C API
28+
# has been part of the NumPy headers since 2.0, but its Cython declarations
29+
# only appear in the numpy/__init__.pxd of newer NumPy versions, and some
30+
# build environments (e.g. the Pyodide cross-build) pin an older one. The
31+
# functions resolve through the API table populated by cnp.import_array().
32+
cdef extern from "numpy/ndarraytypes.h":
33+
ctypedef struct npy_string_allocator:
34+
pass
35+
ctypedef struct npy_packed_static_string:
36+
pass
37+
ctypedef struct PyArray_StringDTypeObject:
38+
pass
39+
40+
cdef extern from "numpy/arrayobject.h":
41+
npy_string_allocator* NpyString_acquire_allocator(
42+
const PyArray_StringDTypeObject* descr
43+
) nogil
44+
void NpyString_release_allocator(npy_string_allocator* allocator) nogil
45+
int NpyString_pack(
46+
npy_string_allocator* allocator,
47+
npy_packed_static_string* packed_string,
48+
const char* buf,
49+
size_t size,
50+
) nogil
51+
52+
2753
def pack_utf8_span(cnp.ndarray rel not None, cnp.ndarray data not None, cnp.ndarray out not None):
2854
"""Fill *out* in place with rows carved out of *data* using *rel*.
2955
@@ -51,8 +77,8 @@ def pack_utf8_span(cnp.ndarray rel not None, cnp.ndarray data not None, cnp.ndar
5177
cdef const uint8_t* data_ptr = <const uint8_t*>cnp.PyArray_DATA(data)
5278
cdef char* out_data = <char*>cnp.PyArray_DATA(out)
5379
cdef cnp.npy_intp itemsize = cnp.PyArray_ITEMSIZE(out)
54-
cdef cnp.npy_string_allocator* allocator = cnp.NpyString_acquire_allocator(
55-
<cnp.PyArray_StringDTypeObject*>cnp.PyArray_DESCR(out)
80+
cdef npy_string_allocator* allocator = NpyString_acquire_allocator(
81+
<const PyArray_StringDTypeObject*>cnp.PyArray_DESCR(out)
5682
)
5783
if allocator == NULL:
5884
raise TypeError("out must be a StringDType array")
@@ -64,16 +90,16 @@ def pack_utf8_span(cnp.ndarray rel not None, cnp.ndarray data not None, cnp.ndar
6490
for i in range(n):
6591
start = rel_ptr[i]
6692
length = rel_ptr[i + 1] - start
67-
ret = cnp.NpyString_pack(
93+
ret = NpyString_pack(
6894
allocator,
69-
<cnp.npy_packed_static_string*>(out_data + i * itemsize),
95+
<npy_packed_static_string*>(out_data + i * itemsize),
7096
<const char*>(data_ptr + start),
7197
<size_t>length,
7298
)
7399
if ret == -1:
74100
break
75101
finally:
76-
cnp.NpyString_release_allocator(allocator)
102+
NpyString_release_allocator(allocator)
77103

78104
if ret == -1:
79105
raise MemoryError("Failed to pack a UTF-8 row into the StringDType array")

0 commit comments

Comments
 (0)