11
11
12
12
#include "npy_config.h"
13
13
14
+ #include "npy_import.h"
14
15
#include "npy_pycompat.h"
15
16
#include "multiarraymodule.h"
16
17
@@ -1302,7 +1303,51 @@ PyArray_New(PyTypeObject *subtype, int nd, npy_intp *dims, int type_num,
1302
1303
}
1303
1304
1304
1305
1305
- /* Steals a reference to the memory view */
1306
+ NPY_NO_EXPORT PyArray_Descr *
1307
+ _dtype_from_buffer_3118 (PyObject * memoryview )
1308
+ {
1309
+ PyArray_Descr * descr ;
1310
+ Py_buffer * view = PyMemoryView_GET_BUFFER (memoryview );
1311
+ if (view -> format != NULL ) {
1312
+ descr = _descriptor_from_pep3118_format (view -> format );
1313
+ if (descr == NULL ) {
1314
+ return NULL ;
1315
+ }
1316
+ }
1317
+ else {
1318
+ /* If no format is specified, just assume a byte array
1319
+ * TODO: void would make more sense here, as it wouldn't null
1320
+ * terminate.
1321
+ */
1322
+ descr = PyArray_DescrNewFromType (NPY_STRING );
1323
+ descr -> elsize = view -> itemsize ;
1324
+ }
1325
+ return descr ;
1326
+ }
1327
+
1328
+
1329
+ /*
1330
+ * Call the python _is_from_ctypes
1331
+ */
1332
+ NPY_NO_EXPORT int
1333
+ _is_from_ctypes (PyObject * obj ) {
1334
+ PyObject * ret_obj ;
1335
+ static PyObject * py_func = NULL ;
1336
+
1337
+ npy_cache_import ("numpy.core._internal" , "_is_from_ctypes" , & py_func );
1338
+
1339
+ if (py_func == NULL ) {
1340
+ return -1 ;
1341
+ }
1342
+ ret_obj = PyObject_CallFunctionObjArgs (py_func , obj , NULL );
1343
+ if (ret_obj == NULL ) {
1344
+ return -1 ;
1345
+ }
1346
+
1347
+ return PyObject_IsTrue (ret_obj );
1348
+ }
1349
+
1350
+
1306
1351
NPY_NO_EXPORT PyObject *
1307
1352
_array_from_buffer_3118 (PyObject * memoryview )
1308
1353
{
@@ -1315,27 +1360,75 @@ _array_from_buffer_3118(PyObject *memoryview)
1315
1360
npy_intp shape [NPY_MAXDIMS ], strides [NPY_MAXDIMS ];
1316
1361
1317
1362
view = PyMemoryView_GET_BUFFER (memoryview );
1318
- if (view -> format != NULL ) {
1319
- descr = _descriptor_from_pep3118_format (view -> format );
1320
- if (descr == NULL ) {
1321
- goto fail ;
1363
+ nd = view -> ndim ;
1364
+ descr = _dtype_from_buffer_3118 (memoryview );
1365
+
1366
+ if (descr == NULL ) {
1367
+ return NULL ;
1368
+ }
1369
+
1370
+ /* Sanity check */
1371
+ if (descr -> elsize != view -> itemsize ) {
1372
+ /* Ctypes has bugs in its PEP3118 implementation, which we need to
1373
+ * work around.
1374
+ *
1375
+ * bpo-10746
9E81
span>
1376
+ * bpo-32780
1377
+ * bpo-32782
1378
+ *
1379
+ * Note that even if the above are fixed in master, we have to drop the
1380
+ * early patch versions of python to actually make use of the fixes.
1381
+ */
1382
+
1383
+ int is_ctypes = _is_from_ctypes (view -> obj );
1384
+ if (is_ctypes < 0 ) {
1385
+ /* This error is not useful */
1386
+ PyErr_WriteUnraisable (view -> obj );
1387
+ is_ctypes = 0 ;
1322
1388
}
1323
1389
1324
- /* Sanity check */
1325
- if ( descr -> elsize != view -> itemsize ) {
1390
+ if (! is_ctypes ) {
1391
+ /* This object has no excuse for a broken PEP3118 buffer */
1326
1392
PyErr_SetString (
1327
1393
PyExc_RuntimeError ,
1328
1394
"Item size computed from the PEP 3118 buffer format "
1329
1395
"string does not match the actual item size." );
1330
- goto fail ;
1396
+ Py_DECREF (descr );
1397
+ return NULL ;
1398
+ }
1399
+
1400
+ if (PyErr_Warn (
1401
+ PyExc_RuntimeWarning ,
1402
+ "A builtin ctypes object gave a PEP3118 format "
1403
+ "string that does not match its itemsize, so a "
1404
+ "best-guess will be made of the data type. "
1405
+ "Newer versions of python may behave correctly." ) < 0 ) {
1406
+ Py_DECREF (descr );
1407
+ return NULL ;
1408
+ }
1409
+
1410
+ /* Thankfully, np.dtype(ctypes_type) works in most cases.
1411
+ * For an array input, this produces a dtype containing all the
1412
+ * dimensions, so the array is now 0d.
1413
+ */
1414
+ nd = 0 ;
1415
+ descr = (PyArray_Descr * )PyObject_CallFunctionObjArgs (
1416
+ (PyObject * )& PyArrayDescr_Type , Py_TYPE (view -> obj ), NULL );
1417
+ if (descr == NULL ) {
1418
+ return NULL ;
1419
+ }
1420
+ if (descr -> elsize != view -> len ) {
1421
+ PyErr_SetString (
1422
+ PyExc_RuntimeError ,
1423
+ "For the given ctypes object, neither the item size "
1424
+ "computed from the PEP 3118 buffer format nor from "
1425
+ "converting the type to a np.dtype matched the actual "
1426
+ "size. This is a bug both in python and numpy" );
1427
+ Py_DECREF (descr );
1428
+ return NULL ;
1331
1429
}
1332
- }
1333
- else {
1334
- descr = PyArray_DescrNewFromType (NPY_STRING );
1335
- descr -> elsize = view -> itemsize ;
1336
1430
}
1337
1431
1338
- nd = view -> ndim ;
1339
1432
if (view -> shape != NULL ) {
1340
1433
int k ;
1341
1434
if (nd > NPY_MAXDIMS || nd < 0 ) {
@@ -1379,13 +1472,12 @@ _array_from_buffer_3118(PyObject *memoryview)
1379
1472
& PyArray_Type , descr ,
1380
1473
nd , shape , strides , view -> buf ,
1381
1474
flags , NULL , memoryview );
1382
- Py_DECREF (memoryview );
1383
1475
return r ;
1384
1476
1477
+
1385
1478
fail :
1386
1479
Py_XDECREF (r );
1387
1480
Py_XDECREF (descr );
1388
- Py_DECREF (memoryview );
1389
1481
return NULL ;
1390
1482
1391
1483
}
@@ -1506,6 +1598,7 @@ PyArray_GetArrayParamsFromObject(PyObject *op,
1506
1598
}
1507
1599
else {
1508
1600
PyObject * arr = _array_from_buffer_3118 (memoryview );
1601
+ Py_DECREF (memoryview );
1509
1602
if (arr == NULL ) {
1510
1603
return -1 ;
1511
1604
}
0 commit comments