Skip to content

Commit fede2e6

Browse files
authored
Fix integer handling with NumPy 2.0 on Windows (pyccel#2116)
Fix integer handling with NumPy 2.0 on Windows. The default integer is correctly deduced however the handling in the wrapper was incorrect. This was fixed (fixes pyccel#2115). Additionally the dtype error output is cleaned up so the positions of the datatypes in NumPy's enum are not hard coded on our side. This fix was complicated by the fact that `np.random.randint`'s default dtype is maintained at `np.long` and therefore does not match the default used by all other NumPy functions in v2: ![image](https://github.com/user-attachments/assets/3f331352-2e92-44d4-8176-1e410af5cfd6)
1 parent 2be7299 commit fede2e6

File tree

16 files changed

+214
-230
lines changed

16 files changed

+214
-230
lines changed

.github/actions/windows_install/action.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ runs:
44
using: "composite"
55
steps:
66
- name: Fix 'Unknown MS Compiler version 1900' problem
7+
continue-on-error: True
78
run: |
89
$PYTHON_EXE_PATH=(Get-Command python).Source
910
$PYTHON_PATH=(Split-Path -Path ${PYTHON_EXE_PATH})

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ All notable changes to this project will be documented in this file.
9595
- #2094 : Fix slicing of array allocated in an if block.
9696
- #2085 : Fix calling class methods before they are defined.
9797
- #2111 : Fix declaration of class attributes with name conflicts using type annotations.
98+
- #2115 : Fix integer handling with NumPy 2.0 on Windows.
9899

99100
### Changed
100101

pyccel/ast/numpy_wrapper.py

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,11 @@ def get_numpy_max_acceptable_version_file():
199199
numpy_ubyte_type = Variable(CNativeInt(), name = 'NPY_UBYTE')
200200
numpy_short_type = Variable(CNativeInt(), name = 'NPY_SHORT')
201201
numpy_ushort_type = Variable(CNativeInt(), name = 'NPY_USHORT')
202-
numpy_int_type = Variable(CNativeInt(), name = 'NPY_INT32')
202+
numpy_int32_type = Variable(CNativeInt(), name = 'NPY_INT32')
203203
numpy_uint_type = Variable(CNativeInt(), name = 'NPY_UINT')
204204
numpy_long_type = Variable(CNativeInt(), name = 'NPY_LONG')
205205
numpy_ulong_type = Variable(CNativeInt(), name = 'NPY_ULONG')
206-
numpy_longlong_type = Variable(CNativeInt(), name = 'NPY_INT64')
206+
numpy_int64_type = Variable(CNativeInt(), name = 'NPY_INT64')
207207
numpy_ulonglong_type = Variable(CNativeInt(), name = 'NPY_ULONGLONG')
208208
numpy_float_type = Variable(CNativeInt(), name = 'NPY_FLOAT')
209209
numpy_double_type = Variable(CNativeInt(), name = 'NPY_DOUBLE')
@@ -212,36 +212,11 @@ def get_numpy_max_acceptable_version_file():
212212
numpy_cdouble_type = Variable(CNativeInt(), name = 'NPY_CDOUBLE')
213213
numpy_clongdouble_type = Variable(CNativeInt(), name = 'NPY_CLONGDOUBLE')
214214

215-
numpy_num_to_type = {0 : numpy_bool_type,
216-
1 : numpy_byte_type,
217-
2 : numpy_ubyte_type,
218-
3 : numpy_short_type,
219-
4 : numpy_ushort_type,
220-
5 : numpy_int_type,
221-
6 : numpy_uint_type,
222-
7 : numpy_long_type,
223-
8 : numpy_ulong_type,
224-
9 : numpy_longlong_type,
225-
10 : numpy_ulonglong_type,
226-
11 : numpy_float_type,
227-
12 : numpy_double_type,
228-
13 : numpy_longdouble_type,
229-
14 : numpy_cfloat_type,
230-
15 : numpy_cdouble_type,
231-
16 : numpy_clongdouble_type}
232-
233-
# This dictionary is required as the precision does not line up with the expected type on windows
234-
numpy_int_type_precision_map = {
235-
1 : np.dtype(np.int8).num,
236-
2 : np.dtype(np.int16).num,
237-
4 : np.dtype(np.int32).num,
238-
8 : np.dtype(np.int64).num}
239-
240215
numpy_dtype_registry = {PythonNativeBool() : numpy_bool_type,
241-
NumpyInt8Type() : numpy_num_to_type[numpy_int_type_precision_map[1]],
242-
NumpyInt16Type() : numpy_num_to_type[numpy_int_type_precision_map[2]],
243-
NumpyInt32Type() : numpy_num_to_type[numpy_int_type_precision_map[4]],
244-
NumpyInt64Type() : numpy_num_to_type[numpy_int_type_precision_map[8]],
216+
NumpyInt8Type() : numpy_byte_type,
217+
NumpyInt16Type() : numpy_short_type,
218+
NumpyInt32Type() : numpy_int32_type,
219+
NumpyInt64Type() : numpy_int64_type,
245220
NumpyFloat32Type() : numpy_float_type,
246221
NumpyFloat64Type() : numpy_double_type,
247222
NumpyFloat128Type() : numpy_longdouble_type,

pyccel/stdlib/cwrapper/cwrapper.c

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,6 @@
77

88

99

10-
// strings order needs to be the same as its equivalent numpy macro
11-
// https://numpy.org/doc/stable/reference/c-api/dtype.html
12-
const char* dataTypes[17] = {"Bool", "Int8", "UInt8", "Int16", "UIn16", "Int32", "UInt32",
13-
"Int64", "UInt64", "Int128", "UInt128", "Float32", "Float64",
14-
"Float128", "Complex64", "Complex128", "Complex256"};
15-
16-
17-
18-
1910
/* Casting python object to c type
2011
*
2112
* Reference of the used c python api function
@@ -174,7 +165,7 @@ void capsule_cleanup(PyObject *capsule) {
174165
#endif
175166
}
176167

177-
#ifdef _WIN32
168+
#if defined(WIN32) && (PyArray_RUNTIME_VERSION >= NPY_2_0_API_VERSION)
178169
PyObject* to_pyarray(int nd, enum NPY_TYPES typenum, void* data, int32_t shape[], bool c_order, bool release_memory)
179170
#else
180171
PyObject* to_pyarray(int nd, enum NPY_TYPES typenum, void* data, int64_t shape[], bool c_order, bool release_memory)

pyccel/stdlib/cwrapper/cwrapper.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@
2525
# define PY_ARRAY_UNIQUE_SYMBOL CWRAPPER_ARRAY_API
2626
# include "numpy/arrayobject.h"
2727

28-
extern const char* dataTypes[17];
29-
3028
/*
3129
* A function which can be passed to a PyCapsule in order to free data that was created by Pyccel.
3230
*/
@@ -50,7 +48,7 @@ void capsule_cleanup(PyObject *capsule);
5048
* c_order : True if the data is in C order, False otherwise.
5149
* release_memory : If true a Capsule is created to automatically free the data when the created PyArrayObject goes out of scope.
5250
*/
53-
#ifdef _WIN32
51+
#if defined(_WIN32) && (PyArray_RUNTIME_VERSION >= NPY_2_0_API_VERSION)
5452
PyObject* to_pyarray(int nd, enum NPY_TYPES typenum, void* data, int32_t shape[], bool c_order, bool release_memory);
5553
#else
5654
PyObject* to_pyarray(int nd, enum NPY_TYPES typenum, void* data, int64_t shape[], bool c_order, bool release_memory);

pyccel/stdlib/cwrapper_ndarrays/cwrapper_ndarrays.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,15 @@ static char* _check_pyarray_dtype(PyArrayObject *a, int dtype)
100100
current_dtype = PyArray_TYPE(a);
101101
if (current_dtype != dtype)
102102
{
103+
PyObject* current_type_name = PyObject_Str(PyArray_DESCR(a)->typeobj);
104+
PyObject* expected_type_name = PyObject_Str(PyArray_TypeObjectFromType(dtype));
105+
Py_ssize_t c_size;
106+
const char* current_name = PyUnicode_AsUTF8AndSize(current_type_name, &c_size);
107+
const char* expected_name = PyUnicode_AsUTF8AndSize(expected_type_name, &c_size);
103108
char* error = (char *)malloc(200);
104109
sprintf(error, "argument dtype must be %s, not %s",
105-
dataTypes[dtype],
106-
dataTypes[current_dtype]);
110+
expected_name,
111+
current_name);
107112
return error;
108113
}
109114

0 commit comments

Comments
 (0)