29
29
#include < utility>
30
30
#include < vector>
31
31
32
+ #if defined(PYBIND11_NUMPY_1_ONLY) && !defined(PYBIND11_INTERNAL_NUMPY_1_ONLY_DETECTED)
33
+ # error PYBIND11_NUMPY_1_ONLY must be defined before any pybind11 header is included.
34
+ #endif
35
+
32
36
/* This will be true on all flat address space platforms and allows us to reduce the
33
37
whole npy_intp / ssize_t / Py_intptr_t business down to just ssize_t for all size
34
38
and dimension types (e.g. shape, strides, indexing), instead of inflicting this
35
- upon the library user. */
39
+ upon the library user.
40
+ Note that NumPy 2 now uses ssize_t for `npy_intp` to simplify this. */
36
41
static_assert (sizeof (::pybind11::ssize_t ) == sizeof(Py_intptr_t), "ssize_t != Py_intptr_t");
37
42
static_assert (std::is_signed<Py_intptr_t>::value, " Py_intptr_t must be signed" );
38
43
// We now can reinterpret_cast between py::ssize_t and Py_intptr_t (MSVC + PyPy cares)
@@ -53,7 +58,8 @@ struct handle_type_name<array> {
53
58
template <typename type, typename SFINAE = void >
54
59
struct npy_format_descriptor ;
55
60
56
- struct PyArrayDescr_Proxy {
61
+ /* NumPy 1 proxy (always includes legacy fields) */
62
+ struct PyArrayDescr1_Proxy {
57
63
PyObject_HEAD
58
64
PyObject *typeobj;
59
65
char kind;
@@ -68,6 +74,43 @@ struct PyArrayDescr_Proxy {
68
74
PyObject *names;
69
75
};
70
76
77
+ #ifndef PYBIND11_NUMPY_1_ONLY
78
+ struct PyArrayDescr_Proxy {
79
+ PyObject_HEAD
80
+ PyObject *typeobj;
81
+ char kind;
82
+ char type;
83
+ char byteorder;
84
+ char _former_flags;
85
+ int type_num;
86
+ /* Additional fields are NumPy version specific. */
87
+ };
88
+ #else
89
+ /* NumPy 1.x only, we can expose all fields */
90
+ using PyArrayDescr_Proxy = PyArrayDescr1_Proxy;
91
+ #endif
92
+
93
+ /* NumPy 2 proxy, including legacy fields */
94
+ struct PyArrayDescr2_Proxy {
95
+ PyObject_HEAD
96
+ PyObject *typeobj;
97
+ char kind;
98
+ char type;
99
+ char byteorder;
100
+ char _former_flags;
101
+ int type_num;
102
+ std::uint64_t flags;
103
+ ssize_t elsize;
104
+ ssize_t alignment;
105
+ PyObject *metadata;
106
+ Py_hash_t hash;
107
+ void *reserved_null[2 ];
108
+ /* The following fields only exist if 0 <= type_num < 2056 */
109
+ char *subarray;
110
+ PyObject *fields;
111
+ PyObject *names;
112
+ };
113
+
71
114
struct PyArray_Proxy {
72
115
PyObject_HEAD
73
116
char *data;
@@ -131,6 +174,14 @@ PYBIND11_NOINLINE module_ import_numpy_core_submodule(const char *submodule_name
131
174
object numpy_version = numpy_lib.attr (" NumpyVersion" )(version_string);
132
175
int major_version = numpy_version.attr (" major" ).cast <int >();
133
176
177
+ #ifdef PYBIND11_NUMPY_1_ONLY
178
+ if (major_version >= 2 ) {
179
+ throw std::runtime_error (
180
+ " This extension was built with PYBIND11_NUMPY_1_ONLY defined, "
181
+ " but NumPy 2 is used in this process. For NumPy2 compatibility, "
182
+ " this extension needs to be rebuilt without the PYBIND11_NUMPY_1_ONLY define." );
183
+ }
184
+ #endif
134
185
/* `numpy.core` was renamed to `numpy._core` in NumPy 2.0 as it officially
135
186
became a private module. */
136
187
std::string numpy_core_path = major_version >= 2 ? " numpy._core" : " numpy.core" ;
@@ -203,6 +254,8 @@ struct npy_api {
203
254
NPY_ULONG_, NPY_ULONGLONG_, NPY_UINT_),
204
255
};
205
256
257
+ unsigned int PyArray_RUNTIME_VERSION_;
258
+
206
259
struct PyArray_Dims {
207
260
Py_intptr_t *ptr;
208
261
int len;
@@ -241,6 +294,7 @@ struct npy_api {
241
294
PyObject *(*PyArray_FromAny_)(PyObject *, PyObject *, int , int , int , PyObject *);
242
295
int (*PyArray_DescrConverter_)(PyObject *, PyObject **);
243
296
bool (*PyArray_EquivTypes_)(PyObject *, PyObject *);
297
+ #ifdef PYBIND11_NUMPY_1_ONLY
244
298
int (*PyArray_GetArrayParamsFromObject_)(PyObject *,
245
299
PyObject *,
246
300
unsigned char ,
@@ -249,6 +303,7 @@ struct npy_api {
249
303
Py_intptr_t *,
250
304
PyObject **,
251
305
PyObject *);
306
+ #endif
252
307
PyObject *(*PyArray_Squeeze_)(PyObject *);
253
308
// Unused. Not removed because that affects ABI of the class.
254
309
int (*PyArray_SetBaseObject_)(PyObject *, PyObject *);
@@ -266,7 +321,8 @@ struct npy_api {
266
321
API_PyArray_DescrFromScalar = 57 ,
267
322
API_PyArray_FromAny = 69 ,
268
323
API_PyArray_Resize = 80 ,
269
- API_PyArray_CopyInto = 82 ,
324
+ // CopyInto was slot 82 and 50 was effectively an alias. NumPy 2 removed 82.
325
+ API_PyArray_CopyInto = 50 ,
270
326
API_PyArray_NewCopy = 85 ,
271
327
API_PyArray_NewFromDescr = 94 ,
272
328
API_PyArray_DescrNewFromType = 96 ,
@@ -275,7 +331,9 @@ struct npy_api {
275
331
API_PyArray_View = 137 ,
276
332
API_PyArray_DescrConverter = 174 ,
277
333
API_PyArray_EquivTypes = 182 ,
334
+ #ifdef PYBIND11_NUMPY_1_ONLY
278
335
API_PyArray_GetArrayParamsFromObject = 278 ,
336
+ #endif
279
337
API_PyArray_SetBaseObject = 282
280
338
};
281
339
@@ -290,7 +348,8 @@ struct npy_api {
290
348
npy_api api;
291
349
#define DECL_NPY_API (Func ) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
292
350
DECL_NPY_API (PyArray_GetNDArrayCFeatureVersion);
293
- if (api.PyArray_GetNDArrayCFeatureVersion_ () < 0x7 ) {
351
+ api.PyArray_RUNTIME_VERSION_ = api.PyArray_GetNDArrayCFeatureVersion_ ();
352
+ if (api.PyArray_RUNTIME_VERSION_ < 0x7 ) {
294
353
pybind11_fail (" pybind11 numpy support requires numpy >= 1.7.0" );
295
354
}
296
355
DECL_NPY_API (PyArray_Type);
@@ -309,7 +368,9 @@ struct npy_api {
309
368
DECL_NPY_API (PyArray_View);
310
369
DECL_NPY_API (PyArray_DescrConverter);
311
370
DECL_NPY_API (PyArray_EquivTypes);
371
+ #ifdef PYBIND11_NUMPY_1_ONLY
312
372
DECL_NPY_API (PyArray_GetArrayParamsFromObject);
373
+ #endif
313
374
DECL_NPY_API (PyArray_SetBaseObject);
314
375
315
376
#undef DECL_NPY_API
@@ -331,6 +392,14 @@ inline const PyArrayDescr_Proxy *array_descriptor_proxy(const PyObject *ptr) {
331
392
return reinterpret_cast <const PyArrayDescr_Proxy *>(ptr);
332
393
}
333
394
395
+ inline const PyArrayDescr1_Proxy *array_descriptor1_proxy (const PyObject *ptr) {
396
+ return reinterpret_cast <const PyArrayDescr1_Proxy *>(ptr);
397
+ }
398
+
399
+ inline const PyArrayDescr2_Proxy *array_descriptor2_proxy (const PyObject *ptr) {
400
+ return reinterpret_cast <const PyArrayDescr2_Proxy *>(ptr);
401
+ }
402
+
334
403
inline bool check_flags (const void *ptr, int flag) {
335
404
return (flag == (array_proxy (ptr)->flags & flag));
336
405
}
@@ -610,10 +679,32 @@ class dtype : public object {
610
679
}
611
680
612
681
// / Size of the data type in bytes.
682
+ #ifdef PYBIND11_NUMPY_1_ONLY
613
683
ssize_t itemsize () const { return detail::array_descriptor_proxy (m_ptr)->elsize ; }
684
+ #else
685
+ ssize_t itemsize () const {
686
+ if (detail::npy_api::get ().PyArray_RUNTIME_VERSION_ < 0x12 ) {
687
+ return detail::array_descriptor1_proxy (m_ptr)->elsize ;
688
+ }
689
+ return detail::array_descriptor2_proxy (m_ptr)->elsize ;
690
+ }
691
+ #endif
614
692
615
693
// / Returns true for structured data types.
694
+ #ifdef PYBIND11_NUMPY_1_ONLY
616
695
bool has_fields () const { return detail::array_descriptor_proxy (m_ptr)->names != nullptr ; }
696
+ #else
697
+ bool has_fields () const {
698
+ if (detail::npy_api::get ().PyArray_RUNTIME_VERSION_ < 0x12 ) {
699
+ return detail::array_descriptor1_proxy (m_ptr)->names != nullptr ;
700
+ }
701
+ const auto *proxy = detail::array_descriptor2_proxy (m_ptr);
702
+ if (proxy->type_num < 0 || proxy->type_num >= 2056 ) {
703
+ return false ;
704
+ }
705
+ return proxy->names != nullptr ;
706
+ }
707
+ #endif
617
708
618
709
// / Single-character code for dtype's kind.
619
710
// / For example, floating point types are 'f' and integral types are 'i'.
@@ -639,11 +730,29 @@ class dtype : public object {
639
730
// / Single character for byteorder
640
731
char byteorder () const { return detail::array_descriptor_proxy (m_ptr)->byteorder ; }
641
732
642
- // / Alignment of the data type
733
+ // / Alignment of the data type
734
+ #ifdef PYBIND11_NUMPY_1_ONLY
643
735
int alignment () const { return detail::array_descriptor_proxy (m_ptr)->alignment ; }
736
+ #else
737
+ ssize_t alignment () const {
738
+ if (detail::npy_api::get ().PyArray_RUNTIME_VERSION_ < 0x12 ) {
739
+ return detail::array_descriptor1_proxy (m_ptr)->alignment ;
740
+ }
741
+ return detail::array_descriptor2_proxy (m_ptr)->alignment ;
742
+ }
743
+ #endif
644
744
645
- // / Flags for the array descriptor
745
+ // / Flags for the array descriptor
746
+ #ifdef PYBIND11_NUMPY_1_ONLY
646
747
char flags () const { return detail::array_descriptor_proxy (m_ptr)->flags ; }
748
+ #else
749
+ std::uint64_t flags () const {
750
+ if (detail::npy_api::get ().PyArray_RUNTIME_VERSION_ < 0x12 ) {
751
+ return (unsigned char ) detail::array_descriptor1_proxy (m_ptr)->flags ;
752
+ }
753
+ return detail::array_descriptor2_proxy (m_ptr)->flags ;
754
+ }
755
+ #endif
647
756
648
757
private:
649
758
static object &_dtype_from_pep3118 () {
@@ -810,9 +919,7 @@ class array : public buffer {
810
919
}
811
920
812
921
// / Byte size of a single element
813
- ssize_t itemsize () const {
814
- return detail::array_descriptor_proxy (detail::array_proxy (m_ptr)->descr )->elsize ;
815
- }
922
+ ssize_t itemsize () const { return dtype ().itemsize (); }
816
923
817
924
// / Total number of bytes
818
925
ssize_t nbytes () const { return size () * itemsize (); }
0 commit comments