From 8ada79b8429aa015ab18f51cf90eacc6378ad997 Mon Sep 17 00:00:00 2001 From: Brock Date: Fri, 12 Apr 2024 14:06:03 -0700 Subject: [PATCH 1/2] DEPR: object casting in Series logical ops in non-bool cases --- doc/source/whatsnew/v3.0.0.rst | 1 + pandas/core/series.py | 17 ++++------ pandas/tests/series/test_logical_ops.py | 42 ++++++++++--------------- 3 files changed, 24 insertions(+), 36 deletions(-) diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index e05cc87d1af14..aedfbf89f8d3f 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -208,6 +208,7 @@ Removal of prior version deprecations/changes - :meth:`SeriesGroupBy.agg` no longer pins the name of the group to the input passed to the provided ``func`` (:issue:`51703`) - All arguments except ``name`` in :meth:`Index.rename` are now keyword only (:issue:`56493`) - All arguments except the first ``path``-like argument in IO writers are now keyword only (:issue:`54229`) +- Deprecating automatic casting to object in :class:`Series` logical operations (``&``, ``^``, ``||``) between series with mismatched indexes and dtypes other than ``object`` or ``bool`` (:issue:`52538`) - Disallow calling :meth:`Series.replace` or :meth:`DataFrame.replace` without a ``value`` and with non-dict-like ``to_replace`` (:issue:`33302`) - Disallow constructing a :class:`arrays.SparseArray` with scalar data (:issue:`53039`) - Disallow non-standard (``np.ndarray``, :class:`Index`, :class:`ExtensionArray`, or :class:`Series`) to :func:`isin`, :func:`unique`, :func:`factorize` (:issue:`52986`) diff --git a/pandas/core/series.py b/pandas/core/series.py index 0f796964eb56d..ab24b224b0957 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -5859,17 +5859,12 @@ def _align_for_op(self, right, align_asobject: bool = False): object, np.bool_, ): - warnings.warn( - "Operation between non boolean Series with different " - "indexes will no longer return a boolean result in " - "a future version. Cast both Series to object type " - "to maintain the prior behavior.", - FutureWarning, - stacklevel=find_stack_level(), - ) - # to keep original value's dtype for bool ops - left = left.astype(object) - right = right.astype(object) + pass + # GH#52538 no longer cast in these cases + else: + # to keep original value's dtype for bool ops + left = left.astype(object) + right = right.astype(object) left, right = left.align(right) diff --git a/pandas/tests/series/test_logical_ops.py b/pandas/tests/series/test_logical_ops.py index b76b69289b72f..dfc3309a8e449 100644 --- a/pandas/tests/series/test_logical_ops.py +++ b/pandas/tests/series/test_logical_ops.py @@ -233,26 +233,22 @@ def test_logical_operators_int_dtype_with_bool_dtype_and_reindex(self): # s_0123 will be all false now because of reindexing like s_tft expected = Series([False] * 7, index=[0, 1, 2, 3, "a", "b", "c"]) - with tm.assert_produces_warning(FutureWarning): - result = s_tft & s_0123 + result = s_tft & s_0123 tm.assert_series_equal(result, expected) - # GH 52538: Deprecate casting to object type when reindex is needed; + # GH#52538: no longer to object type when reindex is needed; # matches DataFrame behavior - expected = Series([False] * 7, index=[0, 1, 2, 3, "a", "b", "c"]) - with tm.assert_produces_warning(FutureWarning): - result = s_0123 & s_tft - tm.assert_series_equal(result, expected) + msg = r"unsupported operand type\(s\) for &: 'float' and 'bool'" + with pytest.raises(TypeError, match=msg): + s_0123 & s_tft s_a0b1c0 = Series([1], list("b")) - with tm.assert_produces_warning(FutureWarning): - res = s_tft & s_a0b1c0 + res = s_tft & s_a0b1c0 expected = s_tff.reindex(list("abc")) tm.assert_series_equal(res, expected) - with tm.assert_produces_warning(FutureWarning): - res = s_tft | s_a0b1c0 + res = s_tft | s_a0b1c0 expected = s_tft.reindex(list("abc")) tm.assert_series_equal(res, expected) @@ -405,27 +401,24 @@ def test_logical_ops_label_based(self, using_infer_string): tm.assert_series_equal(result, expected) # vs non-matching - with tm.assert_produces_warning(FutureWarning): - result = a & Series([1], ["z"]) + result = a & Series([1], ["z"]) expected = Series([False, False, False, False], list("abcz")) tm.assert_series_equal(result, expected) - with tm.assert_produces_warning(FutureWarning): - result = a | Series([1], ["z"]) + result = a | Series([1], ["z"]) expected = Series([True, True, False, False], list("abcz")) tm.assert_series_equal(result, expected) # identity # we would like s[s|e] == s to hold for any e, whether empty or not - with tm.assert_produces_warning(FutureWarning): - for e in [ - empty.copy(), - Series([1], ["z"]), - Series(np.nan, b.index), - Series(np.nan, a.index), - ]: - result = a[a | e] - tm.assert_series_equal(result, a[a]) + for e in [ + empty.copy(), + Series([1], ["z"]), + Series(np.nan, b.index), + Series(np.nan, a.index), + ]: + result = a[a | e] + tm.assert_series_equal(result, a[a]) for e in [Series(["z"])]: warn = FutureWarning if using_infer_string else None @@ -519,7 +512,6 @@ def test_logical_ops_df_compat(self): tm.assert_frame_equal(s3.to_frame() | s4.to_frame(), exp_or1.to_frame()) tm.assert_frame_equal(s4.to_frame() | s3.to_frame(), exp_or.to_frame()) - @pytest.mark.xfail(reason="Will pass once #52839 deprecation is enforced") def test_int_dtype_different_index_not_bool(self): # GH 52500 ser1 = Series([1, 2, 3], index=[10, 11, 23], name="a") From 2c726f2701f8c208b384cccad065c7f80380201f Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Fri, 12 Apr 2024 16:11:39 -0700 Subject: [PATCH 2/2] Update doc/source/whatsnew/v3.0.0.rst Co-authored-by: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> --- doc/source/whatsnew/v3.0.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index aedfbf89f8d3f..50643454bbcec 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -208,7 +208,7 @@ Removal of prior version deprecations/changes - :meth:`SeriesGroupBy.agg` no longer pins the name of the group to the input passed to the provided ``func`` (:issue:`51703`) - All arguments except ``name`` in :meth:`Index.rename` are now keyword only (:issue:`56493`) - All arguments except the first ``path``-like argument in IO writers are now keyword only (:issue:`54229`) -- Deprecating automatic casting to object in :class:`Series` logical operations (``&``, ``^``, ``||``) between series with mismatched indexes and dtypes other than ``object`` or ``bool`` (:issue:`52538`) +- Disallow automatic casting to object in :class:`Series` logical operations (``&``, ``^``, ``||``) between series with mismatched indexes and dtypes other than ``object`` or ``bool`` (:issue:`52538`) - Disallow calling :meth:`Series.replace` or :meth:`DataFrame.replace` without a ``value`` and with non-dict-like ``to_replace`` (:issue:`33302`) - Disallow constructing a :class:`arrays.SparseArray` with scalar data (:issue:`53039`) - Disallow non-standard (``np.ndarray``, :class:`Index`, :class:`ExtensionArray`, or :class:`Series`) to :func:`isin`, :func:`unique`, :func:`factorize` (:issue:`52986`)