From 9d962ddec5f50e263a2eb793ae19a68c9c956d6a Mon Sep 17 00:00:00 2001 From: Daniel Saxton Date: Thu, 27 Aug 2020 20:19:21 -0500 Subject: [PATCH 1/5] Don't set Interval __array_priority__ --- doc/source/whatsnew/v1.1.2.rst | 1 + pandas/_libs/interval.pyx | 1 - pandas/tests/frame/methods/test_replace.py | 7 +++++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.1.2.rst b/doc/source/whatsnew/v1.1.2.rst index 9747a8ef3e71f..158d3fa81b6ea 100644 --- a/doc/source/whatsnew/v1.1.2.rst +++ b/doc/source/whatsnew/v1.1.2.rst @@ -16,6 +16,7 @@ Fixed regressions ~~~~~~~~~~~~~~~~~ - Regression in :meth:`DatetimeIndex.intersection` incorrectly raising ``AssertionError`` when intersecting against a list (:issue:`35876`) - Performance regression for :meth:`RangeIndex.format` (:issue:`35712`) +- Regression in :meth:`DataFrame.replace` where a ``TypeError`` would be raised when attempting to replace elements of type :class:`Interval` (:issue:`35931`) - diff --git a/pandas/_libs/interval.pyx b/pandas/_libs/interval.pyx index 6867e8aba7411..917aef62f59f7 100644 --- a/pandas/_libs/interval.pyx +++ b/pandas/_libs/interval.pyx @@ -299,7 +299,6 @@ cdef class Interval(IntervalMixin): True """ _typ = "interval" - __array_priority__ = 1000 cdef readonly object left """ diff --git a/pandas/tests/frame/methods/test_replace.py b/pandas/tests/frame/methods/test_replace.py index 8603bff0587b6..83dfd42ae2a6e 100644 --- a/pandas/tests/frame/methods/test_replace.py +++ b/pandas/tests/frame/methods/test_replace.py @@ -1581,3 +1581,10 @@ def test_replace_with_compiled_regex(self): result = df.replace({regex: "z"}, regex=True) expected = pd.DataFrame(["z", "b", "c"]) tm.assert_frame_equal(result, expected) + + def test_replace_intervals(self): + # https://github.com/pandas-dev/pandas/issues/35931 + df = pd.DataFrame({"a": [pd.Interval(0, 1), pd.Interval(0, 1)]}) + result = df.replace({"a": {pd.Interval(0, 1): "x"}}) + expected = pd.DataFrame({"a": ["x", "x"]}) + tm.assert_frame_equal(result, expected) From 8c93c5518c8cedeaeed32490537f0ff5afb9bb95 Mon Sep 17 00:00:00 2001 From: Daniel Saxton Date: Fri, 28 Aug 2020 10:52:18 -0500 Subject: [PATCH 2/5] Add xfailing test --- pandas/tests/scalar/interval/test_arithmetic.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pandas/tests/scalar/interval/test_arithmetic.py b/pandas/tests/scalar/interval/test_arithmetic.py index 5252f1a4d5a24..66e787b1daf1a 100644 --- a/pandas/tests/scalar/interval/test_arithmetic.py +++ b/pandas/tests/scalar/interval/test_arithmetic.py @@ -45,3 +45,15 @@ def test_numeric_interval_add_timedelta_raises(interval, delta): with pytest.raises((TypeError, ValueError), match=msg): delta + interval + + +@pytest.mark.xfail(reason="https://github.com/pandas-dev/pandas/pull/35938") +def test_timdelta_add_timestamp_interval(): + delta = np.timedelta64(0) + expected = Interval(Timestamp("2020-01-01"), Timestamp("2020-02-01")) + + result = delta + expected + assert result == expected + + result = expected + delta + assert result == expected From 5eaf357f189629230f14121b020698e0e33806af Mon Sep 17 00:00:00 2001 From: Daniel Saxton Date: Fri, 28 Aug 2020 13:35:12 -0500 Subject: [PATCH 3/5] Add array broadcast test --- pandas/tests/scalar/interval/test_interval.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pandas/tests/scalar/interval/test_interval.py b/pandas/tests/scalar/interval/test_interval.py index a0151bb9ac7bf..8ad9a2c7a9c70 100644 --- a/pandas/tests/scalar/interval/test_interval.py +++ b/pandas/tests/scalar/interval/test_interval.py @@ -2,6 +2,7 @@ import pytest from pandas import Interval, Period, Timedelta, Timestamp +import pandas._testing as tm import pandas.core.common as com @@ -267,3 +268,11 @@ def test_constructor_errors_tz(self, tz_left, tz_right): msg = "left and right must have the same time zone" with pytest.raises(error, match=msg): Interval(left, right) + + def test_equality_comparison_broadcasts_over_array(self): + # https://github.com/pandas-dev/pandas/issues/35931 + interval = Interval(0, 1) + arr = np.array([interval, interval]) + result = interval == arr + expected = np.array([True, True]) + tm.assert_numpy_array_equal(result, expected) From 4b4e4f712e98171fced7c6283bba404e90789813 Mon Sep 17 00:00:00 2001 From: Daniel Saxton Date: Sat, 29 Aug 2020 20:54:25 -0500 Subject: [PATCH 4/5] __richcmp__ --- pandas/_libs/interval.pyx | 6 ++++++ pandas/tests/scalar/interval/test_arithmetic.py | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pandas/_libs/interval.pyx b/pandas/_libs/interval.pyx index 917aef62f59f7..40bd5ad8f5a1f 100644 --- a/pandas/_libs/interval.pyx +++ b/pandas/_libs/interval.pyx @@ -299,6 +299,7 @@ cdef class Interval(IntervalMixin): True """ _typ = "interval" + __array_priority__ = 1000 cdef readonly object left """ @@ -357,6 +358,11 @@ cdef class Interval(IntervalMixin): self_tuple = (self.left, self.right, self.closed) other_tuple = (other.left, other.right, other.closed) return PyObject_RichCompare(self_tuple, other_tuple, op) + elif util.is_array(other): + return np.array( + [PyObject_RichCompare(self, x, op) for x in other], + dtype=bool, + ) return NotImplemented diff --git a/pandas/tests/scalar/interval/test_arithmetic.py b/pandas/tests/scalar/interval/test_arithmetic.py index 66e787b1daf1a..d73e2acdd1a08 100644 --- a/pandas/tests/scalar/interval/test_arithmetic.py +++ b/pandas/tests/scalar/interval/test_arithmetic.py @@ -47,7 +47,6 @@ def test_numeric_interval_add_timedelta_raises(interval, delta): delta + interval -@pytest.mark.xfail(reason="https://github.com/pandas-dev/pandas/pull/35938") def test_timdelta_add_timestamp_interval(): delta = np.timedelta64(0) expected = Interval(Timestamp("2020-01-01"), Timestamp("2020-02-01")) From 10bcf3903934d282a7f26dc97d8b1cf29d117b09 Mon Sep 17 00:00:00 2001 From: Daniel Saxton Date: Mon, 31 Aug 2020 14:02:38 -0500 Subject: [PATCH 5/5] Param over types --- pandas/tests/scalar/interval/test_arithmetic.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pandas/tests/scalar/interval/test_arithmetic.py b/pandas/tests/scalar/interval/test_arithmetic.py index d73e2acdd1a08..b4c2b448e252a 100644 --- a/pandas/tests/scalar/interval/test_arithmetic.py +++ b/pandas/tests/scalar/interval/test_arithmetic.py @@ -47,8 +47,9 @@ def test_numeric_interval_add_timedelta_raises(interval, delta): delta + interval -def test_timdelta_add_timestamp_interval(): - delta = np.timedelta64(0) +@pytest.mark.parametrize("klass", [timedelta, np.timedelta64, Timedelta]) +def test_timdelta_add_timestamp_interval(klass): + delta = klass(0) expected = Interval(Timestamp("2020-01-01"), Timestamp("2020-02-01")) result = delta + expected