Skip to content

Commit 72fa623

Browse files
DEPR: logical ops with dtype-less sequences (#58242)
* DEPR: logical ops with dtype-less sequences * Update doc/source/whatsnew/v3.0.0.rst Co-authored-by: Matthew Roeschke <[email protected]> --------- Co-authored-by: Matthew Roeschke <[email protected]>
1 parent 6e09e97 commit 72fa623

File tree

4 files changed

+30
-41
lines changed

4 files changed

+30
-41
lines changed

doc/source/whatsnew/v3.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ Removal of prior version deprecations/changes
208208
- :meth:`SeriesGroupBy.agg` no longer pins the name of the group to the input passed to the provided ``func`` (:issue:`51703`)
209209
- All arguments except ``name`` in :meth:`Index.rename` are now keyword only (:issue:`56493`)
210210
- All arguments except the first ``path``-like argument in IO writers are now keyword only (:issue:`54229`)
211+
- Disallow allowing logical operations (``||``, ``&``, ``^``) between pandas objects and dtype-less sequences (e.g. ``list``, ``tuple``); wrap the objects in :class:`Series`, :class:`Index`, or ``np.array`` first instead (:issue:`52264`)
211212
- Disallow automatic casting to object in :class:`Series` logical operations (``&``, ``^``, ``||``) between series with mismatched indexes and dtypes other than ``object`` or ``bool`` (:issue:`52538`)
212213
- Disallow calling :meth:`Series.replace` or :meth:`DataFrame.replace` without a ``value`` and with non-dict-like ``to_replace`` (:issue:`33302`)
213214
- Disallow constructing a :class:`arrays.SparseArray` with scalar data (:issue:`53039`)

pandas/core/ops/array_ops.py

+4-8
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
TYPE_CHECKING,
1313
Any,
1414
)
15-
import warnings
1615

1716
import numpy as np
1817

@@ -29,7 +28,6 @@
2928
is_supported_dtype,
3029
is_unitless,
3130
)
32-
from pandas.util._exceptions import find_stack_level
3331

