Skip to content

Commit d309349

Browse files
committed
REF: consistent ndarray-wrapping for lists in arithmetic ops
1 parent bd88fa0 commit d309349

File tree

5 files changed

+25
-4
lines changed

5 files changed

+25
-4
lines changed

pandas/core/arrays/masked.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,9 @@ def _maybe_mask_result(
924924

925925
return IntegerArray(result, mask, copy=False)
926926

927+
elif result.dtype == object:
928+
result[mask] = self.dtype.na_value
929+
return result
927930
else:
928931
result[mask] = np.nan
929932
return result

pandas/core/ops/array_ops.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,10 @@ def arithmetic_op(left: ArrayLike, right: Any, op):
261261
# and `maybe_prepare_scalar_for_op` has already been called on `right`
262262
# We need to special-case datetime64/timedelta64 dtypes (e.g. because numpy
263263
# casts integer dtypes to timedelta64 when operating with timedelta64 - GH#22390)
264+
if isinstance(right, list):
265+
# GH#62423
266+
right = np.array(right)
267+
right = ensure_wrapped_if_datetimelike(right)
264268

265269
if (
266270
should_extension_dispatch(left, right)
@@ -311,6 +315,7 @@ def comparison_op(left: ArrayLike, right: Any, op) -> ArrayLike:
311315
# We don't catch tuple here bc we may be comparing e.g. MultiIndex
312316
# to a tuple that represents a single entry, see test_compare_tuple_strs
313317
rvalues = np.asarray(rvalues)
318+
rvalues = ensure_wrapped_if_datetimelike(rvalues)
314319

315320
if isinstance(rvalues, (np.ndarray, ABCExtensionArray)):
316321
# TODO: make this treatment consistent across ops and classes.

pandas/core/ops/common.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
from functools import wraps
88
from typing import TYPE_CHECKING
99

10+
import numpy as np
11+
1012
from pandas._libs.lib import item_from_zerodim
1113
from pandas._libs.missing import is_matching_na
1214

1315
from pandas.core.dtypes.generic import (
16+
ABCExtensionArray,
1417
ABCIndex,
1518
ABCSeries,
1619
)
@@ -67,6 +70,15 @@ def new_method(self, other):
6770

6871
other = item_from_zerodim(other)
6972

73+
if isinstance(self, ABCExtensionArray):
74+
if isinstance(other, list):
75+
# See GH#62423
76+
other = np.array(other)
77+
if other.dtype.kind in "mM":
78+
from pandas.core.construction import ensure_wrapped_if_datetimelike
79+
80+
other = ensure_wrapped_if_datetimelike(other)
81+
7082
return method(self, other)
7183

7284
# error: Incompatible return value type (got "Callable[[Any, Any], Any]",

pandas/tests/indexes/categorical/test_category.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ def test_disallow_addsub_ops(self, func, op_name):
329329
f"cannot perform {op_name} with this index type: CategoricalIndex",
330330
"can only concatenate list",
331331
rf"unsupported operand type\(s\) for [\+-]: {cat_or_list}",
332+
"Object with dtype category cannot perform the numpy op ",
332333
]
333334
)
334335
with pytest.raises(TypeError, match=msg):

pandas/tests/series/test_arithmetic.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -335,12 +335,12 @@ def test_mask_div_propagate_na_for_non_na_dtype(self):
335335
result = ser2 / ser1
336336
tm.assert_series_equal(result, expected)
337337

338-
@pytest.mark.parametrize("val, dtype", [(3, "Int64"), (3.5, "Float64")])
339-
def test_add_list_to_masked_array(self, val, dtype):
338+
@pytest.mark.parametrize("val", [3, 3.5])
339+
def test_add_list_to_masked_array(self, val):
340340
# GH#22962
341341
ser = Series([1, None, 3], dtype="Int64")
342342
result = ser + [1, None, val]
343-
expected = Series([2, None, 3 + val], dtype=dtype)
343+
expected = Series([2, pd.NA, 3 + val], dtype=object)
344344
tm.assert_series_equal(result, expected)
345345

346346
result = [1, None, val] + ser
@@ -357,7 +357,7 @@ def test_add_list_to_masked_array_boolean(self, request):
357357
msg = "operator is not supported by numexpr for the bool dtype"
358358
with tm.assert_produces_warning(warning, match=msg):
359359
result = ser + [True, None, True]
360-
expected = Series([True, None, True], dtype="boolean")
360+
expected = Series([2, pd.NA, 1], dtype=object)
361361
tm.assert_series_equal(result, expected)
362362

363363
with tm.assert_produces_warning(warning, match=msg):

0 commit comments

Comments
 (0)