Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions pandas/core/arrays/masked.py
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,9 @@ def _maybe_mask_result(

return IntegerArray(result, mask, copy=False)

elif result.dtype == object:
result[mask] = self.dtype.na_value
return result
else:
result[mask] = np.nan
return result
Expand Down
5 changes: 5 additions & 0 deletions pandas/core/ops/array_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ def arithmetic_op(left: ArrayLike, right: Any, op):
# and `maybe_prepare_scalar_for_op` has already been called on `right`
# We need to special-case datetime64/timedelta64 dtypes (e.g. because numpy
# casts integer dtypes to timedelta64 when operating with timedelta64 - GH#22390)
if isinstance(right, list):
# GH#62423
right = np.array(right)
right = ensure_wrapped_if_datetimelike(right)

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

if isinstance(rvalues, (np.ndarray, ABCExtensionArray)):
# TODO: make this treatment consistent across ops and classes.
Expand Down
12 changes: 12 additions & 0 deletions pandas/core/ops/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
from functools import wraps
from typing import TYPE_CHECKING

import numpy as np

from pandas._libs.lib import item_from_zerodim
from pandas._libs.missing import is_matching_na

from pandas.core.dtypes.generic import (
ABCExtensionArray,
ABCIndex,
ABCSeries,
)
Expand Down Expand Up @@ -67,6 +70,15 @@ def new_method(self, other):

other = item_from_zerodim(other)

if isinstance(self, ABCExtensionArray):
if isinstance(other, list):
# See GH#62423
other = np.array(other)
if other.dtype.kind in "mM":
from pandas.core.construction import ensure_wrapped_if_datetimelike

other = ensure_wrapped_if_datetimelike(other)

return method(self, other)

# error: Incompatible return value type (got "Callable[[Any, Any], Any]",
Expand Down
4 changes: 0 additions & 4 deletions pandas/tests/arrays/integer/test_arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,6 @@ def test_error_invalid_values(data, all_arithmetic_operators):
]: # (data[~data.isna()] >= 0).all():
res = ops(str_ser)
expected = pd.Series(["foo" * x for x in data], index=s.index)
expected = expected.fillna(np.nan)
# TODO: doing this fillna to keep tests passing as we make
# assert_almost_equal stricter, but the expected with pd.NA seems
# more-correct than np.nan here.
tm.assert_series_equal(res, expected)
else:
with tm.external_error_raised(TypeError):
Expand Down
1 change: 1 addition & 0 deletions pandas/tests/indexes/categorical/test_category.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ def test_disallow_addsub_ops(self, func, op_name):
f"cannot perform {op_name} with this index type: CategoricalIndex",
"can only concatenate list",
rf"unsupported operand type\(s\) for [\+-]: {cat_or_list}",
"Object with dtype category cannot perform the numpy op ",
]
)
with pytest.raises(TypeError, match=msg):
Expand Down
27 changes: 7 additions & 20 deletions pandas/tests/series/test_arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import pytest

from pandas._libs import lib
from pandas.compat._optional import import_optional_dependency

import pandas as pd
from pandas import (
Expand All @@ -26,7 +25,6 @@
import pandas._testing as tm
from pandas.core import ops
from pandas.core.computation import expressions as expr
from pandas.util.version import Version


@pytest.fixture(autouse=True, params=[0, 1000000], ids=["numexpr", "python"])
Expand Down Expand Up @@ -336,36 +334,25 @@ def test_mask_div_propagate_na_for_non_na_dtype(self):
result = ser2 / ser1
tm.assert_series_equal(result, expected)

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

result = [1, None, val] + ser
tm.assert_series_equal(result, expected)

def test_add_list_to_masked_array_boolean(self, request):
def test_add_list_to_masked_array_boolean(self):
# GH#22962
ne = import_optional_dependency("numexpr", errors="ignore")
warning = (
UserWarning
if request.node.callspec.id == "numexpr"
and ne
and Version(ne.__version__) < Version("2.13.1")
else None
)
ser = Series([True, None, False], dtype="boolean")
msg = "operator is not supported by numexpr for the bool dtype"
with tm.assert_produces_warning(warning, match=msg):
result = ser + [True, None, True]
expected = Series([True, None, True], dtype="boolean")
result = ser + [True, None, True]
expected = Series([2, pd.NA, 1], dtype=object)
tm.assert_series_equal(result, expected)

with tm.assert_produces_warning(warning, match=msg):
result = [True, None, True] + ser
result = [True, None, True] + ser
tm.assert_series_equal(result, expected)


Expand Down
Loading