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
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.24.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,7 @@ The affected cases are:
df + arr[[0], :]

.. ipython:: python
:okwarning:

# Comparison operations and arithmetic operations both broadcast.
df == (1, 2)
Expand Down
1 change: 1 addition & 0 deletions doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,7 @@ Other Deprecations
- Deprecated using ``epoch`` date format in :meth:`DataFrame.to_json` and :meth:`Series.to_json`, use ``iso`` instead. (:issue:`57063`)
- Deprecated allowing ``fill_value`` that cannot be held in the original dtype (excepting NA values for integer and bool dtypes) in :meth:`Series.unstack` and :meth:`DataFrame.unstack` (:issue:`12189`, :issue:`53868`)
- Deprecated allowing ``fill_value`` that cannot be held in the original dtype (excepting NA values for integer and bool dtypes) in :meth:`Series.shift` and :meth:`DataFrame.shift` (:issue:`53802`)
- Deprecated arithmetic operations between pandas objects (:class:`DataFrame`, :class:`Series`, :class:`Index`, and pandas-implemented :class:`ExtensionArray` subclasses) and list-likes other than ``list``, ``np.ndarray``, :class:`ExtensionArray`, :class:`Index`, :class:`Series`, :class:`DataFrame`. For e.g. ``tuple`` or ``range``, explicitly cast these to a supported object instead. In a future version, these will be treated as scalar-like for pointwise operation (:issue:`62423`)
- Deprecated slicing on a :class:`Series` or :class:`DataFrame` with a :class:`DatetimeIndex` using a ``datetime.date`` object, explicitly cast to :class:`Timestamp` instead (:issue:`35830`)

.. ---------------------------------------------------------------------------
Expand Down
12 changes: 12 additions & 0 deletions pandas/core/arrays/arrow/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,18 @@ def _op_method_error_message(self, other, op) -> str:
)

def _evaluate_op_method(self, other, op, arrow_funcs) -> Self:
if is_list_like(other) and not isinstance(
other, (np.ndarray, ExtensionArray, list)
):
warnings.warn(
f"Operation with {type(other).__name__} are deprecated. "
"In a future version these will be treated as scalar-like. "
"To retain the old behavior, explicitly wrap in a Series "
"instead.",
Pandas4Warning,
stacklevel=find_stack_level(),
)

pa_type = self._pa_array.type
other_original = other
other = self._box_pa(other)
Expand Down
14 changes: 14 additions & 0 deletions pandas/core/arrays/boolean.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,25 @@
Self,
cast,
)
import warnings

import numpy as np

from pandas._libs import (
lib,
missing as libmissing,
)
from pandas.errors import Pandas4Warning
from pandas.util._decorators import set_module
from pandas.util._exceptions import find_stack_level

from pandas.core.dtypes.common import is_list_like
from pandas.core.dtypes.dtypes import register_extension_dtype
from pandas.core.dtypes.missing import isna

from pandas.core import ops
from pandas.core.array_algos import masked_accumulations
from pandas.core.arrays import ExtensionArray
from pandas.core.arrays.masked import (
BaseMaskedArray,
BaseMaskedDtype,
Expand Down Expand Up @@ -378,6 +382,16 @@ def _logical_method(self, other, op):
if isinstance(other, BooleanArray):
other, mask = other._data, other._mask
elif is_list_like(other):
if not isinstance(other, (list, ExtensionArray, np.ndarray)):
warnings.warn(
f"Operation with {type(other).__name__} are deprecated. "
"In a future version these will be treated as scalar-like. "
"To retain the old behavior, explicitly wrap in a Series "
"instead.",
Pandas4Warning,
stacklevel=find_stack_level(),
)

other = np.asarray(other, dtype="bool")
if other.ndim > 1:
return NotImplemented
Expand Down
12 changes: 12 additions & 0 deletions pandas/core/arrays/datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
from pandas.errors import (
AbstractMethodError,
InvalidComparison,
Pandas4Warning,
PerformanceWarning,
)
from pandas.util._decorators import (
Expand Down Expand Up @@ -968,6 +969,17 @@ def _cmp_method(self, other, op):
# TODO: handle 2D-like listlikes
return op(self.ravel(), other.ravel()).reshape(self.shape)

if is_list_like(other):
if not isinstance(other, (list, np.ndarray, ExtensionArray)):
warnings.warn(
f"Operation with {type(other).__name__} are deprecated. "
"In a future version these will be treated as scalar-like. "
"To retain the old behavior, explicitly wrap in a Series "
"instead.",
Pandas4Warning,
stacklevel=find_stack_level(),
)

try:
other = self._validate_comparison_value(other)
except InvalidComparison:
Expand Down
16 changes: 15 additions & 1 deletion pandas/core/arrays/interval.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
TypeAlias,
overload,
)
import warnings

import numpy as np

Expand All @@ -38,8 +39,12 @@
npt,
)
from pandas.compat.numpy import function as nv
from pandas.errors import IntCastingNaNError
from pandas.errors import (
IntCastingNaNError,
Pandas4Warning,
)
from pandas.util._decorators import Appender
from pandas.util._exceptions import find_stack_level

