@@ -492,8 +492,10 @@ def test_flatiter():
492492
493493
494494def test_reshape2d ():
495+
495496 class dummy ():
496497 pass
498+
497499 xnew = cbook ._reshape_2D ([], 'x' )
498500 assert np .shape (xnew ) == (1 , 0 )
499501
@@ -515,6 +517,41 @@ class dummy():
515517 xnew = cbook ._reshape_2D (x , 'x' )
516518 assert np .shape (xnew ) == (5 , 3 )
517519
520+ # Now test with a list of lists with different lengths, which means the
521+ # array will internally be converted to a 1D object array of lists
522+ x = [[1 , 2 , 3 ], [3 , 4 ], [2 ]]
523+ xnew = cbook ._reshape_2D (x , 'x' )
524+ assert isinstance (xnew , list )
525+ assert isinstance (xnew [0 ], np .ndarray ) and xnew [0 ].shape == (3 ,)
526+ assert isinstance (xnew [1 ], np .ndarray ) and xnew [1 ].shape == (2 ,)
527+ assert isinstance (xnew [2 ], np .ndarray ) and xnew [2 ].shape == (1 ,)
528+
529+ # We now need to make sure that this works correctly for Numpy subclasses
530+ # where iterating over items can return subclasses too, which may be
531+ # iterable even if they are scalars. To emulate this, we make a Numpy
532+ # array subclass that returns Numpy 'scalars' when iterating or accessing
533+ # values, and these are technically iterable if checking for example
534+ # isinstance(x, collections.abc.Iterable).
535+
536+ class ArraySubclass (np .ndarray ):
537+
538+ def __iter__ (self ):
539+ for value in super ().__iter__ ():
540+ yield np .array (value )
541+
542+ def __getitem__ (self , item ):
543+ return np .array (super ().__getitem__ (item ))
544+
545+ v = np .arange (10 , dtype = float )
546+ x = ArraySubclass ((10 ,), dtype = float , buffer = v .data )
547+
548+ xnew = cbook ._reshape_2D (x , 'x' )
549+
550+ # We check here that the array wasn't split up into many individual
551+ # ArraySubclass, which is what used to happen due to a bug in _reshape_2D
552+ assert len (xnew ) == 1
553+ assert isinstance (xnew [0 ], ArraySubclass )
554+
518555
519556def test_contiguous_regions ():
520557 a , b , c = 3 , 4 , 5
0 commit comments