diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 448ceffdaa1eb..c287e80d91821 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -1016,8 +1016,8 @@ Strings Interval ^^^^^^^^ - :meth:`Index.is_monotonic_decreasing`, :meth:`Index.is_monotonic_increasing`, and :meth:`Index.is_unique` could incorrectly be ``False`` for an ``Index`` created from a slice of another ``Index``. (:issue:`57911`) +- Bug in :class:`Index`, :class:`Series`, :class:`DataFrame` constructors when given a sequence of :class:`Interval` subclass objects casting them to :class:`Interval` (:issue:`46945`) - Bug in :func:`interval_range` where start and end numeric types were always cast to 64 bit (:issue:`57268`) -- Indexing ^^^^^^^^ diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index 83a1b09f00a11..039720017aa7b 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -2255,7 +2255,8 @@ cpdef bint is_interval_array(ndarray values): for i in range(n): val = values[i] - if isinstance(val, Interval): + if type(val) is Interval: + # GH#46945 catch Interval exactly, excluding subclasses if closed is None: closed = val.closed numeric = ( diff --git a/pandas/tests/dtypes/test_inference.py b/pandas/tests/dtypes/test_inference.py index d0955912e12c8..0c9770c572823 100644 --- a/pandas/tests/dtypes/test_inference.py +++ b/pandas/tests/dtypes/test_inference.py @@ -1605,6 +1605,24 @@ def test_is_string_array(self): ) assert not lib.is_string_array(np.array([1, 2])) + def test_is_interval_array_subclass(self): + # GH#46945 + + class TimestampsInterval(Interval): + def __init__(self, left: str, right: str, closed="both") -> None: + super().__init__(Timestamp(left), Timestamp(right), closed) + + @property + def seconds(self) -> float: + return self.length.seconds + + item = TimestampsInterval("1970-01-01 00:00:00", "1970-01-01 00:00:01") + arr = np.array([item], dtype=object) + assert not lib.is_interval_array(arr) + assert lib.infer_dtype(arr) != "interval" + out = Series([item])[0] + assert isinstance(out, TimestampsInterval) + @pytest.mark.parametrize( "func", [