3432
from pandas.core.dtypes.cast import (
3533
construct_1d_object_array_from_listlike,
@@ -424,15 +422,13 @@ def fill_bool(x, left=None):
424422
right = lib.item_from_zerodim(right)
425423
if is_list_like(right) and not hasattr(right, "dtype"):
426424
# e.g. list, tuple
427-
warnings.warn(
425+
raise TypeError(
426+
# GH#52264
428427
"Logical ops (and, or, xor) between Pandas objects and dtype-less "
429-
"sequences (e.g. list, tuple) are deprecated and will raise in a "
430-
"future version. Wrap the object in a Series, Index, or np.array "
428+
"sequences (e.g. list, tuple) are no longer supported. "
429+
"Wrap the object in a Series, Index, or np.array "
431430
"before operating instead.",
432-
FutureWarning,
433-
stacklevel=find_stack_level(),
434431
)
435-
right = construct_1d_object_array_from_listlike(right)
436432

437433
# NB: We assume extract_array has already been called on left and right
438434
lvalues = ensure_wrapped_if_datetimelike(left)

pandas/tests/series/test_arithmetic.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -807,9 +807,6 @@ def test_series_ops_name_retention(self, flex, box, names, all_binary_operators)
807807
r"Logical ops \(and, or, xor\) between Pandas objects and "
808808
"dtype-less sequences"
809809
)
810-
warn = None
811-
if box in [list, tuple] and is_logical:
812-
warn = FutureWarning
813810

814811
right = box(right)
815812
if flex:
@@ -818,9 +815,12 @@ def test_series_ops_name_retention(self, flex, box, names, all_binary_operators)
818815
return
819816
result = getattr(left, name)(right)
820817
else:
821-
# GH#37374 logical ops behaving as set ops deprecated
822-
with tm.assert_produces_warning(warn, match=msg):
823-
result = op(left, right)
818+
if is_logical and box in [list, tuple]:
819+
with pytest.raises(TypeError, match=msg):
820+
# GH#52264 logical ops with dtype-less sequences deprecated
821+
op(left, right)
822+
return
823+
result = op(left, right)
824824

825825
assert isinstance(result, Series)
826826
if box in [Index, Series]:

pandas/tests/series/test_logical_ops.py

+19-27
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def test_logical_operators_int_dtype_with_float(self):
8686
# GH#9016: support bitwise op for integer types
8787
s_0123 = Series(range(4), dtype="int64")
8888

89-
warn_msg = (
89+
err_msg = (
9090
r"Logical ops \(and, or, xor\) between Pandas objects and "
9191
"dtype-less sequences"
9292
)
@@ -97,9 +97,8 @@ def test_logical_operators_int_dtype_with_float(self):
9797
with pytest.raises(TypeError, match=msg):
9898
s_0123 & 3.14
9999
msg = "unsupported operand type.+for &:"
100-
with pytest.raises(TypeError, match=msg):
101-
with tm.assert_produces_warning(FutureWarning, match=warn_msg):
102-
s_0123 & [0.1, 4, 3.14, 2]
100+
with pytest.raises(TypeError, match=err_msg):
101+
s_0123 & [0.1, 4, 3.14, 2]
103102
with pytest.raises(TypeError, match=msg):
104103
s_0123 & np.array([0.1, 4, 3.14, 2])
105104
with pytest.raises(TypeError, match=msg):
@@ -108,17 +107,16 @@ def test_logical_operators_int_dtype_with_float(self):
108107
def test_logical_operators_int_dtype_with_str(self):
109108
s_1111 = Series([1] * 4, dtype="int8")
110109

111-
warn_msg = (
110+
err_msg = (
112111
r"Logical ops \(and, or, xor\) between Pandas objects and "
113112
"dtype-less sequences"
114113
)
115114

116115
msg = "Cannot perform 'and_' with a dtyped.+array and scalar of type"
117116
with pytest.raises(TypeError, match=msg):
118117
s_1111 & "a"
119-
with pytest.raises(TypeError, match="unsupported operand.+for &"):
120-
with tm.assert_produces_warning(FutureWarning, match=warn_msg):
121-
s_1111 & ["a", "b", "c", "d"]
118+
with pytest.raises(TypeError, match=err_msg):
119+
s_1111 & ["a", "b", "c", "d"]
122120

123121
def test_logical_operators_int_dtype_with_bool(self):
124122
# GH#9016: support bitwise op for integer types
@@ -129,17 +127,15 @@ def test_logical_operators_int_dtype_with_bool(self):
129127
result = s_0123 & False
130128
tm.assert_series_equal(result, expected)
131129

132-
warn_msg = (
130+
msg = (
133131
r"Logical ops \(and, or, xor\) between Pandas objects and "
134132
"dtype-less sequences"
135133
)
136-
with tm.assert_produces_warning(FutureWarning, match=warn_msg):
137-
result = s_0123 & [False]
138-
tm.assert_series_equal(result, expected)
134+
with pytest.raises(TypeError, match=msg):
135+
s_0123 & [False]
139136

140-
with tm.assert_produces_warning(FutureWarning, match=warn_msg):
141-
result = s_0123 & (False,)
142-
tm.assert_series_equal(result, expected)
137+
with pytest.raises(TypeError, match=msg):
138+
s_0123 & (False,)
143139

144140
result = s_0123 ^ False
145141
expected = Series([False, True, True, True])
@@ -188,9 +184,8 @@ def test_logical_ops_bool_dtype_with_ndarray(self):
188184
)
189185

190186
expected = Series([True, False, False, False, False])
191-
with tm.assert_produces_warning(FutureWarning, match=msg):
192-
result = left & right
193-
tm.assert_series_equal(result, expected)
187+
with pytest.raises(TypeError, match=msg):
188+
left & right
194189
result = left & np.array(right)
195190
tm.assert_series_equal(result, expected)
196191
result = left & Index(right)
@@ -199,9 +194,8 @@ def test_logical_ops_bool_dtype_with_ndarray(self):
199194
tm.assert_series_equal(result, expected)
200195

201196
expected = Series([True, True, True, True, True])
202-
with tm.assert_produces_warning(FutureWarning, match=msg):
203-
result = left | right
204-
tm.assert_series_equal(result, expected)
197+
with pytest.raises(TypeError, match=msg):
198+
left | right
205199
result = left | np.array(right)
206200
tm.assert_series_equal(result, expected)
207201
result = left | Index(right)
@@ -210,9 +204,8 @@ def test_logical_ops_bool_dtype_with_ndarray(self):
210204
tm.assert_series_equal(result, expected)
211205

212206
expected = Series([False, True, True, True, True])
213-
with tm.assert_produces_warning(FutureWarning, match=msg):
214-
result = left ^ right
215-
tm.assert_series_equal(result, expected)
207+
with pytest.raises(TypeError, match=msg):
208+
left ^ right
216209
result = left ^ np.array(right)
217210
tm.assert_series_equal(result, expected)
218211
result = left ^ Index(right)
@@ -269,9 +262,8 @@ def test_scalar_na_logical_ops_corners(self):
269262
r"Logical ops \(and, or, xor\) between Pandas objects and "
270263
"dtype-less sequences"
271264
)
272-
with tm.assert_produces_warning(FutureWarning, match=msg):
273-
result = s & list(s)
274-
tm.assert_series_equal(result, expected)
265+
with pytest.raises(TypeError, match=msg):
266+
s & list(s)
275267

276268
def test_scalar_na_logical_ops_corners_aligns(self):
277269
s = Series([2, 3, 4, 5, 6, 7, 8, 9, datetime(2005, 1, 1)])

0 commit comments

Comments
 (0)