Skip to content

BUG: PeriodArray comparisons inconsistent with Period comparisons #30722

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,7 @@ Datetimelike
- Bug in :class:`DatetimeArray`, :class:`TimedeltaArray`, and :class:`PeriodArray` where inplace addition and subtraction did not actually operate inplace (:issue:`24115`)
- Bug in :func:`pandas.to_datetime` when called with ``Series`` storing ``IntegerArray`` raising ``TypeError`` instead of returning ``Series`` (:issue:`30050`)
- Bug in :func:`date_range` with custom business hours as ``freq`` and given number of ``periods`` (:issue:`30593`)
- Bug in :class:`PeriodIndex` comparisons with incorrectly casting integers to :class:`Period` objects, inconsistent with the :class:`Period` comparison behavior (:issue:`30722`)

Timedelta
^^^^^^^^^
Expand Down
6 changes: 0 additions & 6 deletions pandas/core/arrays/period.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,13 @@ def _period_array_cmp(cls, op):

@unpack_zerodim_and_defer(opname)
def wrapper(self, other):
ordinal_op = getattr(self.asi8, opname)

if isinstance(other, str):
try:
other = self._scalar_from_string(other)
except ValueError:
# string that can't be parsed as Period
return invalid_comparison(self, other, op)
elif isinstance(other, int):
# TODO: sure we want to allow this? we dont for DTA/TDA
# 2 tests rely on this
other = Period(other, freq=self.freq)
result = ordinal_op(other.ordinal)

if isinstance(other, self._recognized_scalars) or other is NaT:
other = self._scalar_type(other)
Expand Down
30 changes: 29 additions & 1 deletion pandas/tests/arithmetic/test_period.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,42 @@ def test_compare_object_dtype(self, box_with_array, other_box):
class TestPeriodIndexComparisons:
# TODO: parameterize over boxes

@pytest.mark.parametrize("other", ["2017", 2017])
@pytest.mark.parametrize("other", ["2017", pd.Period("2017", freq="D")])
def test_eq(self, other):
idx = PeriodIndex(["2017", "2017", "2018"], freq="D")
expected = np.array([True, True, False])
result = idx == other

tm.assert_numpy_array_equal(result, expected)

@pytest.mark.parametrize(
"other",
[
2017,
[2017, 2017, 2017],
np.array([2017, 2017, 2017]),
np.array([2017, 2017, 2017], dtype=object),
pd.Index([2017, 2017, 2017]),
],
)
def test_eq_integer_disallowed(self, other):
# match Period semantics by not treating integers as Periods

idx = PeriodIndex(["2017", "2017", "2018"], freq="D")
expected = np.array([False, False, False])
result = idx == other

tm.assert_numpy_array_equal(result, expected)

with pytest.raises(TypeError):
idx < other
with pytest.raises(TypeError):
idx > other
with pytest.raises(TypeError):
idx <= other
with pytest.raises(TypeError):
idx >= other

def test_pi_cmp_period(self):
idx = period_range("2007-01", periods=20, freq="M")

Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/indexes/period/test_period.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ def test_index_duplicate_periods(self):
ts = Series(np.random.randn(len(idx)), index=idx)

result = ts[2007]
expected = ts[idx == 2007]
expected = ts[idx == "2007"]
tm.assert_series_equal(result, expected)

def test_index_unique(self):
Expand Down