from pandas.core.dtypes.cast import (
LossySetitemError,
Expand Down Expand Up @@ -736,6 +741,15 @@ def __setitem__(self, key, value) -> None:
def _cmp_method(self, other, op):
# ensure pandas array for list-like and eliminate non-interval scalars
if is_list_like(other):
if not isinstance(other, (list, np.ndarray, ExtensionArray)):
warnings.warn(
f"Operation with {type(other).__name__} are deprecated. "
"In a future version these will be treated as scalar-like. "
"To retain the old behavior, explicitly wrap in a Series "
"instead.",
Pandas4Warning,
stacklevel=find_stack_level(),
)
if len(self) != len(other):
raise ValueError("Lengths must match to compare")
other = pd_array(other)
Expand Down
27 changes: 26 additions & 1 deletion pandas/core/arrays/masked.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@
IS64,
is_platform_windows,
)
from pandas.errors import AbstractMethodError
from pandas.errors import (
AbstractMethodError,
Pandas4Warning,
)
from pandas.util._decorators import doc
from pandas.util._exceptions import find_stack_level

from pandas.core.dtypes.base import ExtensionDtype
from pandas.core.dtypes.cast import maybe_downcast_to_dtype
Expand Down Expand Up @@ -743,6 +747,18 @@ def _arith_method(self, other, op):
op_name = op.__name__
omask = None

if is_list_like(other) and not isinstance(
other, (list, np.ndarray, ExtensionArray)
):
warnings.warn(
f"Operation with {type(other).__name__} are deprecated. "
"In a future version these will be treated as scalar-like. "
"To retain the old behavior, explicitly wrap in a Series "
"instead.",
Pandas4Warning,
stacklevel=find_stack_level(),
)

