Skip to content

Commit 6731d4b

Browse files
jbrockmendelquintusdias
authored andcommitted
REF: combine dispatch_to_index_op into dispatch_to_extension_op (pandas-dev#27747)
1 parent b088e76 commit 6731d4b

File tree

1 file changed

+29
-58
lines changed

1 file changed

+29
-58
lines changed

pandas/core/ops/__init__.py

+29-58
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def get_op_result_name(left, right):
9191
name : object
9292
Usually a string
9393
"""
94-
# `left` is always a pd.Series when called from within ops
94+
# `left` is always a Series when called from within ops
9595
if isinstance(right, (ABCSeries, ABCIndexClass)):
9696
name = _maybe_match_name(left, right)
9797
else:
@@ -610,42 +610,6 @@ def column_op(a, b):
610610
return result
611611

612612

613-
def dispatch_to_index_op(op, left, right, index_class):
614-
"""
615-
Wrap Series left in the given index_class to delegate the operation op
616-
to the index implementation. DatetimeIndex and TimedeltaIndex perform
617-
type checking, timezone handling, overflow checks, etc.
618-
619-
Parameters
620-
----------
621-
op : binary operator (operator.add, operator.sub, ...)
622-
left : Series
623-
right : object
624-
index_class : DatetimeIndex or TimedeltaIndex
625-
626-
Returns
627-
-------
628-
result : object, usually DatetimeIndex, TimedeltaIndex, or Series
629-
"""
630-
left_idx = index_class(left)
631-
632-
# avoid accidentally allowing integer add/sub. For datetime64[tz] dtypes,
633-
# left_idx may inherit a freq from a cached DatetimeIndex.
634-
# See discussion in GH#19147.
635-
if getattr(left_idx, "freq", None) is not None:
636-
left_idx = left_idx._shallow_copy(freq=None)
637-
try:
638-
result = op(left_idx, right)
639-
except NullFrequencyError:
640-
# DatetimeIndex and TimedeltaIndex with freq == None raise ValueError
641-
# on add/sub of integers (or int-like). We re-raise as a TypeError.
642-
raise TypeError(
643-
"incompatible type for a datetime/timedelta "
644-
"operation [{name}]".format(name=op.__name__)
645-
)
646-
return result
647-
648-
649613
def dispatch_to_extension_op(op, left, right):
650614
"""
651615
Assume that left or right is a Series backed by an ExtensionArray,
@@ -666,13 +630,16 @@ def dispatch_to_extension_op(op, left, right):
666630
else:
667631
new_right = right
668632

669-
res_values = op(new_left, new_right)
670-
res_name = get_op_result_name(left, right)
671-
672-
if op.__name__ in ["divmod", "rdivmod"]:
673-
return _construct_divmod_result(left, res_values, left.index, res_name)
674-
675-
return _construct_result(left, res_values, left.index, res_name)
633+
try:
634+
res_values = op(new_left, new_right)
635+
except NullFrequencyError:
636+
# DatetimeIndex and TimedeltaIndex with freq == None raise ValueError
637+
# on add/sub of integers (or int-like). We re-raise as a TypeError.
638+
raise TypeError(
639+
"incompatible type for a datetime/timedelta "
640+
"operation [{name}]".format(name=op.__name__)
641+
)
642+
return res_values
676643

677644

678645
# -----------------------------------------------------------------------------
@@ -994,22 +961,22 @@ def wrapper(left, right):
994961
)
995962

996963
elif is_datetime64_dtype(left) or is_datetime64tz_dtype(left):
997-
# Give dispatch_to_index_op a chance for tests like
998-
# test_dt64_series_add_intlike, which the index dispatching handles
999-
# specifically.
1000-
result = dispatch_to_index_op(op, left, right, pd.DatetimeIndex)
1001-
return construct_result(
1002-
left, result, index=left.index, name=res_name, dtype=result.dtype
1003-
)
964+
from pandas.core.arrays import DatetimeArray
965+
966+
result = dispatch_to_extension_op(op, DatetimeArray(left), right)
967+
return construct_result(left, result, index=left.index, name=res_name)
1004968

1005969
elif is_extension_array_dtype(left) or (
1006970
is_extension_array_dtype(right) and not is_scalar(right)
1007971
):
1008972
# GH#22378 disallow scalar to exclude e.g. "category", "Int64"
1009-
return dispatch_to_extension_op(op, left, right)
973+
result = dispatch_to_extension_op(op, left, right)
974+
return construct_result(left, result, index=left.index, name=res_name)
1010975

1011976
elif is_timedelta64_dtype(left):
1012-
result = dispatch_to_index_op(op, left, right, pd.TimedeltaIndex)
977+
from pandas.core.arrays import TimedeltaArray
978+
979+
result = dispatch_to_extension_op(op, TimedeltaArray(left), right)
1013980
return construct_result(left, result, index=left.index, name=res_name)
1014981

1015982
elif is_timedelta64_dtype(right):
@@ -1130,28 +1097,32 @@ def wrapper(self, other, axis=None):
11301097
raise ValueError("Can only compare identically-labeled Series objects")
11311098

11321099
elif is_categorical_dtype(self):
1133-
# Dispatch to Categorical implementation; pd.CategoricalIndex
1100+
# Dispatch to Categorical implementation; CategoricalIndex
11341101
# behavior is non-canonical GH#19513
1135-
res_values = dispatch_to_index_op(op, self, other, pd.Categorical)
1102+
res_values = dispatch_to_extension_op(op, self, other)
11361103
return self._constructor(res_values, index=self.index, name=res_name)
11371104

11381105
elif is_datetime64_dtype(self) or is_datetime64tz_dtype(self):
11391106
# Dispatch to DatetimeIndex to ensure identical
11401107
# Series/Index behavior
1108+
from pandas.core.arrays import DatetimeArray
11411109

1142-
res_values = dispatch_to_index_op(op, self, other, pd.DatetimeIndex)
1110+
res_values = dispatch_to_extension_op(op, DatetimeArray(self), other)
11431111
return self._constructor(res_values, index=self.index, name=res_name)
11441112

11451113
elif is_timedelta64_dtype(self):
1146-
res_values = dispatch_to_index_op(op, self, other, pd.TimedeltaIndex)
1114+
from pandas.core.arrays import TimedeltaArray
1115+
1116+
res_values = dispatch_to_extension_op(op, TimedeltaArray(self), other)
11471117
return self._constructor(res_values, index=self.index, name=res_name)
11481118

11491119
elif is_extension_array_dtype(self) or (
11501120
is_extension_array_dtype(other) and not is_scalar(other)
11511121
):
11521122
# Note: the `not is_scalar(other)` condition rules out
11531123
# e.g. other == "category"
1154-
return dispatch_to_extension_op(op, self, other)
1124+
res_values = dispatch_to_extension_op(op, self, other)
1125+
return self._constructor(res_values, index=self.index).rename(res_name)
11551126

11561127
elif isinstance(other, ABCSeries):
11571128
# By this point we have checked that self._indexed_same(other)

0 commit comments

Comments
 (0)