@@ -362,7 +362,8 @@ PyArray_GetSubType(int narrays, PyArrayObject **arrays) {
362
362
*/
363
363
NPY_NO_EXPORT PyArrayObject *
364
364
PyArray_ConcatenateArrays (int narrays , PyArrayObject * * arrays , int axis ,
365
- PyArrayObject * ret )
365
+ PyArrayObject * ret , PyArray_Descr * dtype ,
366
+ NPY_CASTING casting )
366
367
{
367
368
int iarrays , idim , ndim ;
368
369
npy_intp shape [NPY_MAXDIMS ];
@@ -426,6 +427,7 @@ PyArray_ConcatenateArrays(int narrays, PyArrayObject **arrays, int axis,
426
427
}
427
428
428
429
if (ret != NULL ) {
430
+ assert (dtype == NULL );
429
431
if (PyArray_NDIM (ret ) != ndim ) {
430
432
PyErr_SetString (PyExc_ValueError ,
431
433
"Output array has wrong dimensionality" );
@@ -445,10 +447,16 @@ PyArray_ConcatenateArrays(int narrays, PyArrayObject **arrays, int axis,
445
447
/* Get the priority subtype for the array */
446
448
PyTypeObject * subtype = PyArray_GetSubType (narrays , arrays );
447
449
448
- /* Get the resulting dtype from combining all the arrays */
449
- PyArray_Descr * dtype = PyArray_ResultType (narrays , arrays , 0 , NULL );
450
450
if (dtype == NULL ) {
451
- return NULL ;
451
+ /* Get the resulting dtype from combining all the arrays */
452
+ dtype = (PyArray_Descr * )PyArray_ResultType (
453
+ narrays , arrays , 0 , NULL );
454
+ if (dtype == NULL ) {
455
+ return NULL ;
456
+ }
457
+ }
458
+ else {
459
+ Py_INCREF (dtype );
452
460
}
453
461
454
462
/*
@@ -494,7 +502,7 @@ PyArray_ConcatenateArrays(int narrays, PyArrayObject **arrays, int axis,
494
502
495
503
/* Copy the data for this array */
496
504
if (PyArray_AssignArray ((PyArrayObject * )sliding_view , arrays [iarrays ],
497
- NULL , NPY_SAME_KIND_CASTING ) < 0 ) {
505
+ NULL , casting ) < 0 ) {
498
506
Py_DECREF (sliding_view );
499
507
Py_DECREF (ret );
500
508
return NULL ;
@@ -514,7 +522,9 @@ PyArray_ConcatenateArrays(int narrays, PyArrayObject **arrays, int axis,
514
522
*/
515
523
NPY_NO_EXPORT PyArrayObject *
516
524
PyArray_ConcatenateFlattenedArrays (int narrays , PyArrayObject * * arrays ,
517
- NPY_ORDER order , PyArrayObject * ret )
525
+ NPY_ORDER order , PyArrayObject * ret ,
526
+ PyArray_Descr * dtype , NPY_CASTING casting ,
527
+ npy_bool casting_not_passed )
518
528
{
519
529
int iarrays ;
520
530
npy_intp shape = 0 ;
@@ -541,7 +551,10 @@ PyArray_ConcatenateFlattenedArrays(int narrays, PyArrayObject **arrays,
541
551
}
542
552
}
543
553
554
+ int out_passed = 0 ;
544
555
if (ret != NULL ) {
556
+ assert (dtype == NULL );
557
+ out_passed = 1 ;
545
558
if (PyArray_NDIM (ret ) != 1 ) {
546
559
PyErr_SetString (PyExc_ValueError ,
547
560
"Output array must be 1D" );
@@ -560,10 +573,16 @@ PyArray_ConcatenateFlattenedArrays(int narrays, PyArrayObject **arrays,
560
573
/* Get the priority subtype for the array */
561
574
PyTypeObject * subtype = PyArray_GetSubType (narrays , arrays );
562
575
563
- /* Get the resulting dtype from combining all the arrays */
564
- PyArray_Descr * dtype = PyArray_ResultType (narrays , arrays , 0 , NULL );
565
576
if (dtype == NULL ) {
566
- return NULL ;
577
+ /* Get the resulting dtype from combining all the arrays */
578
+ dtype = (PyArray_Descr * )PyArray_ResultType (
579
+ narrays , arrays , 0 , NULL );
580
+ if (dtype == NULL ) {
581
+ return NULL ;
582
+ }
583
+ }
584
+ else {
585
+ Py_INCREF (dtype );
567
586
}
568
587
569
588
stride = dtype -> elsize ;
@@ -593,10 +612,37 @@ PyArray_ConcatenateFlattenedArrays(int narrays, PyArrayObject **arrays,
593
612
return NULL ;
594
613
}
595
614
615
+ int give_deprecation_warning = 1 ; /* To give warning for just one input array. */
596
616
for (iarrays = 0 ; iarrays < narrays ; ++ iarrays ) {
597
617
/* Adjust the window dimensions for this array */
598
618
sliding_view -> dimensions [0 ] = PyArray_SIZE (arrays [iarrays ]);
599
619
620
+ if (!PyArray_CanCastArrayTo (
621
+ arrays [iarrays ], PyArray_DESCR (ret ), casting )) {
622
+ /* This should be an error, but was previously allowed here. */
623
+ if (casting_not_passed && out_passed ) {
624
+ /* NumPy 1.20, 2020-09-03 */
625
+ if (give_deprecation_warning && DEPRECATE (
626
+ "concatenate() with `axis=None` will use same-kind "
627
+ "casting by default in the future. Please use "
628
+ "`casting='unsafe'` to retain the old behaviour. "
629
+ "In the future this will be a TypeError." ) < 0 ) {
630
+ Py_DECREF (sliding_view );
631
+ Py_DECREF (ret );
632
+ return NULL ;
633
+ }
634
+ give_deprecation_warning = 0 ;
635
+ }
636
+ else {
637
+ npy_set_invalid_cast_error (
638
+ PyArray_DESCR (arrays [iarrays ]), PyArray_DESCR (ret ),
639
+ casting , PyArray_NDIM (arrays [iarrays ]) == 0 );
640
+ Py_DECREF (sliding_view );
641
+ Py_DECREF (ret );
642
+ return NULL ;
643
+ }
644
+ }
645
+
600
646
/* Copy the data for this array */
601
647
if (PyArray_CopyAsFlat ((PyArrayObject * )sliding_view , arrays [iarrays ],
602
648
order ) < 0 ) {
@@ -614,8 +660,21 @@ PyArray_ConcatenateFlattenedArrays(int narrays, PyArrayObject **arrays,
614
660
return ret ;
615
661
}
616
662
663
+
664
+ /**
665
+ * Implementation for np.concatenate
666
+ *
667
+ * @param op Sequence of arrays to concatenate
668
+ * @param axis Axis to concatenate along
669
+ * @param ret output array to fill
670
+ * @param dtype Forced output array dtype (cannot be combined with ret)
671
+ * @param casting Casting mode used
672
+ * @param casting_not_passed Deprecation helper
673
+ */
617
674
NPY_NO_EXPORT PyObject *
618
- PyArray_ConcatenateInto (PyObject * op , int axis , PyArrayObject * ret )
675
+ PyArray_ConcatenateInto (PyObject * op ,
676
+ int axis , PyArrayObject * ret , PyArray_Descr * dtype ,
677
+ NPY_CASTING casting , npy_bool casting_not_passed )
619
678
{
620
679
int iarrays , narrays ;
621
680
PyArrayObject * * arrays ;
@@ -625,6 +684,12 @@ PyArray_ConcatenateInto(PyObject *op, int axis, PyArrayObject *ret)
625
684
"The first input argument needs to be a sequence" );
626
685
return NULL ;
627
686
}
687
+ if (ret != NULL && dtype != NULL ) {
688
+ PyErr_SetString (PyExc_TypeError ,
689
+ "concatenate() only takes `out` or `dtype` as an "
690
+ "argument, but both were provided." );
691
+ return NULL ;
692
+ }
628
693
629
694
/* Convert the input list into arrays */
630
695
narrays = PySequence_Size (op );
@@ -651,10 +716,13 @@ PyArray_ConcatenateInto(PyObject *op, int axis, PyArrayObject *ret)
651
716
}
652
717
653
718
if (axis >= NPY_MAXDIMS ) {
654
- ret = PyArray_ConcatenateFlattenedArrays (narrays , arrays , NPY_CORDER , ret );
719
+ ret = PyArray_ConcatenateFlattenedArrays (
720
+ narrays , arrays , NPY_CORDER , ret , dtype ,
721
+ casting , casting_not_passed );
655
722
}
656
723
else {
657
- ret = PyArray_ConcatenateArrays (narrays , arrays , axis , ret );
724
+ ret = PyArray_ConcatenateArrays (
725
+ narrays , arrays , axis , ret , dtype , casting );
658
726
}
659
727
660
728
for (iarrays = 0 ; iarrays < narrays ; ++ iarrays ) {
@@ -686,7 +754,16 @@ PyArray_ConcatenateInto(PyObject *op, int axis, PyArrayObject *ret)
686
754
NPY_NO_EXPORT PyObject *
687
755
PyArray_Concatenate (PyObject * op , int axis )
688
756
{
689
- return PyArray_ConcatenateInto (op , axis , NULL );
757
+ /* retain legacy behaviour for casting */
758
+ NPY_CASTING casting ;
759
+ if (axis >= NPY_MAXDIMS ) {
760
+ casting = NPY_UNSAFE_CASTING ;
761
+ }
762
+ else {
763
+ casting = NPY_SAME_KIND_CASTING ;
764
+ }
765
+ return PyArray_ConcatenateInto (
766
+ op , axis , NULL , NULL , casting , 0 );
690
767
}
691
768
692
769
static int
@@ -2259,11 +2336,27 @@ array_concatenate(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds)
2259
2336
{
2260
2337
PyObject * a0 ;
2261
2338
PyObject * out = NULL ;
2339
+ PyArray_Descr * dtype = NULL ;
2340
+ NPY_CASTING casting = NPY_SAME_KIND_CASTING ;
2341
+ PyObject * casting_obj = NULL ;
2342
+ PyObject * res ;
2262
2343
int axis = 0 ;
2263
- static char * kwlist [] = {"seq" , "axis" , "out" , NULL };
2264
-
2265
- if (!PyArg_ParseTupleAndKeywords (args , kwds , "O|O&O:concatenate" , kwlist ,
2266
- & a0 , PyArray_AxisConverter , & axis , & out )) {
2344
+ static char * kwlist [] = {"seq" , "axis" , "out" , "dtype" , "casting" , NULL };
2345
+ if (!PyArg_ParseTupleAndKeywords (args , kwds , "O|O&O$O&O:concatenate" , kwlist ,
2346
+ & a0 , PyArray_AxisConverter , & axis , & out ,
2347
+ PyArray_DescrConverter2 , & dtype , & casting_obj )) {
2348
+ return NULL ;
2349
+ }
2350
+ int casting_not_passed = 0 ;
2351
+ if (casting_obj == NULL ) {
2352
+ /*
2353
+ * Casting was not passed in, needed for deprecation only.
2354
+ * This should be simplified once the deprecation is finished.
2355
+ */
2356
+ casting_not_passed = 1 ;
2357
+ }
2358
+ else if (!PyArray_CastingConverter (casting_obj , & casting )) {
2359
+ Py_XDECREF (dtype );
2267
2360
return NULL ;
2268
2361
}
2269
2362
if (out != NULL ) {
@@ -2272,10 +2365,14 @@ array_concatenate(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds)
2272
2365
}
2273
2366
else if (!PyArray_Check (out )) {
2274
2367
PyErr_SetString (PyExc_TypeError , "'out' must be an array" );
2368
+ Py_XDECREF (dtype );
2275
2369
return NULL ;
2276
2370
}
2277
2371
}
2278
- return PyArray_ConcatenateInto (a0 , axis , (PyArrayObject * )out );
2372
+ res = PyArray_ConcatenateInto (a0 , axis , (PyArrayObject * )out , dtype ,
2373
+ casting , casting_not_passed );
2374
+ Py_XDECREF (dtype );
2375
+ return res ;
2279
2376
}
2280
2377
2281
2378
static PyObject *
0 commit comments