if (
not hasattr(other, "dtype")
and is_list_like(other)
Expand Down Expand Up @@ -847,6 +863,15 @@ def _cmp_method(self, other, op) -> BooleanArray:
other, mask = other._data, other._mask

elif is_list_like(other):
if not isinstance(other, (list, np.ndarray, ExtensionArray)):
warnings.warn(
f"Operation with {type(other).__name__} are deprecated. "
"In a future version these will be treated as scalar-like. "
"To retain the old behavior, explicitly wrap in a Series "
"instead.",
Pandas4Warning,
stacklevel=find_stack_level(),
)
other = np.asarray(other)
if other.ndim > 1:
raise NotImplementedError("can only perform ops with 1-d structures")
Expand Down
26 changes: 25 additions & 1 deletion pandas/core/arrays/sparse/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@
)
from pandas._libs.tslibs import NaT
from pandas.compat.numpy import function as nv
from pandas.errors import PerformanceWarning
from pandas.errors import (
Pandas4Warning,
PerformanceWarning,
)
from pandas.util._decorators import doc
from pandas.util._exceptions import find_stack_level
from pandas.util._validators import (
Expand Down Expand Up @@ -1805,6 +1808,16 @@ def _arith_method(self, other, op):
return _wrap_result(op_name, result, self.sp_index, fill)

else:
if not isinstance(other, (list, np.ndarray, ExtensionArray)):
warnings.warn(
f"Operation with {type(other).__name__} are deprecated. "
"In a future version these will be treated as scalar-like. "
"To retain the old behavior, explicitly wrap in a Series "
"instead.",
Pandas4Warning,
stacklevel=find_stack_level(),
)

other = np.asarray(other)
with np.errstate(all="ignore"):
if len(self) != len(other):
Expand All @@ -1817,6 +1830,17 @@ def _arith_method(self, other, op):
return _sparse_array_op(self, other, op, op_name)

def _cmp_method(self, other, op) -> SparseArray:
if is_list_like(other) and not isinstance(
other, (list, np.ndarray, ExtensionArray)
):
warnings.warn(
f"Operation with {type(other).__name__} are deprecated. "
"In a future version these will be treated as scalar-like. "
"To retain the old behavior, explicitly wrap in a Series "
"instead.",
Pandas4Warning,
stacklevel=find_stack_level(),
)
if not is_scalar(other) and not isinstance(other, type(self)):
# convert list-like to ndarray
other = np.asarray(other)
Expand Down
9 changes: 9 additions & 0 deletions pandas/core/arrays/string_.py
Original file line number Diff line number Diff line change
Expand Up @@ -1102,6 +1102,15 @@ def _cmp_method(self, other, op):
valid = ~mask

if lib.is_list_like(other):
if not isinstance(other, (list, ExtensionArray, np.ndarray)):
warnings.warn(
f"Operation with {type(other).__name__} are deprecated. "
"In a future version these will be treated as scalar-like. "
"To retain the old behavior, explicitly wrap in a Series "
"instead.",
Pandas4Warning,
stacklevel=find_stack_level(),
)
if len(other) != len(self):
# prevent improper broadcasting when other is 2D
raise ValueError(
Expand Down
10 changes: 10 additions & 0 deletions pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -8430,6 +8430,16 @@ def to_series(right):
)

elif is_list_like(right) and not isinstance(right, (Series, DataFrame)):
if not isinstance(right, (np.ndarray, ExtensionArray, Index, list, dict)):
warnings.warn(
f"Operation with {type(right).__name__} are deprecated. "
"In a future version these will be treated as scalar-like. "
"To retain the old behavior, explicitly wrap in a Series "
"instead.",
Pandas4Warning,
stacklevel=find_stack_level(),
)

# GH#36702. Raise when attempting arithmetic with list of array-like.
if any(is_array_like(el) for el in right):
raise ValueError(
Expand Down
9 changes: 9 additions & 0 deletions pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -6035,6 +6035,15 @@ def _flex_method(self, other, op, *, level=None, fill_value=None, axis: Axis = 0
if isinstance(other, Series):
return self._binop(other, op, level=level, fill_value=fill_value)
elif isinstance(other, (np.ndarray, list, tuple)):
if isinstance(other, tuple):
op_name = op.__name__.strip("_")
warnings.warn(
f"Series.{op_name} with a tuple is deprecated and will be "
"treated as scalar-like in a future version. "
"Explicitly wrap in a numpy array instead.",
Pandas4Warning,
stacklevel=find_stack_level(),
)
if len(other) != len(self):
raise ValueError("Lengths must be equal")
other = self._constructor(other, self.index, copy=False)
Expand Down
10 changes: 5 additions & 5 deletions pandas/tests/arithmetic/test_interval.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,19 +207,19 @@ def test_compare_list_like_interval_mixed_closed(
@pytest.mark.parametrize(
"other",
[
(
[
Interval(0, 1),
Interval(Timedelta("1 day"), Timedelta("2 days")),
Interval(4, 5, "both"),
Interval(10, 20, "neither"),
),
(0, 1.5, Timestamp("20170103"), np.nan),
(
],
[0, 1.5, Timestamp("20170103"), np.nan],
[
Timestamp("20170102", tz="US/Eastern"),
Timedelta("2 days"),
"baz",
pd.NaT,
),
],
],
)
def test_compare_list_like_object(self, op, interval_array, other):
Expand Down
10 changes: 8 additions & 2 deletions pandas/tests/arrays/test_datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,10 +306,16 @@ def test_cmp_dt64_arraylike_tznaive(self, comparison_op):
tuple(right),
right.astype(object),
]:
result = op(arr, other)
depr_msg = "Operation with tuple are deprecated."
warn = None
if isinstance(other, tuple):
warn = Pandas4Warning
with tm.assert_produces_warning(warn, match=depr_msg):
result = op(arr, other)
tm.assert_numpy_array_equal(result, expected)

result = op(other, arr)
with tm.assert_produces_warning(warn, match=depr_msg):
result = op(other, arr)
tm.assert_numpy_array_equal(result, expected)


Expand Down
1 change: 1 addition & 0 deletions pandas/tests/extension/test_numpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ def test_arith_series_with_array(self, data, all_arithmetic_operators):
self.series_array_exc = series_array_exc
super().test_arith_series_with_array(data, all_arithmetic_operators)

@skip_nested
def test_arith_frame_with_scalar(self, data, all_arithmetic_operators, request):
opname = all_arithmetic_operators
frame_scalar_exc = None
Expand Down
Loading
Loading