diff --git a/doc/source/user_guide/basics.rst b/doc/source/user_guide/basics.rst index 5c2f2410e688c..16a85ccc74b43 100644 --- a/doc/source/user_guide/basics.rst +++ b/doc/source/user_guide/basics.rst @@ -329,16 +329,6 @@ You can test if a pandas object is empty, via the :attr:`~DataFrame.empty` prope df.empty pd.DataFrame(columns=list("ABC")).empty -To evaluate single-element pandas objects in a boolean context, use the method -:meth:`~DataFrame.bool`: - -.. ipython:: python - - pd.Series([True]).bool() - pd.Series([False]).bool() - pd.DataFrame([[True]]).bool() - pd.DataFrame([[False]]).bool() - .. warning:: You might be tempted to do the following: diff --git a/doc/source/user_guide/gotchas.rst b/doc/source/user_guide/gotchas.rst index adb40e166eab4..47f1b74c0b894 100644 --- a/doc/source/user_guide/gotchas.rst +++ b/doc/source/user_guide/gotchas.rst @@ -121,16 +121,6 @@ Below is how to check if any of the values are ``True``: if pd.Series([False, True, False]).any(): print("I am any") -To evaluate single-element pandas objects in a boolean context, use the method -:meth:`~DataFrame.bool`: - -.. ipython:: python - - pd.Series([True]).bool() - pd.Series([False]).bool() - pd.DataFrame([[True]]).bool() - pd.DataFrame([[False]]).bool() - Bitwise boolean ~~~~~~~~~~~~~~~ diff --git a/doc/source/whatsnew/v0.13.0.rst b/doc/source/whatsnew/v0.13.0.rst index 8ce038200acc4..2e086f560bd53 100644 --- a/doc/source/whatsnew/v0.13.0.rst +++ b/doc/source/whatsnew/v0.13.0.rst @@ -153,12 +153,16 @@ API changes Added the ``.bool()`` method to ``NDFrame`` objects to facilitate evaluating of single-element boolean Series: - .. ipython:: python + .. code-block:: python - pd.Series([True]).bool() - pd.Series([False]).bool() - pd.DataFrame([[True]]).bool() - pd.DataFrame([[False]]).bool() + >>> pd.Series([True]).bool() + True + >>> pd.Series([False]).bool() + False + >>> pd.DataFrame([[True]]).bool() + True + >>> pd.DataFrame([[False]]).bool() + False - All non-Index NDFrames (``Series``, ``DataFrame``, ``Panel``, ``Panel4D``, ``SparsePanel``, etc.), now support the entire set of arithmetic operators diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index 69a955dc3cd9f..44188c03fcf17 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -125,6 +125,7 @@ Deprecations - Deprecated the 'axis' keyword in :meth:`.GroupBy.idxmax`, :meth:`.GroupBy.idxmin`, :meth:`.GroupBy.fillna`, :meth:`.GroupBy.take`, :meth:`.GroupBy.skew`, :meth:`.GroupBy.rank`, :meth:`.GroupBy.cumprod`, :meth:`.GroupBy.cumsum`, :meth:`.GroupBy.cummax`, :meth:`.GroupBy.cummin`, :meth:`.GroupBy.pct_change`, :meth:`GroupBy.diff`, :meth:`.GroupBy.shift`, and :meth:`DataFrameGroupBy.corrwith`; for ``axis=1`` operate on the underlying :class:`DataFrame` instead (:issue:`50405`, :issue:`51046`) - Deprecated passing a dictionary to :meth:`.SeriesGroupBy.agg`; pass a list of aggregations instead (:issue:`50684`) - Deprecated logical operations (``|``, ``&``, ``^``) between pandas objects and dtype-less sequences (e.g. ``list``, ``tuple``), wrap a sequence in a :class:`Series` or numpy array before operating instead (:issue:`51521`) +- Deprecated the methods :meth:`Series.bool` and :meth:`DataFrame.bool` (:issue:`51749`) - Deprecated :meth:`DataFrame.swapaxes` and :meth:`Series.swapaxes`, use :meth:`DataFrame.transpose` or :meth:`Series.transpose` instead (:issue:`51946`) - Deprecated parameter ``convert_type`` in :meth:`Series.apply` (:issue:`52140`) - diff --git a/pandas/conftest.py b/pandas/conftest.py index 7ede781db9018..70e1c317c2043 100644 --- a/pandas/conftest.py +++ b/pandas/conftest.py @@ -137,6 +137,11 @@ def pytest_collection_modifyitems(items, config) -> None: ignored_doctest_warnings = [ # Docstring divides by zero to show behavior difference ("missing.mask_zero_div_zero", "divide by zero encountered"), + ( + "pandas.core.generic.NDFrame.bool", + "(Series|DataFrame).bool is now deprecated and will be removed " + "in future version of pandas", + ), ] for item in items: diff --git a/pandas/core/generic.py b/pandas/core/generic.py index bb3573d148e98..52a4353dcbfac 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -1513,6 +1513,13 @@ def bool(self) -> bool_t: >>> pd.DataFrame({'col': [False]}).bool() False """ + + warnings.warn( + f"{type(self).__name__}.bool is now deprecated and will be removed " + "in future version of pandas", + FutureWarning, + stacklevel=find_stack_level(), + ) v = self.squeeze() if isinstance(v, (bool, np.bool_)): return bool(v) diff --git a/pandas/tests/generic/test_frame.py b/pandas/tests/generic/test_frame.py index 8a1e0f0923531..79f055909fdea 100644 --- a/pandas/tests/generic/test_frame.py +++ b/pandas/tests/generic/test_frame.py @@ -47,19 +47,27 @@ def test_set_axis_name_mi(self, func): def test_nonzero_single_element(self): # allow single item via bool method + msg_warn = ( + "DataFrame.bool is now deprecated and will be removed " + "in future version of pandas" + ) df = DataFrame([[True]]) - assert df.bool() + df1 = DataFrame([[False]]) + with tm.assert_produces_warning(FutureWarning, match=msg_warn): + assert df.bool() - df = DataFrame([[False]]) - assert not df.bool() + with tm.assert_produces_warning(FutureWarning, match=msg_warn): + assert not df1.bool() df = DataFrame([[False, False]]) - msg = "The truth value of a DataFrame is ambiguous" - with pytest.raises(ValueError, match=msg): - df.bool() - with pytest.raises(ValueError, match=msg): + msg_err = "The truth value of a DataFrame is ambiguous" + with pytest.raises(ValueError, match=msg_err): bool(df) + with tm.assert_produces_warning(FutureWarning, match=msg_warn): + with pytest.raises(ValueError, match=msg_err): + df.bool() + def test_metadata_propagation_indiv_groupby(self): # groupby df = DataFrame( diff --git a/pandas/tests/generic/test_generic.py b/pandas/tests/generic/test_generic.py index d23d97f43de03..acc1a8c2e1d05 100644 --- a/pandas/tests/generic/test_generic.py +++ b/pandas/tests/generic/test_generic.py @@ -451,3 +451,12 @@ def test_flags_identity(self, frame_or_series): assert obj.flags is obj.flags obj2 = obj.copy() assert obj2.flags is not obj.flags + + def test_bool_dep(self) -> None: + # GH-51749 + msg_warn = ( + "DataFrame.bool is now deprecated and will be removed " + "in future version of pandas" + ) + with tm.assert_produces_warning(FutureWarning, match=msg_warn): + DataFrame({"col": [False]}).bool() diff --git a/pandas/tests/generic/test_series.py b/pandas/tests/generic/test_series.py index 5098897f057a5..ee0a7fb77f336 100644 --- a/pandas/tests/generic/test_series.py +++ b/pandas/tests/generic/test_series.py @@ -41,11 +41,16 @@ def test_get_bool_data_preserve_dtype(self): def test_nonzero_single_element(self): # allow single item via bool method + msg_warn = ( + "Series.bool is now deprecated and will be removed " + "in future version of pandas" + ) ser = Series([True]) - assert ser.bool() - - ser = Series([False]) - assert not ser.bool() + ser1 = Series([False]) + with tm.assert_produces_warning(FutureWarning, match=msg_warn): + assert ser.bool() + with tm.assert_produces_warning(FutureWarning, match=msg_warn): + assert not ser1.bool() @pytest.mark.parametrize("data", [np.nan, pd.NaT, True, False]) def test_nonzero_single_element_raise_1(self, data): @@ -58,35 +63,46 @@ def test_nonzero_single_element_raise_1(self, data): @pytest.mark.parametrize("data", [np.nan, pd.NaT]) def test_nonzero_single_element_raise_2(self, data): + msg_warn = ( + "Series.bool is now deprecated and will be removed " + "in future version of pandas" + ) + msg_err = "bool cannot act on a non-boolean single element Series" series = Series([data]) - - msg = "bool cannot act on a non-boolean single element Series" - with pytest.raises(ValueError, match=msg): - series.bool() + with tm.assert_produces_warning(FutureWarning, match=msg_warn): + with pytest.raises(ValueError, match=msg_err): + series.bool() @pytest.mark.parametrize("data", [(True, True), (False, False)]) def test_nonzero_multiple_element_raise(self, data): # multiple bool are still an error + msg_warn = ( + "Series.bool is now deprecated and will be removed " + "in future version of pandas" + ) + msg_err = "The truth value of a Series is ambiguous" series = Series([data]) - - msg = "The truth value of a Series is ambiguous" - with pytest.raises(ValueError, match=msg): + with pytest.raises(ValueError, match=msg_err): bool(series) - with pytest.raises(ValueError, match=msg): - series.bool() + with tm.assert_produces_warning(FutureWarning, match=msg_warn): + with pytest.raises(ValueError, match=msg_err): + series.bool() @pytest.mark.parametrize("data", [1, 0, "a", 0.0]) def test_nonbool_single_element_raise(self, data): # single non-bool are an error + msg_warn = ( + "Series.bool is now deprecated and will be removed " + "in future version of pandas" + ) + msg_err1 = "The truth value of a Series is ambiguous" + msg_err2 = "bool cannot act on a non-boolean single element Series" series = Series([data]) - - msg = "The truth value of a Series is ambiguous" - with pytest.raises(ValueError, match=msg): + with pytest.raises(ValueError, match=msg_err1): bool(series) - - msg = "bool cannot act on a non-boolean single element Series" - with pytest.raises(ValueError, match=msg): - series.bool() + with tm.assert_produces_warning(FutureWarning, match=msg_warn): + with pytest.raises(ValueError, match=msg_err2): + series.bool() def test_metadata_propagation_indiv_resample(self): # resample