Skip to content

Commit

Permalink
BUG: np.timedelta64 + Period (#44182)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbrockmendel authored Oct 28, 2021
1 parent 3152733 commit 66ce5de
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 49 deletions.
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v1.4.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ I/O

Period
^^^^^^
-
- Bug in adding a :class:`Period` object to a ``np.timedelta64`` object incorrectly raising ``TypeError`` (:issue:`44182`)
-

Plotting
Expand Down
9 changes: 8 additions & 1 deletion pandas/_libs/tslibs/period.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ cimport numpy as cnp
from cpython.object cimport (
Py_EQ,
Py_NE,
PyObject_RichCompare,
PyObject_RichCompareBool,
)
from numpy cimport (
Expand Down Expand Up @@ -1594,6 +1595,9 @@ cdef class _Period(PeriodMixin):
PeriodDtypeBase _dtype
BaseOffset freq

# higher than np.ndarray, np.matrix, np.timedelta64
__array_priority__ = 100

dayofweek = _Period.day_of_week
dayofyear = _Period.day_of_year

Expand Down Expand Up @@ -1652,7 +1656,10 @@ cdef class _Period(PeriodMixin):
return PyObject_RichCompareBool(self.ordinal, other.ordinal, op)
elif other is NaT:
return _nat_scalar_rules[op]
return NotImplemented # TODO: ndarray[object]?
elif util.is_array(other):
# in particular ndarray[object]; see test_pi_cmp_period
return np.array([PyObject_RichCompare(self, x, op) for x in other])
return NotImplemented

def __hash__(self):
return hash((self.ordinal, self.freqstr))
Expand Down
4 changes: 4 additions & 0 deletions pandas/tests/arithmetic/test_period.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@ def test_pi_cmp_period(self):
exp = idx.values < idx.values[10]
tm.assert_numpy_array_equal(result, exp)

# Tests Period.__richcmp__ against ndarray[object, ndim=2]
result = idx.values.reshape(10, 2) < idx[10]
tm.assert_numpy_array_equal(result, exp.reshape(10, 2))

# TODO: moved from test_datetime64; de-duplicate with version below
def test_parr_cmp_period_scalar2(self, box_with_array):
xbox = get_expected_box(box_with_array)
Expand Down
59 changes: 12 additions & 47 deletions pandas/tests/scalar/period/test_period.py
Original file line number Diff line number Diff line change
Expand Up @@ -1287,20 +1287,8 @@ def test_add_offset(self):
msg = "Input has different freq|Input cannot be converted to Period"
with pytest.raises(IncompatibleFrequency, match=msg):
p + o

if isinstance(o, np.timedelta64):
msg = "cannot use operands with types"
with pytest.raises(TypeError, match=msg):
o + p
else:
msg = "|".join(
[
"Input has different freq",
"Input cannot be converted to Period",
]
)
with pytest.raises(IncompatibleFrequency, match=msg):
o + p
with pytest.raises(IncompatibleFrequency, match=msg):
o + p

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

with pytest.raises(IncompatibleFrequency, match=msg):
p + o

if isinstance(o, np.timedelta64):
td_msg = "cannot use operands with types"
with pytest.raises(TypeError, match=td_msg):
o + p
else:
with pytest.raises(IncompatibleFrequency, match=msg):
o + p
with pytest.raises(IncompatibleFrequency, match=msg):
o + p

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

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

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

exp = Period("2011-03-30", freq=freq)
assert p + timedelta(-2) == exp
Expand All @@ -1385,14 +1364,8 @@ def test_add_offset(self):
]:
with pytest.raises(IncompatibleFrequency, match=msg):
p + o

if isinstance(o, np.timedelta64):
td_msg = "cannot use operands with types"
with pytest.raises(TypeError, match=td_msg):
o + p
else:
with pytest.raises(IncompatibleFrequency, match=msg):
o + p
with pytest.raises(IncompatibleFrequency, match=msg):
o + p

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

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

exp = Period("2011-04-01 11:00", freq=freq)
assert p + timedelta(minutes=120) == exp
Expand All @@ -1440,14 +1411,8 @@ def test_add_offset(self):
]:
with pytest.raises(IncompatibleFrequency, match=msg):
p + o

if isinstance(o, np.timedelta64):
td_msg = "cannot use operands with types"
with pytest.raises(TypeError, match=td_msg):
o + p
else:
with pytest.raises(IncompatibleFrequency, match=msg):
o + p
with pytest.raises(IncompatibleFrequency, match=msg):
o + p

def test_sub_offset(self):
# freq is DateOffset
Expand Down

0 comments on commit 66ce5de

Please sign in to comment.