@@ -342,6 +342,10 @@ def test_setitem_complete_column_with_array(self):
342342 "d" : [1 , 1 , 1 ],
343343 }
344344 )
345+ expected ["c" ] = expected ["c" ].astype (arr .dtype )
346+ expected ["d" ] = expected ["d" ].astype (arr .dtype )
347+ assert expected ["c" ].dtype == arr .dtype
348+ assert expected ["d" ].dtype == arr .dtype
345349 tm .assert_frame_equal (df , expected )
346350
347351 @pytest .mark .parametrize ("dtype" , ["f8" , "i8" , "u8" ])
@@ -381,16 +385,35 @@ def test_setitem_frame_duplicate_columns(self, using_array_manager):
381385 [np .nan , 1 , 2 , np .nan , 4 , 5 ],
382386 [np .nan , 1 , 2 , np .nan , 4 , 5 ],
383387 ],
384- columns = cols ,
385388 dtype = "object" ,
386389 )
390+
387391 if using_array_manager :
388392 # setitem replaces column so changes dtype
393+
394+ expected .columns = cols
389395 expected ["C" ] = expected ["C" ].astype ("int64" )
390396 # TODO(ArrayManager) .loc still overwrites
391397 expected ["B" ] = expected ["B" ].astype ("int64" )
398+ else :
399+ # set these with unique columns to be extra-unambiguous
400+ expected [2 ] = expected [2 ].astype (np .int64 )
401+ expected [5 ] = expected [5 ].astype (np .int64 )
402+ expected .columns = cols
403+
392404 tm .assert_frame_equal (df , expected )
393405
406+ def test_setitem_frame_duplicate_columns_size_mismatch (self ):
407+ # GH#39510
408+ cols = ["A" , "B" , "C" ] * 2
409+ df = DataFrame (index = range (3 ), columns = cols )
410+ with pytest .raises (ValueError , match = "Columns must be same length as key" ):
411+ df [["A" ]] = (0 , 3 , 5 )
412+
413+ df2 = df .iloc [:, :3 ] # unique columns
414+ with pytest .raises (ValueError , match = "Columns must be same length as key" ):
415+ df2 [["A" ]] = (0 , 3 , 5 )
416+
394417 @pytest .mark .parametrize ("cols" , [["a" , "b" , "c" ], ["a" , "a" , "a" ]])
395418 def test_setitem_df_wrong_column_number (self , cols ):
396419 # GH#38604
@@ -890,3 +913,47 @@ def test_setitem_clear_caches(self):
890913
891914 assert df ["z" ] is not foo
892915 tm .assert_series_equal (df ["z" ], expected )
916+
917+ def test_setitem_duplicate_columns_not_inplace (self ):
918+ # GH#39510
919+ cols = ["A" , "B" ] * 2
920+ df = DataFrame (0.0 , index = [0 ], columns = cols )
921+ df_copy = df .copy ()
922+ df_view = df [:]
923+ df ["B" ] = (2 , 5 )
924+
925+ expected = DataFrame ([[0.0 , 2 , 0.0 , 5 ]], columns = cols )
926+ tm .assert_frame_equal (df_view , df_copy )
927+ tm .assert_frame_equal (df , expected )
928+
929+ @pytest .mark .parametrize ("value" , [1 , np .array ([[1 ], [1 ]]), [[1 ], [1 ]]])
930+ def test_setitem_same_dtype_not_inplace (self , value , using_array_manager , request ):
931+ # GH#39510
932+ if not using_array_manager :
933+ mark = pytest .mark .xfail (
934+ reason = "Setitem with same dtype still changing inplace"
935+ )
936+ request .node .add_marker (mark )
937+
938+ cols = ["A" , "B" ]
939+ df = DataFrame (0 , index = [0 , 1 ], columns = cols )
940+ df_copy = df .copy ()
941+ df_view = df [:]
942+ df [["B" ]] = value
943+
944+ expected = DataFrame ([[0 , 1 ], [0 , 1 ]], columns = cols )
945+ tm .assert_frame_equal (df , expected )
946+ tm .assert_frame_equal (df_view , df_copy )
947+
948+ @pytest .mark .parametrize ("value" , [1.0 , np .array ([[1.0 ], [1.0 ]]), [[1.0 ], [1.0 ]]])
949+ def test_setitem_listlike_key_scalar_value_not_inplace (self , value ):
950+ # GH#39510
951+ cols = ["A" , "B" ]
952+ df = DataFrame (0 , index = [0 , 1 ], columns = cols )
953+ df_copy = df .copy ()
954+ df_view = df [:]
955+ df [["B" ]] = value
956+
957+ expected = DataFrame ([[0 , 1.0 ], [0 , 1.0 ]], columns = cols )
958+ tm .assert_frame_equal (df_view , df_copy )
959+ tm .assert_frame_equal (df , expected )
0 commit comments