Skip to content

Commit aa273c8

Browse files
photonikerItom Build Server
authored andcommitted
Merge pull request #305 from itom-project/Numpy_2_adaptations
Numpy 2 adaptations
2 parents 357ef85 + da04978 commit aa273c8

File tree

3 files changed

+182
-146
lines changed

3 files changed

+182
-146
lines changed

Qitom/python/pythonDataObject.cpp

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#include "pythonEngineInc.h"
2525

2626
#include "numpy/arrayscalars.h"
27-
27+
#include "numpy/ndarrayobject.h"
2828
#include "structmember.h"
2929

3030
#include "../global.h"
@@ -46,6 +46,7 @@
4646

4747
#define PROTOCOL_STR_LENGTH 128
4848

49+
4950
namespace ito {
5051
template<class T>
5152
std::unique_ptr<T> make_unique(std::size_t size)
@@ -1172,7 +1173,13 @@ bool PythonDataObject::PyDataObj_CopyFromDatetimeNpNdArray(
11721173

11731174
// in case of datetime or timedelta: The values are int64, based on 1.1.1970
11741175
// the timebase is given by:
1176+
// Assuming NumPy 1.7+ has the new behavior for descr metadata
1177+
#ifdef NPY_2_0_API_VERSION
1178+
const auto md = (PyArray_DatetimeDTypeMetaData*)(descr);
1179+
#else
11751180
const auto md = (PyArray_DatetimeDTypeMetaData*)(descr->c_metadata);
1181+
#endif
1182+
11761183
// timezone is ignored in numpy. If dataObject contains a timezone, ignore it and raise a
11771184
// warning.
11781185

@@ -1302,7 +1309,11 @@ bool PythonDataObject::PyDataObj_CopyFromTimedeltaNpNdArray(
13021309

13031310
// in case of datetime or timedelta: The values are int64, based on 1.1.1970
13041311
// the timebase is given by:
1312+
#ifdef NPY_2_0_API_VERSION
1313+
const auto md = (PyArray_DatetimeDTypeMetaData*)(descr);
1314+
#else
13051315
const auto md = (PyArray_DatetimeDTypeMetaData*)(descr->c_metadata);
1316+
#endif
13061317

13071318
if (md == nullptr)
13081319
{
@@ -2522,7 +2533,6 @@ PyObject* PythonDataObject::PyDataObject_getValue(PyDataObject* self, void* /*cl
25222533
return -1;
25232534
}
25242535

2525-
// try to convert value to a numpy-array
25262536
#if !defined(NPY_NO_DEPRECATED_API) || (NPY_NO_DEPRECATED_API < NPY_1_7_API_VERSION)
25272537
PyObject* arr = PyArray_FromObject(value, typenum, 1, 1); // new ref
25282538
#else
@@ -8550,7 +8560,11 @@ RetVal PythonDataObject::parseTypeNumber(int typeno, char& typekind, int& itemsi
85508560
// todo: maybe kind and size can be hard coded
85518561
PyArray_Descr* descr = PyArray_DescrNewFromType(NPY_DATETIME);
85528562
typekind = descr->kind; // NPY_DATETIMELTR
8563+
#ifdef NPY_2_0_API_VERSION
8564+
itemsize = PyDataType_ELSIZE(descr);
8565+
#else
85538566
itemsize = descr->elsize; // 8
8567+
#endif
85548568
Py_DECREF(descr);
85558569

85568570
// PyDatetimeScalarObject
@@ -8560,7 +8574,11 @@ RetVal PythonDataObject::parseTypeNumber(int typeno, char& typekind, int& itemsi
85608574
// todo: maybe kind and size can be hard coded
85618575
PyArray_Descr* descr = PyArray_DescrNewFromType(NPY_TIMEDELTA);
85628576
typekind = descr->kind; // NPY_TIMEDELTALTR
8577+
#ifdef NPY_2_0_API_VERSION
8578+
itemsize = PyDataType_ELSIZE(descr);
8579+
#else
85638580
itemsize = descr->elsize; // 8
8581+
#endif
85648582
Py_DECREF(descr);
85658583
break;
85668584
}
@@ -8734,7 +8752,11 @@ std::string PythonDataObject::getNpDTypeStringFromNpDTypeEnum(const int type)
87348752
case NPY_HALF:
87358753
typeStr = "half";
87368754
break;
8755+
#ifdef NPY_2_0_API_VERSION
8756+
case NPY_NTYPES_LEGACY:
8757+
#else
87378758
case NPY_NTYPES:
8759+
#endif
87388760
typeStr = "ntypes";
87398761
break;
87408762
case NPY_NOTYPE:
@@ -8962,7 +8984,11 @@ ito::RetVal PythonDataObject::copyNpArrayValuesToDataObject(
89628984
ito::DateTime* rowPtr;
89638985
PyArray_Descr* dtype = PyArray_DESCR(npNdArray);
89648986

8987+
#ifdef NPY_2_0_API_VERSION
8988+
const auto md = (PyArray_DatetimeDTypeMetaData*)(dtype);
8989+
#else
89658990
const auto md = (PyArray_DatetimeDTypeMetaData*)(dtype->c_metadata);
8991+
#endif
89668992
// timezone is ignored in numpy. If dataObject contains a timezone, ignore it and raise a
89678993
// warning.
89688994

@@ -8992,7 +9018,11 @@ ito::RetVal PythonDataObject::copyNpArrayValuesToDataObject(
89929018
ito::TimeDelta* rowPtr;
89939019
PyArray_Descr* dtype = PyArray_DESCR(npNdArray);
89949020

9021+
#ifdef NPY_2_0_API_VERSION
9022+
const auto md = (PyArray_DatetimeDTypeMetaData*)(dtype);
9023+
#else
89959024
const auto md = (PyArray_DatetimeDTypeMetaData*)(dtype->c_metadata);
9025+
#endif
89969026
// timezone is ignored in numpy. If dataObject contains a timezone, ignore it and raise a
89979027
// warning.
89989028

@@ -9534,7 +9564,11 @@ PyArrayObject* nparrayFromTimeDeltaDataObject(
95349564
{
95359565
// step 1: create numpy array
95369566
PyArray_Descr* descr = PyArray_DescrNewFromType(NPY_TIMEDELTA);
9567+
#ifdef NPY_2_0_API_VERSION
9568+
auto metaData = (PyArray_DatetimeDTypeMetaData*)(descr);
9569+
#else
95379570
auto metaData = (PyArray_DatetimeDTypeMetaData*)(descr->c_metadata);
9571+
#endif
95389572

95399573
if (meta != nullptr)
95409574
{
@@ -9655,7 +9689,11 @@ PyArrayObject* nparrayFromDateTimeDataObject(
96559689
{
96569690
// step 1: create numpy array
96579691
PyArray_Descr* descr = PyArray_DescrNewFromType(NPY_DATETIME);
9692+
#ifdef NPY_2_0_API_VERSION
9693+
auto metaData = (PyArray_DatetimeDTypeMetaData*)(descr);
9694+
#else
96589695
auto metaData = (PyArray_DatetimeDTypeMetaData*)(descr->c_metadata);
9696+
#endif
96599697

96609698
if (meta != nullptr)
96619699
{
@@ -9819,7 +9857,11 @@ PyObject* PythonDataObject::PyDataObj_Array_(PyDataObject* self, PyObject* args)
98199857

98209858
if (newtype && PyDataType_ISDATETIME(newtype))
98219859
{
9860+
#ifdef NPY_2_0_API_VERSION
9861+
meta = &(((PyArray_DatetimeDTypeMetaData*)newtype)->meta);
9862+
#else
98229863
meta = &(((PyArray_DatetimeDTypeMetaData*)newtype->c_metadata)->meta);
9864+
#endif
98239865
}
98249866

98259867
newArray = nparrayFromDateTimeDataObject(selfDO, meta);
@@ -9830,7 +9872,11 @@ PyObject* PythonDataObject::PyDataObj_Array_(PyDataObject* self, PyObject* args)
98309872

98319873
if (newtype && PyDataType_ISDATETIME(newtype))
98329874
{
9875+
#if (NPY_2_0_API_VERSION)
9876+
meta = &(((PyArray_DatetimeDTypeMetaData*)newtype)->meta);
9877+
#else
98339878
meta = &(((PyArray_DatetimeDTypeMetaData*)newtype->c_metadata)->meta);
9879+
#endif
98349880
}
98359881

98369882
newArray = nparrayFromTimeDeltaDataObject(selfDO, meta);

Qitom/python/pythonItom.cpp

Lines changed: 62 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545
#include "../organizer/uiOrganizer.h"
4646
#include "../organizer/userOrganizer.h"
4747

48+
#include "numpy/ndarrayobject.h" // Ensure to include the necessary NumPy header
49+
4850
#include <qcoreapplication.h>
4951

5052
#include <qdir.h>
@@ -4781,9 +4783,7 @@ PyObject* PythonItom::PyLoadMatlabMat(PyObject* /*pSelf*/, PyObject* pArgs)
47814783
}
47824784

47834785
// Arguments must be: filename -> string
4784-
47854786
PyObject* filename = NULL; // borrowed reference
4786-
47874787
if (!PyArg_ParseTuple(pArgs, "U", &filename))
47884788
{
47894789
Py_XDECREF(scipyIoModule);
@@ -4792,21 +4792,23 @@ PyObject* PythonItom::PyLoadMatlabMat(PyObject* /*pSelf*/, PyObject* pArgs)
47924792

47934793
PyObject* kwdDict = PyDict_New();
47944794
PyObject* argTuple = PyTuple_New(1);
4795-
// PyTuple_SetItem(argTuple, 0, PyUnicode_FromString(filename));
47964795
Py_INCREF(filename);
47974796
PyTuple_SetItem(argTuple, 0, filename); // steals a reference
47984797
PyDict_SetItemString(kwdDict, "squeeze_me", Py_True);
4798+
4799+
// Get callable loadmat function
47994800
PyObject* loadmatobj = PyUnicode_FromString("loadmat");
48004801
PyObject* callable = PyObject_GetAttr(scipyIoModule, loadmatobj);
48014802
Py_DECREF(loadmatobj);
4803+
4804+
// Call loadmat
48024805
resultLoadMat = PyObject_Call(callable, argTuple, kwdDict);
48034806
Py_DECREF(kwdDict);
48044807
Py_DECREF(argTuple);
48054808

48064809
if (resultLoadMat)
48074810
{
4808-
// parse every element of dictionary and check if it is a numpy.ndarray. If so, transforms
4809-
// it to c-style contiguous form
4811+
// Check if the result is a dictionary
48104812
if (PyDict_Check(resultLoadMat))
48114813
{
48124814
PyObject* key = NULL;
@@ -4816,76 +4818,89 @@ PyObject* PythonItom::PyLoadMatlabMat(PyObject* /*pSelf*/, PyObject* pArgs)
48164818
PyObject* importMatlabMatAsDataObjectObj =
48174819
PyUnicode_FromString("importMatlabMatAsDataObject");
48184820

4821+
// Iterate through dictionary items
48194822
while (PyDict_Next(
48204823
resultLoadMat, &pos, &key, &value)) // borrowed reference to key and value
48214824
{
4822-
if (PyArray_Check(value))
4825+
if (PyArray_Check(value)) // Check if the value is a NumPy array
48234826
{
4824-
if (PyArray_SIZE((PyArrayObject*)value) ==
4825-
1) // this is either a single value or a matlab-struct
4826-
{
4827-
PyObject* item = PyArray_ToList((PyArrayObject*)value); // new ref
4827+
PyArrayObject* array =
4828+
reinterpret_cast<PyArrayObject*>(value); // Cast to PyArrayObject
48284829

4829-
if (item && (PyLong_Check(item) || PyFloat_Check(item))) // keep it
4830+
// Check if it's a single element or a struct
4831+
if (PyArray_SIZE(array) == 1)
4832+
{
4833+
PyObject* item = PyArray_ToList(array); // new ref
4834+
if (item &&
4835+
(PyLong_Check(item) || PyFloat_Check(item))) // Keep it if it's a scalar
48304836
{
48314837
PyDict_SetItem(resultLoadMat, key, item);
48324838
}
4833-
else if (value && PyArray_HASFIELDS((PyArrayObject*)value))
4839+
else if (PyArray_HASFIELDS(
4840+
array)) // Use HASFIELDS macro to check for fields
48344841
{
4835-
// it may be that this is a struct which has been generated earlier from
4836-
// a npDataObject or dataObject
4837-
PyArray_Descr* descr = PyArray_DESCR((PyArrayObject*)value);
4842+
// It may be that this is a struct
4843+
PyArray_Descr* descr = PyArray_DESCR(array); // Get the descriptor
48384844

4839-
if (descr->fields != NULL) // fields is a dictionary with "fieldname" =>
4840-
// type-description for this field
4845+
// Instead of checking 'fields', let's manually check for a specific
4846+
// field
4847+
if (descr) // Check if descriptor exists
48414848
{
4842-
if (PyDict_Contains(descr->fields, itomMetaInfoObj))
4849+
// Get the field names if available
4850+
PyObject* fields = PyObject_GetAttrString(
4851+
reinterpret_cast<PyObject*>(descr), "fields");
4852+
if (fields &&
4853+
PyDict_Check(fields)) // Check if fields is a dictionary
48434854
{
4844-
PythonEngine* pyEngine = qobject_cast<PythonEngine*>(
4845-
AppManagement::getPythonEngine());
4846-
if (pyEngine)
4855+
// Now check if itomMetaInfoObj exists in the fields
4856+
if (PyDict_Contains(fields, itomMetaInfoObj) == 1)
48474857
{
4848-
PyObject* result = PyObject_CallMethodObjArgs(
4849-
pyEngine->m_itomFunctions,
4850-
importMatlabMatAsDataObjectObj,
4851-
value,
4852-
NULL); // new reference
4853-
4854-
if (result == NULL || PyErr_Occurred())
4858+
PythonEngine* pyEngine = qobject_cast<PythonEngine*>(
4859+
AppManagement::getPythonEngine());
4860+
if (pyEngine)
48554861
{
4862+
PyObject* result = PyObject_CallMethodObjArgs(
4863+
pyEngine->m_itomFunctions,
4864+
importMatlabMatAsDataObjectObj,
4865+
array,
4866+
NULL); // new reference
4867+
4868+
if (result == NULL || PyErr_Occurred())
4869+
{
4870+
Py_XDECREF(result);
4871+
Py_XDECREF(scipyIoModule);
4872+
Py_XDECREF(itomMetaInfoObj);
4873+
Py_XDECREF(importMatlabMatAsDataObjectObj);
4874+
PyErr_PrintEx(0);
4875+
PyErr_SetString(
4876+
PyExc_RuntimeError,
4877+
"Error while parsing imported dataObject or "
4878+
"npDataObject.");
4879+
return NULL;
4880+
}
4881+
PyDict_SetItem(resultLoadMat, key, result);
48564882
Py_XDECREF(result);
4883+
}
4884+
else
4885+
{
48574886
Py_XDECREF(scipyIoModule);
48584887
Py_XDECREF(itomMetaInfoObj);
48594888
Py_XDECREF(importMatlabMatAsDataObjectObj);
4860-
PyErr_PrintEx(0);
48614889
PyErr_SetString(
4862-
PyExc_RuntimeError,
4863-
"Error while parsing imported dataObject or "
4864-
"npDataObject.");
4890+
PyExc_RuntimeError, "Python Engine not available");
48654891
return NULL;
48664892
}
4867-
PyDict_SetItem(resultLoadMat, key, result);
4868-
Py_XDECREF(result);
4869-
}
4870-
else
4871-
{
4872-
Py_XDECREF(scipyIoModule);
4873-
Py_XDECREF(itomMetaInfoObj);
4874-
Py_XDECREF(importMatlabMatAsDataObjectObj);
4875-
PyErr_SetString(
4876-
PyExc_RuntimeError, "Python Engine not available");
4877-
return NULL;
48784893
}
48794894
}
4895+
Py_XDECREF(fields);
48804896
}
48814897
}
4882-
48834898
Py_XDECREF(item);
48844899
}
4885-
else // this should be an ordinary numpy.array
4900+
else // Ordinary numpy array
48864901
{
4887-
PyObject* newArr = (PyObject*)PyArray_GETCONTIGUOUS(
4888-
(PyArrayObject*)value); // should be new reference
4902+
PyObject* newArr =
4903+
(PyObject*)PyArray_GETCONTIGUOUS(array); // should be new reference
48894904
PyDict_SetItem(resultLoadMat, key, newArr);
48904905
Py_DECREF(newArr);
48914906
}
@@ -4898,7 +4913,6 @@ PyObject* PythonItom::PyLoadMatlabMat(PyObject* /*pSelf*/, PyObject* pArgs)
48984913
}
48994914

49004915
Py_XDECREF(scipyIoModule);
4901-
49024916
return resultLoadMat;
49034917
}
49044918

0 commit comments

Comments
 (0)