From 4d1e2b19da0209d4b4b754f2266036f443175df7 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Mon, 3 Feb 2020 14:37:08 -0600 Subject: [PATCH 1/2] REGR: Fixed setitem with MultiIndex Closes https://github.com/pandas-dev/pandas/issues/31449 --- doc/source/whatsnew/v1.0.1.rst | 1 + pandas/core/indexing.py | 3 ++- pandas/tests/indexing/multiindex/test_setitem.py | 10 ++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.0.1.rst b/doc/source/whatsnew/v1.0.1.rst index 180411afb117d..e0182e4e3c1f2 100644 --- a/doc/source/whatsnew/v1.0.1.rst +++ b/doc/source/whatsnew/v1.0.1.rst @@ -17,6 +17,7 @@ Fixed regressions - Fixed regression in :class:`DataFrame` setting values with a slice (e.g. ``df[-4:] = 1``) indexing by label instead of position (:issue:`31469`) - Fixed regression when indexing a ``Series`` or ``DataFrame`` indexed by ``DatetimeIndex`` with a slice containg a :class:`datetime.date` (:issue:`31501`) +- Fixed regression in ``DataFrame.__setitem__`` raising an ``AttributeError`` with a :class:`MultiIndex` and a non-monotonic indexer (:issue:`31449`) - Fixed regression in :class:`Series` multiplication when multiplying a numeric :class:`Series` with >10000 elements with a timedelta-like scalar (:issue:`31457`) - Fixed regression in :meth:`GroupBy.apply` if called with a function which returned a non-pandas non-scalar object (e.g. a list or numpy array) (:issue:`31441`) - Fixed regression in :meth:`to_datetime` when parsing non-nanosecond resolution datetimes (:issue:`31491`) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 77003719360d9..e0b11522c7be4 100755 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -893,7 +893,8 @@ def _setitem_with_indexer(self, indexer, value): # we can directly set the series here # as we select a slice indexer on the mi - idx = index._convert_slice_indexer(idx) + if isinstance(idx, slice): + idx = index._convert_slice_indexer(idx) obj._consolidate_inplace() obj = obj.copy() obj._data = obj._data.setitem(indexer=tuple([idx]), value=value) diff --git a/pandas/tests/indexing/multiindex/test_setitem.py b/pandas/tests/indexing/multiindex/test_setitem.py index aebd1ad2573ed..38ed00371e6e5 100644 --- a/pandas/tests/indexing/multiindex/test_setitem.py +++ b/pandas/tests/indexing/multiindex/test_setitem.py @@ -414,6 +414,16 @@ def test_astype_assignment_with_dups(self): df["A"] = df["A"].astype(np.float64) tm.assert_index_equal(df.index, index) + def test_setitem_nonmonotonic(self): + # https://github.com/pandas-dev/pandas/issues/31449 + index = pd.MultiIndex.from_tuples( + [("a", "c"), ("b", "x"), ("a", "d")], names=["l1", "l2"] + ) + df = pd.DataFrame(index=index, data=np.arange(3), columns=["e"]) + df.loc["a", "e"] = np.arange(99, 101) + expected = pd.DataFrame({"e": [99, 1, 100]}, index=index) + tm.assert_frame_equal(df, expected) + def test_frame_setitem_view_direct(multiindex_dataframe_random_data): # this works because we are modifying the underlying array From 90f991f16f614152a872777a977e298720e41c18 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Mon, 3 Feb 2020 15:05:24 -0600 Subject: [PATCH 2/2] 32-bit compat --- pandas/tests/indexing/multiindex/test_setitem.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/indexing/multiindex/test_setitem.py b/pandas/tests/indexing/multiindex/test_setitem.py index 38ed00371e6e5..1e641760f7e8d 100644 --- a/pandas/tests/indexing/multiindex/test_setitem.py +++ b/pandas/tests/indexing/multiindex/test_setitem.py @@ -419,8 +419,8 @@ def test_setitem_nonmonotonic(self): index = pd.MultiIndex.from_tuples( [("a", "c"), ("b", "x"), ("a", "d")], names=["l1", "l2"] ) - df = pd.DataFrame(index=index, data=np.arange(3), columns=["e"]) - df.loc["a", "e"] = np.arange(99, 101) + df = pd.DataFrame(data=[0, 1, 2], index=index, columns=["e"]) + df.loc["a", "e"] = np.arange(99, 101, dtype="int64") expected = pd.DataFrame({"e": [99, 1, 100]}, index=index) tm.assert_frame_equal(df, expected)