Skip to content

Commit 66ce5de

Browse files
authored
BUG: np.timedelta64 + Period (#44182)
1 parent 3152733 commit 66ce5de

File tree

4 files changed

+25
-49
lines changed

4 files changed

+25
-49
lines changed

doc/source/whatsnew/v1.4.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ I/O
567567

568568
Period
569569
^^^^^^
570-
-
570+
- Bug in adding a :class:`Period` object to a ``np.timedelta64`` object incorrectly raising ``TypeError`` (:issue:`44182`)
571571
-
572572

573573
Plotting

pandas/_libs/tslibs/period.pyx

+8-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ cimport numpy as cnp
44
from cpython.object cimport (
55
Py_EQ,
66
Py_NE,
7+
PyObject_RichCompare,
78
PyObject_RichCompareBool,
89
)
910
from numpy cimport (
@@ -1594,6 +1595,9 @@ cdef class _Period(PeriodMixin):
15941595
PeriodDtypeBase _dtype
15951596
BaseOffset freq
15961597

1598+
# higher than np.ndarray, np.matrix, np.timedelta64
1599+
__array_priority__ = 100
1600+
15971601
dayofweek = _Period.day_of_week
15981602
dayofyear = _Period.day_of_year
15991603

@@ -1652,7 +1656,10 @@ cdef class _Period(PeriodMixin):
16521656
return PyObject_RichCompareBool(self.ordinal, other.ordinal, op)
16531657
elif other is NaT:
16541658
return _nat_scalar_rules[op]
1655-
return NotImplemented # TODO: ndarray[object]?
1659+
elif util.is_array(other):
1660+
# in particular ndarray[object]; see test_pi_cmp_period
1661+
return np.array([PyObject_RichCompare(self, x, op) for x in other])
1662+
return NotImplemented
16561663

16571664
def __hash__(self):
16581665
return hash((self.ordinal, self.freqstr))

pandas/tests/arithmetic/test_period.py

+4
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ def test_pi_cmp_period(self):
185185
exp = idx.values < idx.values[10]
186186
tm.assert_numpy_array_equal(result, exp)
187187

188+
# Tests Period.__richcmp__ against ndarray[object, ndim=2]
189+
result = idx.values.reshape(10, 2) < idx[10]
190+
tm.assert_numpy_array_equal(result, exp.reshape(10, 2))
191+
188192
# TODO: moved from test_datetime64; de-duplicate with version below
189193
def test_parr_cmp_period_scalar2(self, box_with_array):
190194
xbox = get_expected_box(box_with_array)

pandas/tests/scalar/period/test_period.py

+12-47
Original file line numberDiff line numberDiff line change
@@ -1287,20 +1287,8 @@ def test_add_offset(self):
12871287
msg = "Input has different freq|Input cannot be converted to Period"
12881288
with pytest.raises(IncompatibleFrequency, match=msg):
12891289
p + o
1290-
1291-
if isinstance(o, np.timedelta64):
1292-
msg = "cannot use operands with types"
1293-
with pytest.raises(TypeError, match=msg):
1294-
o + p
1295-
else:
1296-
msg = "|".join(
1297-
[
1298-
"Input has different freq",
1299-
"Input cannot be converted to Period",
1300-
]
1301-
)
1302-
with pytest.raises(IncompatibleFrequency, match=msg):
1303-
o + p
1290+
with pytest.raises(IncompatibleFrequency, match=msg):
1291+
o + p
13041292

13051293
for freq in ["M", "2M", "3M"]:
13061294
p = Period("2011-03", freq=freq)
@@ -1329,14 +1317,8 @@ def test_add_offset(self):
13291317

13301318
with pytest.raises(IncompatibleFrequency, match=msg):
13311319
p + o
1332-
1333-
if isinstance(o, np.timedelta64):
1334-
td_msg = "cannot use operands with types"
1335-
with pytest.raises(TypeError, match=td_msg):
1336-
o + p
1337-
else:
1338-
with pytest.raises(IncompatibleFrequency, match=msg):
1339-
o + p
1320+
with pytest.raises(IncompatibleFrequency, match=msg):
1321+
o + p
13401322

13411323
# freq is Tick
13421324
for freq in ["D", "2D", "3D"]:
@@ -1352,14 +1334,11 @@ def test_add_offset(self):
13521334

13531335
exp = Period("2011-04-03", freq=freq)
13541336
assert p + np.timedelta64(2, "D") == exp
1355-
msg = "cannot use operands with types"
1356-
with pytest.raises(TypeError, match=msg):
1357-
np.timedelta64(2, "D") + p
1337+
assert np.timedelta64(2, "D") + p == exp
13581338

13591339
exp = Period("2011-04-02", freq=freq)
13601340
assert p + np.timedelta64(3600 * 24, "s") == exp
1361-
with pytest.raises(TypeError, match=msg):
1362-
np.timedelta64(3600 * 24, "s") + p
1341+
assert np.timedelta64(3600 * 24, "s") + p == exp
13631342

13641343
exp = Period("2011-03-30", freq=freq)
13651344
assert p + timedelta(-2) == exp
@@ -1385,14 +1364,8 @@ def test_add_offset(self):
13851364
]:
13861365
with pytest.raises(IncompatibleFrequency, match=msg):
13871366
p + o
1388-
1389-
if isinstance(o, np.timedelta64):
1390-
td_msg = "cannot use operands with types"
1391-
with pytest.raises(TypeError, match=td_msg):
1392-
o + p
1393-
else:
1394-
with pytest.raises(IncompatibleFrequency, match=msg):
1395-
o + p
1367+
with pytest.raises(IncompatibleFrequency, match=msg):
1368+
o + p
13961369

13971370
for freq in ["H", "2H", "3H"]:
13981371
p = Period("2011-04-01 09:00", freq=freq)
@@ -1408,13 +1381,11 @@ def test_add_offset(self):
14081381
msg = "cannot use operands with types"
14091382
exp = Period("2011-04-01 12:00", freq=freq)
14101383
assert p + np.timedelta64(3, "h") == exp
1411-
with pytest.raises(TypeError, match=msg):
1412-
np.timedelta64(3, "h") + p
1384+
assert np.timedelta64(3, "h") + p == exp
14131385

14141386
exp = Period("2011-04-01 10:00", freq=freq)
14151387
assert p + np.timedelta64(3600, "s") == exp
1416-
with pytest.raises(TypeError, match=msg):
1417-
np.timedelta64(3600, "s") + p
1388+
assert np.timedelta64(3600, "s") + p == exp
14181389

14191390
exp = Period("2011-04-01 11:00", freq=freq)
14201391
assert p + timedelta(minutes=120) == exp
@@ -1440,14 +1411,8 @@ def test_add_offset(self):
14401411
]:
14411412
with pytest.raises(IncompatibleFrequency, match=msg):
14421413
p + o
1443-
1444-
if isinstance(o, np.timedelta64):
1445-
td_msg = "cannot use operands with types"
1446-
with pytest.raises(TypeError, match=td_msg):
1447-
o + p
1448-
else:
1449-
with pytest.raises(IncompatibleFrequency, match=msg):
1450-
o + p
1414+
with pytest.raises(IncompatibleFrequency, match=msg):
1415+
o + p
14511416

14521417
def test_sub_offset(self):
14531418
# freq is DateOffset

0 commit comments

Comments
 (0)