@@ -126,7 +126,7 @@ def na_op(x, y):
126
126
return na_op
127
127
128
128
129
- def na_arithmetic_op (left , right , op , str_rep : str ):
129
+ def na_arithmetic_op (left , right , op , str_rep : Optional [ str ], is_cmp : bool = False ):
130
130
"""
131
131
Return the result of evaluating op on the passed in values.
132
132
@@ -137,6 +137,8 @@ def na_arithmetic_op(left, right, op, str_rep: str):
137
137
left : np.ndarray
138
138
right : np.ndarray or scalar
139
139
str_rep : str or None
140
+ is_cmp : bool, default False
141
+ If this a comparison operation.
140
142
141
143
Returns
142
144
-------
@@ -151,8 +153,18 @@ def na_arithmetic_op(left, right, op, str_rep: str):
151
153
try :
152
154
result = expressions .evaluate (op , str_rep , left , right )
153
155
except TypeError :
156
+ if is_cmp :
157
+ # numexpr failed on comparison op, e.g. ndarray[float] > datetime
158
+ # In this case we do not fall back to the masked op, as that
159
+ # will handle complex numbers incorrectly, see GH#32047
160
+ raise
154
161
result = masked_arith_op (left , right , op )
155
162
163
+ if is_cmp and (is_scalar (result ) or result is NotImplemented ):
164
+ # numpy returned a scalar instead of operating element-wise
165
+ # e.g. numeric array vs str
166
+ return invalid_comparison (left , right , op )
167
+
156
168
return missing .dispatch_fill_zeros (op , left , right , result )
157
169
158
170
@@ -199,7 +211,9 @@ def arithmetic_op(left: ArrayLike, right: Any, op, str_rep: str):
199
211
return res_values
200
212
201
213
202
- def comparison_op (left : ArrayLike , right : Any , op ) -> ArrayLike :
214
+ def comparison_op (
215
+ left : ArrayLike , right : Any , op , str_rep : Optional [str ] = None ,
216
+ ) -> ArrayLike :
203
217
"""
204
218
Evaluate a comparison operation `=`, `!=`, `>=`, `>`, `<=`, or `<`.
205
219
@@ -244,16 +258,8 @@ def comparison_op(left: ArrayLike, right: Any, op) -> ArrayLike:
244
258
res_values = comp_method_OBJECT_ARRAY (op , lvalues , rvalues )
245
259
246
260
else :
247
- op_name = f"__{ op .__name__ } __"
248
- method = getattr (lvalues , op_name )
249
261
with np .errstate (all = "ignore" ):
250
- res_values = method (rvalues )
251
-
252
- if res_values is NotImplemented :
253
- res_values = invalid_comparison (lvalues , rvalues , op )
254
- if is_scalar (res_values ):
255
- typ = type (rvalues )
256
- raise TypeError (f"Could not compare { typ } type with Series" )
262
+ res_values = na_arithmetic_op (lvalues , rvalues , op , str_rep , is_cmp = True )
257
263
258
264
return res_values
259
265
@@ -380,7 +386,7 @@ def get_array_op(op, str_rep: Optional[str] = None):
380
386
"""
381
387
op_name = op .__name__ .strip ("_" )
382
388
if op_name in {"eq" , "ne" , "lt" , "le" , "gt" , "ge" }:
383
- return partial (comparison_op , op = op )
389
+ return partial (comparison_op , op = op , str_rep = str_rep )
384
390
elif op_name in {"and" , "or" , "xor" , "rand" , "ror" , "rxor" }:
385
391
return partial (logical_op , op = op )
386
392
else :
0 commit comments