From 8a9f0e76558db5d4a3a6a40971918b8031139dc3 Mon Sep 17 00:00:00 2001 From: Alexis Duburcq Date: Fri, 15 Mar 2024 19:58:26 +0100 Subject: [PATCH] Add support of numpy 2.0.0b1 --- CHANGELOG.md | 1 + include/eigenpy/numpy-allocator.hpp | 8 ++++++++ include/eigenpy/numpy.hpp | 9 ++++++++- include/eigenpy/user-type.hpp | 4 ++-- src/numpy.cpp | 24 +++++++++++++++++++++++- src/register.cpp | 8 ++++---- 6 files changed, 46 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8edbc9dba..18791046b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added - Allow use of installed JRL-cmakemodule ([#446](https://github.com/stack-of-tasks/eigenpy/pull/446) +- Support of Numpy 2.0.0b1 ([#448](https://github.com/stack-of-tasks/eigenpy/pull/448)) ### Fixed - Fix unit test build in C++11 ([#442](https://github.com/stack-of-tasks/eigenpy/pull/442)) diff --git a/include/eigenpy/numpy-allocator.hpp b/include/eigenpy/numpy-allocator.hpp index 61653940a..c2c1ba798 100644 --- a/include/eigenpy/numpy-allocator.hpp +++ b/include/eigenpy/numpy-allocator.hpp @@ -138,7 +138,11 @@ struct numpy_allocator_impl_matrix > { outer_stride = reverse_strides ? mat.innerStride() : mat.outerStride(); +#if NPY_ABI_VERSION < 0x02000000 const int elsize = call_PyArray_DescrFromType(Scalar_type_code)->elsize; +#else + const int elsize = PyDataType_ELSIZE(call_PyArray_DescrFromType(Scalar_type_code)); +#endif npy_intp strides[2] = {elsize * inner_stride, elsize * outer_stride}; PyArrayObject *pyArray = (PyArrayObject *)call_PyArray_New( @@ -204,7 +208,11 @@ struct numpy_allocator_impl_matrix< outer_stride = reverse_strides ? mat.innerStride() : mat.outerStride(); +#if NPY_ABI_VERSION < 0x02000000 const int elsize = call_PyArray_DescrFromType(Scalar_type_code)->elsize; +#else + const int elsize = PyDataType_ELSIZE(call_PyArray_DescrFromType(Scalar_type_code)); +#endif npy_intp strides[2] = {elsize * inner_stride, elsize * outer_stride}; PyArrayObject *pyArray = (PyArrayObject *)call_PyArray_New( diff --git a/include/eigenpy/numpy.hpp b/include/eigenpy/numpy.hpp index 6ab627d8b..d58533a90 100644 --- a/include/eigenpy/numpy.hpp +++ b/include/eigenpy/numpy.hpp @@ -16,6 +16,13 @@ #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #endif +/* Allow compiling against NumPy 1.x and 2.x + see: https://github.com/numpy/numpy/blob/afea8fd66f6bdbde855f5aff0b4e73eb0213c646/doc/source/reference/c-api/array.rst#L1224 +*/ +#if NPY_ABI_VERSION < 0x02000000 +#define PyArray_DescrProto PyArray_Descr +#endif + #include #include @@ -170,7 +177,7 @@ inline void call_PyArray_InitArrFuncs(PyArray_ArrFuncs* funcs) { PyArray_InitArrFuncs(funcs); } -inline int call_PyArray_RegisterDataType(PyArray_Descr* dtype) { +inline int call_PyArray_RegisterDataType(PyArray_DescrProto* dtype) { return PyArray_RegisterDataType(dtype); } diff --git a/include/eigenpy/user-type.hpp b/include/eigenpy/user-type.hpp index e66b2d9f5..b7eb67be6 100644 --- a/include/eigenpy/user-type.hpp +++ b/include/eigenpy/user-type.hpp @@ -171,7 +171,7 @@ struct SpecialMethods { char* srcptr = static_cast(src); PyArrayObject* py_array = static_cast(array); - PyArray_CopySwapFunc* copyswap = PyArray_DESCR(py_array)->f->copyswap; + PyArray_CopySwapFunc* copyswap = PyDataType_GetArrFuncs(PyArray_DESCR(py_array))->copyswap; for (npy_intp i = 0; i < n; i++) { copyswap(dstptr, srcptr, swap, array); @@ -189,7 +189,7 @@ struct SpecialMethods { return (npy_bool)(value != ZeroValue); } else { T tmp_value; - PyArray_DESCR(py_array)->f->copyswap( + PyDataType_GetArrFuncs(PyArray_DESCR(py_array))->copyswap( &tmp_value, ip, PyArray_ISBYTESWAPPED(py_array), array); return (npy_bool)(tmp_value != ZeroValue); } diff --git a/src/numpy.cpp b/src/numpy.cpp index 01018ba89..fc4d37394 100644 --- a/src/numpy.cpp +++ b/src/numpy.cpp @@ -14,8 +14,30 @@ void import_numpy() { } int PyArray_TypeNum(PyTypeObject* type) { - return PyArray_TypeNumFromName(const_cast(type->tp_name)); + PyArray_Descr * descr = PyArray_DescrFromTypeObject(reinterpret_cast(type)); + if (descr == NULL) { + return NPY_NOTYPE; + } + return descr->type_num; +} + +/* PEP 674 disallow using macros as l-values + see : https://peps.python.org/pep-0674/ +*/ +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE) +static inline void _Py_SET_TYPE(PyObject *o, PyTypeObject *type) { + Py_TYPE(o) = type; } +#define Py_SET_TYPE(o, type) _Py_SET_TYPE((PyObject*)(o), type) +#endif + +#if NPY_ABI_VERSION < 0x02000000 + static inline PyArray_ArrFuncs * + PyDataType_GetArrFuncs(PyArray_Descr *descr) + { + return descr->f; + } +#endif #if defined _WIN32 || defined __CYGWIN__ diff --git a/src/register.cpp b/src/register.cpp index 84e84f645..1a8ce771c 100644 --- a/src/register.cpp +++ b/src/register.cpp @@ -63,9 +63,9 @@ int Register::registerNewType( throw std::invalid_argument("PyType_Ready fails to initialize input type."); } - PyArray_Descr* descr_ptr = - new PyArray_Descr(*call_PyArray_DescrFromType(NPY_OBJECT)); - PyArray_Descr& descr = *descr_ptr; + PyArray_DescrProto* descr_ptr = new PyArray_DescrProto(); + Py_SET_TYPE(descr_ptr, &PyArrayDescr_Type); + PyArray_DescrProto& descr = *descr_ptr; descr.typeobj = py_type_ptr; descr.kind = 'V'; descr.byteorder = '='; @@ -98,7 +98,7 @@ int Register::registerNewType( PyArray_Descr* new_descr = call_PyArray_DescrFromType(code); if (PyDict_SetItemString(py_type_ptr->tp_dict, "dtype", - (PyObject*)descr_ptr) < 0) { + (PyObject*)new_descr) < 0) { throw std::invalid_argument("PyDict_SetItemString fails."); }