Skip to content

Commit caf81fa

Browse files
authored
BUG: DataFrame.__setitem__ not raising ValueError when rhs is df and has wrong number of columns (#39341)
1 parent 9e47ff7 commit caf81fa

File tree

3 files changed

+32
-6
lines changed

3 files changed

+32
-6
lines changed

doc/source/whatsnew/v1.3.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ Indexing
287287
- Bug in :meth:`DataFrame.__setitem__` raising ``ValueError`` with empty :class:`DataFrame` and specified columns for string indexer and non empty :class:`DataFrame` to set (:issue:`38831`)
288288
- Bug in :meth:`DataFrame.loc.__setitem__` raising ValueError when expanding unique column for :class:`DataFrame` with duplicate columns (:issue:`38521`)
289289
- Bug in :meth:`DataFrame.iloc.__setitem__` and :meth:`DataFrame.loc.__setitem__` with mixed dtypes when setting with a dictionary value (:issue:`38335`)
290+
- Bug in :meth:`DataFrame.__setitem__` not raising ``ValueError`` when right hand side is a :class:`DataFrame` with wrong number of columns (:issue:`38604`)
290291
- Bug in :meth:`DataFrame.loc` dropping levels of :class:`MultiIndex` when :class:`DataFrame` used as input has only one row (:issue:`10521`)
291292
- Bug in setting ``timedelta64`` values into numeric :class:`Series` failing to cast to object dtype (:issue:`39086`)
292293
- Bug in setting :class:`Interval` values into a :class:`Series` or :class:`DataFrame` with mismatched :class:`IntervalDtype` incorrectly casting the new values to the existing dtype (:issue:`39120`)

pandas/core/frame.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3223,7 +3223,7 @@ def _setitem_array(self, key, value):
32233223
self._check_setitem_copy()
32243224
self.iloc[indexer] = value
32253225
else:
3226-
if isinstance(value, DataFrame):
3226+
if isinstance(value, DataFrame) and self.columns.is_unique:
32273227
if len(value.columns) != len(key):
32283228
raise ValueError("Columns must be same length as key")
32293229
for k1, k2 in zip(key, value.columns):
@@ -3256,12 +3256,20 @@ def _setitem_frame(self, key, value):
32563256
def _set_item_frame_value(self, key, value: DataFrame) -> None:
32573257
self._ensure_valid_index(value)
32583258

3259-
# align right-hand-side columns if self.columns
3260-
# is multi-index and self[key] is a sub-frame
3261-
if isinstance(self.columns, MultiIndex) and key in self.columns:
3259+
# align columns
3260+
if key in self.columns:
32623261
loc = self.columns.get_loc(key)
3263-
if isinstance(loc, (slice, Series, np.ndarray, Index)):
3264-
cols = maybe_droplevels(self.columns[loc], key)
3262+
cols = self.columns[loc]
3263+
len_cols = 1 if is_scalar(cols) else len(cols)
3264+
if len_cols != len(value.columns):
3265+
raise ValueError("Columns must be same length as key")
3266+
3267+
# align right-hand-side columns if self.columns
3268+
# is multi-index and self[key] is a sub-frame
3269+
if isinstance(self.columns, MultiIndex) and isinstance(
3270+
loc, (slice, Series, np.ndarray, Index)
3271+
):
3272+
cols = maybe_droplevels(cols, key)
32653273
if len(cols) and not cols.equals(value.columns):
32663274
value = value.reindex(cols, axis=1)
32673275

pandas/tests/frame/indexing/test_setitem.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,23 @@ def test_setitem_frame_duplicate_columns(self):
366366
)
367367
tm.assert_frame_equal(df, expected)
368368

369+
@pytest.mark.parametrize("cols", [["a", "b", "c"], ["a", "a", "a"]])
370+
def test_setitem_df_wrong_column_number(self, cols):
371+
# GH#38604
372+
df = DataFrame([[1, 2, 3]], columns=cols)
373+
rhs = DataFrame([[10, 11]], columns=["d", "e"])
374+
msg = "Columns must be same length as key"
375+
with pytest.raises(ValueError, match=msg):
376+
df["a"] = rhs
377+
378+
def test_setitem_listlike_indexer_duplicate_columns(self):
379+
# GH#38604
380+
df = DataFrame([[1, 2, 3]], columns=["a", "b", "b"])
381+
rhs = DataFrame([[10, 11, 12]], columns=["d", "e", "c"])
382+
df[["a", "b"]] = rhs
383+
expected = DataFrame([[10, 11, 12]], columns=["a", "b", "b"])
384+
tm.assert_frame_equal(df, expected)
385+
369386

370387
class TestDataFrameSetItemWithExpansion:
371388
def test_setitem_listlike_views(self):

0 commit comments

Comments
 (0)