@@ -1367,6 +1367,160 @@ PyArray_GetArrayParamsFromObject(PyObject *NPY_UNUSED(op),
1367
1367
}
1368
1368
1369
1369
1370
+ /*
1371
+ * This function is a legacy implementation to retain subarray dtype
1372
+ * behaviour in array coercion. The behaviour here makes sense if tuples
1373
+ * of matching dimensionality are being coerced. Due to the difficulty
1374
+ * that the result is ill-defined for lists of array-likes, this is deprecated.
1375
+ *
1376
+ * WARNING: Do not use this function, it exists purely to support a deprecated
1377
+ * code path.
1378
+ */
1379
+ static int
1380
+ setArrayFromSequence (PyArrayObject * a , PyObject * s ,
1381
+ int dim , PyArrayObject * dst )
1382
+ {
1383
+ Py_ssize_t i , slen ;
1384
+ int res = -1 ;
1385
+
1386
+ /* first recursion, view equal destination */
1387
+ if (dst == NULL )
1388
+ dst = a ;
1389
+
1390
+ /*
1391
+ * This code is to ensure that the sequence access below will
1392
+ * return a lower-dimensional sequence.
1393
+ */
1394
+
1395
+ /* INCREF on entry DECREF on exit */
1396
+ Py_INCREF (s );
1397
+
1398
+ PyObject * seq = NULL ;
1399
+
1400
+ if (PyArray_Check (s )) {
1401
+ if (!(PyArray_CheckExact (s ))) {
1402
+ /*
1403
+ * make sure a base-class array is used so that the dimensionality
1404
+ * reduction assumption is correct.
1405
+ */
1406
+ /* This will DECREF(s) if replaced */
1407
+ s = PyArray_EnsureArray (s );
1408
+ if (s == NULL ) {
1409
+ goto fail ;
1410
+ }
1411
+ }
1412
3419
+
1413
+ /* dst points to correct array subsection */
1414
+ if (PyArray_CopyInto (dst , (PyArrayObject * )s ) < 0 ) {
1415
+ goto fail ;
1416
+ }
1417
+
1418
+ Py_DECREF (s );
1419
+ return 0 ;
1420
+ }
1421
+
1422
+ if (dim > PyArray_NDIM (a )) {
1423
+ PyErr_Format (PyExc_ValueError ,
1424
+ "setArrayFromSequence: sequence/array dimensions mismatch." );
1425
+ goto fail ;
1426
+ }
1427
+
1428
+ /* Try __array__ before using s as a sequence */
1429
+ PyObject * tmp = _array_from_array_like (s , NULL , 0 , NULL );
1430
+ if (tmp == NULL ) {
1431
+ goto fail ;
1432
+ }
1433
+ else if (tmp == Py_NotImplemented ) {
1434
+ Py_DECREF (tmp );
1435
+ }
1436
+ else {
1437
+ int r = PyArray_CopyInto (dst , (PyArrayObject * )tmp );
1438
+ Py_DECREF (tmp );
1439
+ if (r < 0 ) {
1440
+ goto fail ;
1441
+ }
1442
+ Py_DECREF (s );
1443
+ return 0 ;
1444
+ }
1445
+
1446
+ seq = PySequence_Fast (s , "Could not convert object to sequence" );
1447
+ if (seq == NULL ) {
1448
+ goto fail ;
1449
+ }
1450
+ slen = PySequence_Fast_GET_SIZE (seq );
1451
+
1452
+ /*
1453
+ * Either the dimensions match, or the sequence has length 1 and can
1454
+ * be broadcast to the destination.
1455
+ */
1456
+ if (slen != PyArray_DIMS (a )[dim ] && slen != 1 ) {
1457
+ PyErr_Format (PyExc_ValueError ,
1458
+ "cannot copy sequence with size %zd to array axis "
1459
+ "with dimension %" NPY_INTP_FMT , slen , PyArray_DIMS (a )[dim ]);
1460
+ goto fail ;
1461
+ }
1462
+
1463
+ /* Broadcast the one element from the sequence to all the outputs */
1464
+ if (slen == 1 ) {
1465
+ PyObject * o = PySequence_Fast_GET_ITEM (seq , 0 );
1466
+ npy_intp alen = PyArray_DIM (a , dim );
1467
+
1468
+ for (i = 0 ; i < alen ; i ++ ) {
1469
+ if ((PyArray_NDIM (a ) - dim ) > 1 ) {
1470
+ PyArrayObject * tmp =
1471
+ (PyArrayObject * )array_item_asarray (dst , i );
1472
+ if (tmp == NULL ) {
1473
+ goto fail ;
1474
+ }
1475
+
1476
+ res = setArrayFromSequence (a , o , dim + 1 , tmp );
1477
+ Py_DECREF (tmp );
1478
+ }
1479
+ else {
1480
+ char * b = (PyArray_BYTES (dst ) + i * PyArray_STRIDES (dst )[0 ]);
1481
+ res = PyArray_SETITEM (dst , b , o );
1482
+ }
1483
+ if (res < 0 ) {
1484
+ goto fail ;
1485
+ }
1486
+ }
1487
+ }
1488
+ /* Copy element by element */
1489
+ else {
1490
+ for (i = 0 ; i < slen ; i ++ ) {
1491
+ PyObject * o = PySequence_Fast_GET_ITEM (seq , i );
1492
+ if ((PyArray_NDIM (a ) - dim ) > 1 ) {
1493
+ PyArrayObject * tmp =
1494
+ (PyArrayObject * )array_item_asarray (dst , i );
1495
+ if (tmp == NULL ) {
1496
+ goto fail ;
1497
+ }
1498
+
1499
+ res = setArrayFromSequence (a , o , dim + 1 , tmp );
1500
+ Py_DECREF (tmp );
1501
+ }
1502
+ else {
1503
+ char * b = (PyArray_BYTES (dst ) + i * PyArray_STRIDES (dst )[0 ]);
1504
+ res = PyArray_SETITEM (dst , b , o );
1505
+ }
1506
+ if (res < 0 ) {
150
6377
7
+ goto fail ;
1508
+ }
1509
+ }
1510
+ }
1511
+
1512
+ Py_DECREF (seq );
1513
+ Py_DECREF (s );
1514
+ return 0 ;
1515
+
1516
+ fail :
1517
+ Py_XDECREF (seq );
1518
+ Py_DECREF (s );
1519
+ return res ;
1520
+ }
1521
+
1522
+
1523
+
1370
1524
/*NUMPY_API
1371
1525
* Does not check for NPY_ARRAY_ENSURECOPY and NPY_ARRAY_NOTSWAPPED in flags
1372
1526
* Steals a reference to newtype --- which can be NULL
@@ -1407,6 +1561,54 @@ PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth,
1407
1561
if (ndim < 0 ) {
1408
1562
return NULL ;
1409
1563
}
1564
+
1565
+ if (NPY_UNLIKELY (fixed_descriptor != NULL && PyDataType_HASSUBARRAY (dtype ))) {
1566
+ /*
1567
+ * When a subarray dtype was passed in, its dimensions are absorbed
1568
+ * into the array dimension (causing a dimension mismatch).
1569
+ * We can't reasonably handle this because of inconsistencies in
1570
+ * how it was handled (depending on nested list vs. embed array-likes).
1571
+ * So we give a deprecation warning and fall back to legacy code.
1572
+ */
1573
+ ret = (PyArrayObject * )PyArray_NewFromDescr (
1574
+ & PyArray_Type , dtype , ndim , dims , NULL , NULL ,
1575
+ flags & NPY_ARRAY_F_CONTIGUOUS , NULL );
1576
+ if (ret == NULL ) {
1577
+ npy_free_coercion_cache (cache );
1578
+ return NULL ;
1579
+ }
1580
+ assert (PyArray_NDIM (ret ) != ndim );
1581
+
1582
+ if (cache == NULL ) {
1583
+ /* This is a single item. Sets only first subarray element. */
1584
+ assert (ndim == 0 );
1585
+ if (PyArray_Pack (PyArray_DESCR (ret ), PyArray_DATA (ret ), op ) < 0 ) {
1586
+ Py_DECREF (ret );
1587
+ return NULL ;
1588
+ }
1589
+ }
1590
+ else {
1591
+ npy_free_coercion_cache (cache );
1592
+ if (setArrayFromSequence (ret , op , 0 , NULL ) < 0 ) {
1593
+ Py_DECREF (ret );
1594
+ return NULL ;
1595
+ }
1596
+ }
1597
+ /* NumPy 1.20, 2020-10-01 */
1598
+ if (DEPRECATE (
1599
+ "using a dtype with a subarray field is deprecated. "
1600
+ "This can lead to inconsistent behaviour due to the resulting "
1601
+ "dtype being different from the input dtype. "
1602
+ "You may try to use `dtype=dtype.base`, which should give the "
1603
+ "same result for most inputs, but does not guarantee the "
1604
+ "output dimensions to match the subarray ones. "
1605
+ "(Deprecated NumPy 1.20)" )) {
1606
+ Py_DECREF (ret );
1607
+ return NULL ;
1608
+ }
1609
+ return (PyObject * )ret ;
1610
+ }
1611
+
1410
1612
if (dtype == NULL ) {
1411
1613
dtype = PyArray_DescrFromType (NPY_DEFAULT_TYPE );
1412
1614
}
0 commit comments