From 89c375e0ff3b83a73bc01aab387505e72cb68ce3 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Mon, 15 Feb 2021 16:06:54 +0100 Subject: [PATCH 1/3] REF: call ensure_wrapped_if_datetimelike before the array arithmetic_op --- pandas/core/arrays/numpy_.py | 2 ++ pandas/core/internals/ops.py | 4 ++++ pandas/core/ops/__init__.py | 3 +++ pandas/core/ops/array_ops.py | 15 ++++++--------- pandas/core/series.py | 3 +++ 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/pandas/core/arrays/numpy_.py b/pandas/core/arrays/numpy_.py index c9db995319cdf..6e4aa1a5efacf 100644 --- a/pandas/core/arrays/numpy_.py +++ b/pandas/core/arrays/numpy_.py @@ -23,6 +23,7 @@ ) from pandas.core.arraylike import OpsMixin from pandas.core.arrays._mixins import NDArrayBackedExtensionArray +from pandas.core.construction import ensure_wrapped_if_datetimelike from pandas.core.strings.object_array import ObjectStringArrayMixin @@ -395,6 +396,7 @@ def _cmp_method(self, other, op): other = other._ndarray pd_op = ops.get_array_op(op) + other = ensure_wrapped_if_datetimelike(other) with np.errstate(all="ignore"): result = pd_op(self._ndarray, other) diff --git a/pandas/core/internals/ops.py b/pandas/core/internals/ops.py index 5f03d6709dfa4..b3ea959c7cba5 100644 --- a/pandas/core/internals/ops.py +++ b/pandas/core/internals/ops.py @@ -8,6 +8,8 @@ from pandas._typing import ArrayLike +from pandas.core.construction import ensure_wrapped_if_datetimelike + if TYPE_CHECKING: from pandas.core.internals.blocks import Block from pandas.core.internals.managers import BlockManager @@ -54,6 +56,8 @@ def operate_blockwise( res_blks: list[Block] = [] for lvals, rvals, locs, left_ea, right_ea, rblk in _iter_block_pairs(left, right): + lvals = ensure_wrapped_if_datetimelike(lvals) + rvals = ensure_wrapped_if_datetimelike(rvals) res_values = array_op(lvals, rvals) if left_ea and not right_ea and hasattr(res_values, "reshape"): res_values = res_values.reshape(1, -1) diff --git a/pandas/core/ops/__init__.py b/pandas/core/ops/__init__.py index f6bde348888a1..4ea5315aac091 100644 --- a/pandas/core/ops/__init__.py +++ b/pandas/core/ops/__init__.py @@ -29,6 +29,7 @@ algorithms, roperator, ) +from pandas.core.construction import ensure_wrapped_if_datetimelike from pandas.core.ops.array_ops import ( # noqa:F401 arithmetic_op, comp_method_OBJECT_ARRAY, @@ -140,6 +141,8 @@ def fill_binop(left, right, fill_value): right = right.copy() right[right_mask & mask] = fill_value + left = ensure_wrapped_if_datetimelike(left) + right = ensure_wrapped_if_datetimelike(right) return left, right diff --git a/pandas/core/ops/array_ops.py b/pandas/core/ops/array_ops.py index ba9da8d648597..387d8b463b8b4 100644 --- a/pandas/core/ops/array_ops.py +++ b/pandas/core/ops/array_ops.py @@ -195,20 +195,17 @@ def arithmetic_op(left: ArrayLike, right: Any, op): Or a 2-tuple of these in the case of divmod or rdivmod. """ - # NB: We assume that extract_array has already been called - # on `left` and `right`. + # NB: We assume that extract_array and ensure_wrapped_if_datetimelike + # has already been called on `left` and `right`. # We need to special-case datetime64/timedelta64 dtypes (e.g. because numpy # casts integer dtypes to timedelta64 when operating with timedelta64 - GH#22390) - lvalues = ensure_wrapped_if_datetimelike(left) - rvalues = ensure_wrapped_if_datetimelike(right) - rvalues = _maybe_upcast_for_op(rvalues, lvalues.shape) + right = _maybe_upcast_for_op(right, left.shape) - if should_extension_dispatch(lvalues, rvalues) or isinstance(rvalues, Timedelta): + if should_extension_dispatch(left, right) or isinstance(right, Timedelta): # Timedelta is included because numexpr will fail on it, see GH#31457 - res_values = op(lvalues, rvalues) - + res_values = op(left, right) else: - res_values = _na_arithmetic_op(lvalues, rvalues, op) + res_values = _na_arithmetic_op(left, right, op) return res_values diff --git a/pandas/core/series.py b/pandas/core/series.py index 440bc4c89e647..3b32f743d9710 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -100,6 +100,7 @@ import pandas.core.common as com from pandas.core.construction import ( create_series_with_explicit_dtype, + ensure_wrapped_if_datetimelike, extract_array, is_empty_data, sanitize_array, @@ -5313,6 +5314,8 @@ def _arith_method(self, other, op): lvalues = self._values rvalues = extract_array(other, extract_numpy=True, extract_range=True) + lvalues = ensure_wrapped_if_datetimelike(lvalues) + rvalues = ensure_wrapped_if_datetimelike(rvalues) with np.errstate(all="ignore"): result = ops.arithmetic_op(lvalues, rvalues, op) From b029347ac0fb51812e43d842ddeffae30b4c3db0 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Wed, 21 Apr 2021 15:18:45 +0200 Subject: [PATCH 2/3] remove unnecessary calls to ensure_wrapped_if_datetimelike --- pandas/core/internals/ops.py | 4 ---- pandas/core/series.py | 1 - 2 files changed, 5 deletions(-) diff --git a/pandas/core/internals/ops.py b/pandas/core/internals/ops.py index b3ea959c7cba5..5f03d6709dfa4 100644 --- a/pandas/core/internals/ops.py +++ b/pandas/core/internals/ops.py @@ -8,8 +8,6 @@ from pandas._typing import ArrayLike -from pandas.core.construction import ensure_wrapped_if_datetimelike - if TYPE_CHECKING: from pandas.core.internals.blocks import Block from pandas.core.internals.managers import BlockManager @@ -56,8 +54,6 @@ def operate_blockwise( res_blks: list[Block] = [] for lvals, rvals, locs, left_ea, right_ea, rblk in _iter_block_pairs(left, right): - lvals = ensure_wrapped_if_datetimelike(lvals) - rvals = ensure_wrapped_if_datetimelike(rvals) res_values = array_op(lvals, rvals) if left_ea and not right_ea and hasattr(res_values, "reshape"): res_values = res_values.reshape(1, -1) diff --git a/pandas/core/series.py b/pandas/core/series.py index bea660d424a16..de74a692b15fc 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -5314,7 +5314,6 @@ def _arith_method(self, other, op): lvalues = self._values rvalues = extract_array(other, extract_numpy=True, extract_range=True) - lvalues = ensure_wrapped_if_datetimelike(lvalues) rvalues = ensure_wrapped_if_datetimelike(rvalues) with np.errstate(all="ignore"): From 017efb2d2f5e658d5afb798af28e3429e60583e0 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Wed, 21 Apr 2021 22:23:43 +0200 Subject: [PATCH 3/3] remove from fill_binop --- pandas/core/ops/__init__.py | 3 --- pandas/core/series.py | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/pandas/core/ops/__init__.py b/pandas/core/ops/__init__.py index 4ea5315aac091..f6bde348888a1 100644 --- a/pandas/core/ops/__init__.py +++ b/pandas/core/ops/__init__.py @@ -29,7 +29,6 @@ algorithms, roperator, ) -from pandas.core.construction import ensure_wrapped_if_datetimelike from pandas.core.ops.array_ops import ( # noqa:F401 arithmetic_op, comp_method_OBJECT_ARRAY, @@ -141,8 +140,6 @@ def fill_binop(left, right, fill_value): right = right.copy() right[right_mask & mask] = fill_value - left = ensure_wrapped_if_datetimelike(left) - right = ensure_wrapped_if_datetimelike(right) return left, right diff --git a/pandas/core/series.py b/pandas/core/series.py index de74a692b15fc..85c30096b1001 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -2873,7 +2873,7 @@ def _binop(self, other: Series, func, level=None, fill_value=None): if not self.index.equals(other.index): this, other = self.align(other, level=level, join="outer", copy=False) - this_vals, other_vals = ops.fill_binop(this.values, other.values, fill_value) + this_vals, other_vals = ops.fill_binop(this._values, other._values, fill_value) with np.errstate(all="ignore"): result = func(this_vals, other_vals)