Skip to content

Commit 6b8442b

Browse files
authored
ENH: Period comparisons with mismatched freq use py3 behavior (pandas-dev#39274)
1 parent d40d0c5 commit 6b8442b

File tree

5 files changed

+28
-26
lines changed

5 files changed

+28
-26
lines changed

doc/source/whatsnew/v1.3.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ I/O
322322

323323
Period
324324
^^^^^^
325-
325+
- Comparisons of :class:`Period` objects or :class:`Index`, :class:`Series`, or :class:`DataFrame` with mismatched ``PeriodDtype`` now behave like other mismatched-type comparisons, returning ``False`` for equals, ``True`` for not-equal, and raising ``TypeError`` for inequality checks (:issue:`??`)
326326
-
327327
-
328328

pandas/_libs/tslibs/period.pyx

+4
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,10 @@ cdef class _Period(PeriodMixin):
15471547
def __richcmp__(self, other, op):
15481548
if is_period_object(other):
15491549
if other.freq != self.freq:
1550+
if op == Py_EQ:
1551+
return False
1552+
elif op == Py_NE:
1553+
return True
15501554
msg = DIFFERENT_FREQ.format(cls=type(self).__name__,
15511555
own_freq=self.freqstr,
15521556
other_freq=other.freqstr)

pandas/core/arrays/datetimelike.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from pandas._libs import algos, lib
2222
from pandas._libs.tslibs import (
2323
BaseOffset,
24+
IncompatibleFrequency,
2425
NaT,
2526
NaTType,
2627
Period,
@@ -441,7 +442,7 @@ def _validate_comparison_value(self, other):
441442
try:
442443
# GH#18435 strings get a pass from tzawareness compat
443444
other = self._scalar_from_string(other)
444-
except ValueError:
445+
except (ValueError, IncompatibleFrequency):
445446
# failed to parse as Timestamp/Timedelta/Period
446447
raise InvalidComparison(other)
447448

@@ -451,7 +452,7 @@ def _validate_comparison_value(self, other):
451452
other = self._scalar_type(other) # type: ignore[call-arg]
452453
try:
453454
self._check_compatible_with(other)
454-
except TypeError as err:
455+
except (TypeError, IncompatibleFrequency) as err:
455456
# e.g. tzawareness mismatch
456457
raise InvalidComparison(other) from err
457458

@@ -465,7 +466,7 @@ def _validate_comparison_value(self, other):
465466
try:
466467
other = self._validate_listlike(other, allow_object=True)
467468
self._check_compatible_with(other)
468-
except TypeError as err:
469+
except (TypeError, IncompatibleFrequency) as err:
469470
if is_object_dtype(getattr(other, "dtype", None)):
470471
# We will have to operate element-wise
471472
pass

pandas/tests/arithmetic/test_period.py

+16-15
Original file line numberDiff line numberDiff line change
@@ -272,38 +272,38 @@ def test_parr_cmp_pi(self, freq, box_with_array):
272272
tm.assert_equal(base <= idx, exp)
273273

274274
@pytest.mark.parametrize("freq", ["M", "2M", "3M"])
275-
def test_parr_cmp_pi_mismatched_freq_raises(self, freq, box_with_array):
275+
def test_parr_cmp_pi_mismatched_freq(self, freq, box_with_array):
276276
# GH#13200
277277
# different base freq
278278
base = PeriodIndex(["2011-01", "2011-02", "2011-03", "2011-04"], freq=freq)
279279
base = tm.box_expected(base, box_with_array)
280280

281-
msg = "Input has different freq=A-DEC from "
282-
with pytest.raises(IncompatibleFrequency, match=msg):
281+
msg = rf"Invalid comparison between dtype=period\[{freq}\] and Period"
282+
with pytest.raises(TypeError, match=msg):
283283
base <= Period("2011", freq="A")
284284

285-
with pytest.raises(IncompatibleFrequency, match=msg):
285+
with pytest.raises(TypeError, match=msg):
286286
Period("2011", freq="A") >= base
287287

288288
# TODO: Could parametrize over boxes for idx?
289289
idx = PeriodIndex(["2011", "2012", "2013", "2014"], freq="A")
290-
rev_msg = r"Input has different freq=(M|2M|3M) from PeriodArray\(freq=A-DEC\)"
290+
rev_msg = r"Invalid comparison between dtype=period\[A-DEC\] and PeriodArray"
291291
idx_msg = rev_msg if box_with_array in [tm.to_array, pd.array] else msg
292-
with pytest.raises(IncompatibleFrequency, match=idx_msg):
292+
with pytest.raises(TypeError, match=idx_msg):
293293
base <= idx
294294

295295
# Different frequency
296-
msg = "Input has different freq=4M from "
297-
with pytest.raises(IncompatibleFrequency, match=msg):
296+
msg = rf"Invalid comparison between dtype=period\[{freq}\] and Period"
297+
with pytest.raises(TypeError, match=msg):
298298
base <= Period("2011", freq="4M")
299299

300-
with pytest.raises(IncompatibleFrequency, match=msg):
300+
with pytest.raises(TypeError, match=msg):
301301
Period("2011", freq="4M") >= base
302302

303303
idx = PeriodIndex(["2011", "2012", "2013", "2014"], freq="4M")
304-
rev_msg = r"Input has different freq=(M|2M|3M) from PeriodArray\(freq=4M\)"
304+
rev_msg = r"Invalid comparison between dtype=period\[4M\] and PeriodArray"
305305
idx_msg = rev_msg if box_with_array in [tm.to_array, pd.array] else msg
306-
with pytest.raises(IncompatibleFrequency, match=idx_msg):
306+
with pytest.raises(TypeError, match=idx_msg):
307307
base <= idx
308308

309309
@pytest.mark.parametrize("freq", ["M", "2M", "3M"])
@@ -354,12 +354,13 @@ def test_pi_cmp_nat_mismatched_freq_raises(self, freq):
354354
idx1 = PeriodIndex(["2011-01", "2011-02", "NaT", "2011-05"], freq=freq)
355355

356356
diff = PeriodIndex(["2011-02", "2011-01", "2011-04", "NaT"], freq="4M")
357-
msg = "Input has different freq=4M from Period(Array|Index)"
358-
with pytest.raises(IncompatibleFrequency, match=msg):
357+
msg = rf"Invalid comparison between dtype=period\[{freq}\] and PeriodArray"
358+
with pytest.raises(TypeError, match=msg):
359359
idx1 > diff
360360

361-
with pytest.raises(IncompatibleFrequency, match=msg):
362-
idx1 == diff
361+
result = idx1 == diff
362+
expected = np.array([False, False, False, False], dtype=bool)
363+
tm.assert_numpy_array_equal(result, expected)
363364

364365
# TODO: De-duplicate with test_pi_cmp_nat
365366
@pytest.mark.parametrize("dtype", [object, None])

pandas/tests/scalar/period/test_period.py

+3-7
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@ def test_construction(self):
3434
i4 = Period("2005", freq="M")
3535
i5 = Period("2005", freq="m")
3636

37-
msg = r"Input has different freq=M from Period\(freq=A-DEC\)"
38-
with pytest.raises(IncompatibleFrequency, match=msg):
39-
i1 != i4
37+
assert i1 != i4
4038
assert i4 == i5
4139

4240
i1 = Period.now("Q")
@@ -1071,11 +1069,9 @@ def test_comparison_mismatched_freq(self):
10711069
jan = Period("2000-01", "M")
10721070
day = Period("2012-01-01", "D")
10731071

1072+
assert not jan == day
1073+
assert jan != day
10741074
msg = r"Input has different freq=D from Period\(freq=M\)"
1075-
with pytest.raises(IncompatibleFrequency, match=msg):
1076-
jan == day
1077-
with pytest.raises(IncompatibleFrequency, match=msg):
1078-
jan != day
10791075
with pytest.raises(IncompatibleFrequency, match=msg):
10801076
jan < day
10811077
with pytest.raises(IncompatibleFrequency, match=msg):

0 commit comments

Comments
 (0)