@@ -91,7 +91,7 @@ def get_op_result_name(left, right):
91
91
name : object
92
92
Usually a string
93
93
"""
94
- # `left` is always a pd. Series when called from within ops
94
+ # `left` is always a Series when called from within ops
95
95
if isinstance (right , (ABCSeries , ABCIndexClass )):
96
96
name = _maybe_match_name (left , right )
97
97
else :
@@ -610,42 +610,6 @@ def column_op(a, b):
610
610
return result
611
611
612
612
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
-
649
613
def dispatch_to_extension_op (op , left , right ):
650
614
"""
651
615
Assume that left or right is a Series backed by an ExtensionArray,
@@ -666,13 +630,16 @@ def dispatch_to_extension_op(op, left, right):
666
630
else :
667
631
new_right = right
668
632
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
676
643
677
644
678
645
# -----------------------------------------------------------------------------
@@ -994,22 +961,22 @@ def wrapper(left, right):
994
961
)
995
962
996
963
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 )
1004
968
1005
969
elif is_extension_array_dtype (left ) or (
1006
970
is_extension_array_dtype (right ) and not is_scalar (right )
1007
971
):
1008
972
# 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 )
1010
975
1011
976
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 )
1013
980
return construct_result (left , result , index = left .index , name = res_name )
1014
981
1015
982
elif is_timedelta64_dtype (right ):
@@ -1130,28 +1097,32 @@ def wrapper(self, other, axis=None):
1130
1097
raise ValueError ("Can only compare identically-labeled Series objects" )
1131
1098
1132
1099
elif is_categorical_dtype (self ):
1133
- # Dispatch to Categorical implementation; pd. CategoricalIndex
1100
+ # Dispatch to Categorical implementation; CategoricalIndex
1134
1101
# 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 )
1136
1103
return self ._constructor (res_values , index = self .index , name = res_name )
1137
1104
1138
1105
elif is_datetime64_dtype (self ) or is_datetime64tz_dtype (self ):
1139
1106
# Dispatch to DatetimeIndex to ensure identical
1140
1107
# Series/Index behavior
1108
+ from pandas .core .arrays import DatetimeArray
1141
1109
1142
- res_values = dispatch_to_index_op (op , self , other , pd . DatetimeIndex )
1110
+ res_values = dispatch_to_extension_op (op , DatetimeArray ( self ) , other )
1143
1111
return self ._constructor (res_values , index = self .index , name = res_name )
1144
1112
1145
1113
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 )
1147
1117
return self ._constructor (res_values , index = self .index , name = res_name )
1148
1118
1149
1119
elif is_extension_array_dtype (self ) or (
1150
1120
is_extension_array_dtype (other ) and not is_scalar (other )
1151
1121
):
1152
1122
# Note: the `not is_scalar(other)` condition rules out
1153
1123
# 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 )
1155
1126
1156
1127
elif isinstance (other , ABCSeries ):
1157
1128
# By this point we have checked that self._indexed_same(other)
0 commit comments