From 3bf7b260abadb805b4502518eb5148c083ce528a Mon Sep 17 00:00:00 2001 From: Katsuya Horiuchi Date: Fri, 23 Aug 2019 22:30:25 +0900 Subject: [PATCH 1/5] DataFrame.drop raising TypeError when passing empty DatetimeIndex/list Closes #27994 --- pandas/core/generic.py | 2 ++ pandas/tests/frame/test_axis_select_reindex.py | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index ba1c516b9b444..80958245a4e31 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -3888,6 +3888,8 @@ def drop( for axis, labels in axes.items(): if labels is not None: + if isinstance(labels, (list, Index)) and len(labels) == 0: + continue obj = obj._drop_axis(labels, axis, level=level, errors=errors) if inplace: diff --git a/pandas/tests/frame/test_axis_select_reindex.py b/pandas/tests/frame/test_axis_select_reindex.py index 1ef10ea5857d0..54f49bfa2eae9 100644 --- a/pandas/tests/frame/test_axis_select_reindex.py +++ b/pandas/tests/frame/test_axis_select_reindex.py @@ -117,6 +117,14 @@ def test_drop(self): df.drop(labels=df[df.b > 0].index, inplace=True) assert_frame_equal(df, expected) + # Empty DatetimeIndex/list, GH 27994 + df_index = pd.DataFrame( + {"a": [0, 1]}, + index=[pd.Timestamp("2019-01-01"), pd.Timestamp("2019-01-01")], + ) + assert_frame_equal(df_index.drop([]), df_index) + assert_frame_equal(df_index.drop(df_index[df_index["a"] > 2].index), df_index) + def test_drop_multiindex_not_lexsorted(self): # GH 11640 From 36d19f7c5748e2511fa896049b4b998a9df3ef8b Mon Sep 17 00:00:00 2001 From: Katsuya Horiuchi Date: Fri, 23 Aug 2019 22:46:11 +0900 Subject: [PATCH 2/5] DOC: Update whatsnew --- doc/source/whatsnew/v0.25.2.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.25.2.rst b/doc/source/whatsnew/v0.25.2.rst index 76473405374e8..3bf3833e9b101 100644 --- a/doc/source/whatsnew/v0.25.2.rst +++ b/doc/source/whatsnew/v0.25.2.rst @@ -99,7 +99,7 @@ Sparse Other ^^^^^ -- +- Bug in :meth:`DataFrame.drop` when passing empty :meth:`DatetimeIndex` or :meth:`list` - .. _whatsnew_0.252.contributors: From f32ed62a76d2c05065b7ef731db1ce26e62ed251 Mon Sep 17 00:00:00 2001 From: Katsuya Horiuchi Date: Sat, 24 Aug 2019 09:48:19 +0900 Subject: [PATCH 3/5] Small changes for PR #28114 * Make separate change * Fix whatsnew * Use is_list_like --- doc/source/whatsnew/v0.25.2.rst | 2 +- pandas/core/generic.py | 2 +- pandas/tests/frame/test_axis_select_reindex.py | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/source/whatsnew/v0.25.2.rst b/doc/source/whatsnew/v0.25.2.rst index 3bf3833e9b101..9a8a820f64419 100644 --- a/doc/source/whatsnew/v0.25.2.rst +++ b/doc/source/whatsnew/v0.25.2.rst @@ -99,7 +99,7 @@ Sparse Other ^^^^^ -- Bug in :meth:`DataFrame.drop` when passing empty :meth:`DatetimeIndex` or :meth:`list` +- Bug in :meth:`DataFrame.drop` when passing empty :meth:`DatetimeIndex` or `list` - .. _whatsnew_0.252.contributors: diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 80958245a4e31..f6638f9d91719 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -3888,7 +3888,7 @@ def drop( for axis, labels in axes.items(): if labels is not None: - if isinstance(labels, (list, Index)) and len(labels) == 0: + if is_list_like(labels) and not len(labels): continue obj = obj._drop_axis(labels, axis, level=level, errors=errors) diff --git a/pandas/tests/frame/test_axis_select_reindex.py b/pandas/tests/frame/test_axis_select_reindex.py index 54f49bfa2eae9..a2e3ca09c8dc0 100644 --- a/pandas/tests/frame/test_axis_select_reindex.py +++ b/pandas/tests/frame/test_axis_select_reindex.py @@ -117,13 +117,15 @@ def test_drop(self): df.drop(labels=df[df.b > 0].index, inplace=True) assert_frame_equal(df, expected) - # Empty DatetimeIndex/list, GH 27994 + def test_drop_empty_index(self): + # GH 27994 df_index = pd.DataFrame( {"a": [0, 1]}, index=[pd.Timestamp("2019-01-01"), pd.Timestamp("2019-01-01")], ) assert_frame_equal(df_index.drop([]), df_index) - assert_frame_equal(df_index.drop(df_index[df_index["a"] > 2].index), df_index) + assert_frame_equal(df_index.drop(np.array([])), df_index) + assert_frame_equal(df_index.drop(df_index[:0]), df_index) def test_drop_multiindex_not_lexsorted(self): # GH 11640 From 02bb501eedbca2cbd3a260adc7f4c2b60aead893 Mon Sep 17 00:00:00 2001 From: Katsuya Horiuchi Date: Sat, 31 Aug 2019 23:30:04 +0900 Subject: [PATCH 4/5] Raise KeyError when passing str to DataFrame.drop * Handle str passed to DataFrame.drop() when dataframe has DatetimeIndex * Add comments * Fix whatsnew --- doc/source/whatsnew/v1.0.0.rst | 2 +- pandas/core/generic.py | 1 + pandas/core/indexes/base.py | 4 ++++ pandas/tests/frame/test_axis_select_reindex.py | 10 ++++++++++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index 4ee9878c0b04f..d94bba67cdd6d 100644 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -208,7 +208,7 @@ Other ^^^^^ - Trying to set the ``display.precision``, ``display.max_rows`` or ``display.max_columns`` using :meth:`set_option` to anything but a ``None`` or a positive int will raise a ``ValueError`` (:issue:`23348`) - :meth:`DataFrame.to_csv` and :meth:`Series.to_csv` now support dicts as ``compression`` argument with key ``'method'`` being the compression method and others as additional compression options when the compression method is ``'zip'``. (:issue:`26023`) -- Bug in :meth:`DataFrame.drop` when passing empty :meth:`DatetimeIndex` or `list` +- Bug in :meth:`DataFrame.drop` when passing empty :class:`DatetimeIndex` or ``list`` (:issue:`27994`) .. _whatsnew_1000.contributors: diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 62f4e95cd2f4d..ab73d40dd888d 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -3915,6 +3915,7 @@ def drop( for axis, labels in axes.items(): if labels is not None: + # Check for empty Index, GH 27994 if is_list_like(labels) and not len(labels): continue obj = obj._drop_axis(labels, axis, level=level, errors=errors) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 2dbd592fc6787..9022fa9ee69e7 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -4720,6 +4720,10 @@ def get_indexer_non_unique(self, target): return pself.get_indexer_non_unique(ptarget) if self.is_all_dates: + # If `target` doesn't consist of dates, `target.asi8` will return + # None, which will raise TypeError. GH 27994 + if not target.is_all_dates: + raise KeyError("{} not found in axis".format(target.to_numpy())) tgt_values = target.asi8 else: tgt_values = target._ndarray_values diff --git a/pandas/tests/frame/test_axis_select_reindex.py b/pandas/tests/frame/test_axis_select_reindex.py index a2e3ca09c8dc0..25441fe62dd0c 100644 --- a/pandas/tests/frame/test_axis_select_reindex.py +++ b/pandas/tests/frame/test_axis_select_reindex.py @@ -127,6 +127,16 @@ def test_drop_empty_index(self): assert_frame_equal(df_index.drop(np.array([])), df_index) assert_frame_equal(df_index.drop(df_index[:0]), df_index) + @pytest.mark.parametrize("labels", ["a", ["a"]]) + def test_drop_empty_index_str(self, labels): + # Passing str to DataFrame.drop() for dataframe with DatetimeIndex + # should raise KeyError, GH 27994 + with pytest.raises(KeyError, match="not found in axis"): + pd.DataFrame( + {"a": [0, 1]}, + index=[pd.Timestamp("2019-01-01"), pd.Timestamp("2019-01-01")], + ).drop(labels) + def test_drop_multiindex_not_lexsorted(self): # GH 11640 From 25bf949ff80e4b10551a6a50afaea6d7f5c63a8e Mon Sep 17 00:00:00 2001 From: Katsuya Horiuchi Date: Wed, 4 Sep 2019 01:34:27 +0900 Subject: [PATCH 5/5] Made trivial changes for PR28114 * Move whatsnew * Change variable names & keep consistency in tests --- doc/source/whatsnew/v1.0.0.rst | 3 +-- .../tests/frame/test_axis_select_reindex.py | 22 ++++++++++++------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index d183c2976afa2..2e188ec5a9af5 100644 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -184,7 +184,7 @@ Groupby/resample/rolling Reshaping ^^^^^^^^^ -- +- Bug in :meth:`DataFrame.drop` when passing empty :class:`DatetimeIndex` or ``list`` (:issue:`27994`) - Sparse @@ -211,7 +211,6 @@ Other - Trying to set the ``display.precision``, ``display.max_rows`` or ``display.max_columns`` using :meth:`set_option` to anything but a ``None`` or a positive int will raise a ``ValueError`` (:issue:`23348`) - Using :meth:`DataFrame.replace` with overlapping keys in a nested dictionary will no longer raise, now matching the behavior of a flat dictionary (:issue:`27660`) - :meth:`DataFrame.to_csv` and :meth:`Series.to_csv` now support dicts as ``compression`` argument with key ``'method'`` being the compression method and others as additional compression options when the compression method is ``'zip'``. (:issue:`26023`) -- Bug in :meth:`DataFrame.drop` when passing empty :class:`DatetimeIndex` or ``list`` (:issue:`27994`) .. _whatsnew_1000.contributors: diff --git a/pandas/tests/frame/test_axis_select_reindex.py b/pandas/tests/frame/test_axis_select_reindex.py index 25441fe62dd0c..901cdfbe1a032 100644 --- a/pandas/tests/frame/test_axis_select_reindex.py +++ b/pandas/tests/frame/test_axis_select_reindex.py @@ -119,23 +119,29 @@ def test_drop(self): def test_drop_empty_index(self): # GH 27994 - df_index = pd.DataFrame( + df = pd.DataFrame( {"a": [0, 1]}, index=[pd.Timestamp("2019-01-01"), pd.Timestamp("2019-01-01")], ) - assert_frame_equal(df_index.drop([]), df_index) - assert_frame_equal(df_index.drop(np.array([])), df_index) - assert_frame_equal(df_index.drop(df_index[:0]), df_index) + result_empty_list = df.drop([]) + assert_frame_equal(result_empty_list, df) + + result_empty_array = df.drop(np.array([])) + assert_frame_equal(result_empty_array, df) + + result_empty_index = df.drop(df[:0]) + assert_frame_equal(result_empty_index, df) @pytest.mark.parametrize("labels", ["a", ["a"]]) def test_drop_empty_index_str(self, labels): # Passing str to DataFrame.drop() for dataframe with DatetimeIndex # should raise KeyError, GH 27994 + df = pd.DataFrame( + {"a": [0, 1]}, + index=[pd.Timestamp("2019-01-01"), pd.Timestamp("2019-01-01")], + ) with pytest.raises(KeyError, match="not found in axis"): - pd.DataFrame( - {"a": [0, 1]}, - index=[pd.Timestamp("2019-01-01"), pd.Timestamp("2019-01-01")], - ).drop(labels) + df.drop(labels) def test_drop_multiindex_not_lexsorted(self): # GH 11640