From 0a74285ca2549f8d5d9a0d7e00773cf54ab0f163 Mon Sep 17 00:00:00 2001 From: phofl Date: Tue, 25 Jan 2022 22:15:02 +0100 Subject: [PATCH 1/3] REGR: loc.setitem losing index name when df was empty before --- doc/source/whatsnew/v1.4.1.rst | 1 + pandas/core/indexing.py | 1 + pandas/tests/frame/indexing/test_indexing.py | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/doc/source/whatsnew/v1.4.1.rst b/doc/source/whatsnew/v1.4.1.rst index 79dae514b77e9..026051d126d5b 100644 --- a/doc/source/whatsnew/v1.4.1.rst +++ b/doc/source/whatsnew/v1.4.1.rst @@ -15,6 +15,7 @@ including other versions of pandas. Fixed regressions ~~~~~~~~~~~~~~~~~ - Regression in :meth:`Series.mask` with ``inplace=True`` and ``PeriodDtype`` and an incompatible ``other`` coercing to a common dtype instead of raising (:issue:`45546`) +- Regression in :meth:`DataFrame.loc.__setitem__` losing :class:`Index` name if :class:`DataFrame` was empty before (:issue:`45621`) - .. --------------------------------------------------------------------------- diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 5f9bc142c5836..0ba2f70752055 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -2018,6 +2018,7 @@ def _setitem_with_indexer_missing(self, indexer, value): # internals.concat logic df = value.to_frame().T df.index = [indexer] + df.index.name = self.obj.index.name if not has_dtype: # i.e. if we already had a Series or ndarray, keep that # dtype. But if we had a list or dict, then do inference diff --git a/pandas/tests/frame/indexing/test_indexing.py b/pandas/tests/frame/indexing/test_indexing.py index 5a97c591fd621..4476fbe2f78c9 100644 --- a/pandas/tests/frame/indexing/test_indexing.py +++ b/pandas/tests/frame/indexing/test_indexing.py @@ -1279,6 +1279,13 @@ def test_setting_mismatched_na_into_nullable_fails( with pytest.raises(TypeError, match=msg): df2.iloc[:2, 0] = [null, null] + def test_loc_expand_empty_frame_keep_index_name(self): + # GH#45621 + df = DataFrame(columns=["b"], index=Index([], name="a")) + df.loc[0] = 1 + expected = DataFrame({"b": [1]}, index=Index([0], name="a")) + tm.assert_frame_equal(df, expected) + class TestDataFrameIndexingUInt64: def test_setitem(self, uint64_frame): From 024dd9cac1d0131f02da6771338463022a1b9d5a Mon Sep 17 00:00:00 2001 From: phofl Date: Tue, 25 Jan 2022 22:48:44 +0100 Subject: [PATCH 2/3] Add ignore --- pandas/core/indexing.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 0ba2f70752055..c6ae4669d104c 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -2018,7 +2018,8 @@ def _setitem_with_indexer_missing(self, indexer, value): # internals.concat logic df = value.to_frame().T df.index = [indexer] - df.index.name = self.obj.index.name + # error: "List[Any]" has no attribute "name" + df.index.name = self.obj.index.name # type: ignore[attr-defined] if not has_dtype: # i.e. if we already had a Series or ndarray, keep that # dtype. But if we had a list or dict, then do inference From e7bdaeea2d451b200da7e4f9eca5ddd9745a2cea Mon Sep 17 00:00:00 2001 From: phofl Date: Wed, 26 Jan 2022 21:42:16 +0100 Subject: [PATCH 3/3] Use index --- pandas/core/indexing.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index c6ae4669d104c..fdcb55f3a637a 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -2017,9 +2017,7 @@ def _setitem_with_indexer_missing(self, indexer, value): # We will ignore the existing dtypes instead of using # internals.concat logic df = value.to_frame().T - df.index = [indexer] - # error: "List[Any]" has no attribute "name" - df.index.name = self.obj.index.name # type: ignore[attr-defined] + df.index = Index([indexer], name=self.obj.index.name) if not has_dtype: # i.e. if we already had a Series or ndarray, keep that # dtype. But if we had a list or dict, then do inference