Skip to content

Commit 3b1469f

Browse files
authored
CLN: avoid hasattr check in Timestamp.__richcmp__ (#34143)
1 parent 537ab5a commit 3b1469f

File tree

4 files changed

+35
-61
lines changed

4 files changed

+35
-61
lines changed

pandas/_libs/tslibs/timestamps.pyx

Lines changed: 29 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ from pandas._libs.tslibs.fields import get_start_end_field, get_date_name_field
3737
from pandas._libs.tslibs.nattype cimport NPY_NAT, c_NaT as NaT
3838
from pandas._libs.tslibs.np_datetime cimport (
3939
check_dts_bounds, npy_datetimestruct, dt64_to_dtstruct,
40-
reverse_ops, cmp_scalar,
40+
cmp_scalar,
4141
)
4242
from pandas._libs.tslibs.np_datetime import OutOfBoundsDatetime
4343
from pandas._libs.tslibs.offsets cimport to_offset
@@ -228,53 +228,40 @@ cdef class _Timestamp(ABCTimestamp):
228228
ots = other
229229
elif other is NaT:
230230
return op == Py_NE
231-
elif PyDateTime_Check(other):
232-
if self.nanosecond == 0:
231+
elif PyDateTime_Check(other) or is_datetime64_object(other):
232+
if self.nanosecond == 0 and PyDateTime_Check(other):
233233
val = self.to_pydatetime()
234234
return PyObject_RichCompareBool(val, other, op)
235235

236236
try:
237237
ots = type(self)(other)
238238
except ValueError:
239239
return self._compare_outside_nanorange(other, op)
240+
241+
elif is_array(other):
242+
# avoid recursion error GH#15183
243+
if other.dtype.kind == "M":
244+
if self.tz is None:
245+
return PyObject_RichCompare(self.asm8, other, op)
246+
raise TypeError(
247+
"Cannot compare tz-naive and tz-aware timestamps"
248+
)
249+
elif other.dtype.kind == "O":
250+
# Operate element-wise
251+
return np.array(
252+
[PyObject_RichCompare(self, x, op) for x in other],
253+
dtype=bool,
254+
)
255+
elif op == Py_NE:
256+
return np.ones(other.shape, dtype=np.bool_)
257+
elif op == Py_EQ:
258+
return np.zeros(other.shape, dtype=np.bool_)
259+
return NotImplemented
260+
240261
else:
241-
ndim = getattr(other, "ndim", -1)
242-
243-
if ndim != -1:
244-
if ndim == 0:
245-
if is_datetime64_object(other):
246-
other = type(self)(other)
247-
elif is_array(other):
248-
# zero-dim array, occurs if try comparison with
249-
# datetime64 scalar on the left hand side
250-
# Unfortunately, for datetime64 values, other.item()
251-
# incorrectly returns an integer, so we need to use
252-
# the numpy C api to extract it.
253-
other = cnp.PyArray_ToScalar(cnp.PyArray_DATA(other),
254-
other)
255-
other = type(self)(other)
256-
else:
257-
return NotImplemented
258-
elif is_array(other):
259-
# avoid recursion error GH#15183
260-
if other.dtype.kind == "M":
261-
if self.tz is None:
262-
return PyObject_RichCompare(self.asm8, other, op)
263-
raise TypeError(
264-
"Cannot compare tz-naive and tz-aware timestamps"
265-
)
266-
if other.dtype.kind == "O":
267-
# Operate element-wise
268-
return np.array(
269-
[PyObject_RichCompare(self, x, op) for x in other],
270-
dtype=bool,
271-
)
272-
return PyObject_RichCompare(np.array([self]), other, op)
273-
return PyObject_RichCompare(other, self, reverse_ops[op])
274-
else:
275-
return NotImplemented
262+
return NotImplemented
276263

277-
self._assert_tzawareness_compat(other)
264+
self._assert_tzawareness_compat(ots)
278265
return cmp_scalar(self.value, ots.value, op)
279266

280267
def __reduce_ex__(self, protocol):
@@ -314,22 +301,7 @@ cdef class _Timestamp(ABCTimestamp):
314301
datetime dtval = self.to_pydatetime()
315302

316303
self._assert_tzawareness_compat(other)
317-
318-
if self.nanosecond == 0:
319-
return PyObject_RichCompareBool(dtval, other, op)
320-
else:
321-
if op == Py_EQ:
322-
return False
323-
elif op == Py_NE:
324-
return True
325-
elif op == Py_LT:
326-
return dtval < other
327-
elif op == Py_LE:
328-
return dtval < other
329-
elif op == Py_GT:
330-
return dtval >= other
331-
elif op == Py_GE:
332-
return dtval >= other
304+
return PyObject_RichCompareBool(dtval, other, op)
333305

334306
cdef _assert_tzawareness_compat(_Timestamp self, datetime other):
335307
if self.tzinfo is None:
@@ -406,10 +378,10 @@ cdef class _Timestamp(ABCTimestamp):
406378
elif is_tick_object(other):
407379
try:
408380
nanos = other.nanos
409-
except OverflowError:
381+
except OverflowError as err:
410382
raise OverflowError(
411383
f"the add operation between {other} and {self} will overflow"
412-
)
384+
) from err
413385
result = type(self)(self.value + nanos, tz=self.tzinfo, freq=self.freq)
414386
return result
415387

pandas/tests/arithmetic/test_numeric.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ def test_df_numeric_cmp_dt64_raises(self):
6666
ts = pd.Timestamp.now()
6767
df = pd.DataFrame({"x": range(5)})
6868

69-
msg = "'[<>]' not supported between instances of 'Timestamp' and 'int'"
69+
msg = (
70+
"'[<>]' not supported between instances of 'numpy.ndarray' and 'Timestamp'"
71+
)
7072
with pytest.raises(TypeError, match=msg):
7173
df > ts
7274
with pytest.raises(TypeError, match=msg):

pandas/tests/frame/test_arithmetic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def test_timestamp_compare(self):
106106
else:
107107
msg = (
108108
"'(<|>)=?' not supported between "
109-
"instances of 'Timestamp' and 'float'"
109+
"instances of 'numpy.ndarray' and 'Timestamp'"
110110
)
111111
with pytest.raises(TypeError, match=msg):
112112
left_f(df, pd.Timestamp("20010109"))

pandas/tests/scalar/timestamp/test_comparisons.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,9 @@ def test_compare_zerodim_array(self):
211211
assert arr.ndim == 0
212212

213213
result = arr < ts
214-
assert result is True
214+
assert result is np.bool_(True)
215215
result = arr > ts
216-
assert result is False
216+
assert result is np.bool_(False)
217217

218218

219219
def test_rich_comparison_with_unsupported_type():

0 commit comments

Comments
 (0)