From 736ae02d5c53a46a6e2924e3ed615586ba77a165 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Fri, 19 Sep 2025 02:08:40 +0530 Subject: [PATCH 01/10] BUG: Raise TypeError for mismatched signed/unsigned dtypes in IntervalIndex.from_arrays --- pandas/core/indexes/interval.py | 14 ++++++++++++++ pandas/tests/indexes/interval/test_interval.py | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py index ad3278d3ec205..b139a8685fab8 100644 --- a/pandas/core/indexes/interval.py +++ b/pandas/core/indexes/interval.py @@ -310,6 +310,20 @@ def from_arrays( copy: bool = False, dtype: Dtype | None = None, ) -> IntervalIndex: + # Check for mismatched signed/unsigned integer dtypes + left_dtype = getattr(left, "dtype", None) + right_dtype = getattr(right, "dtype", None) + if ( + left_dtype is not None + and right_dtype is not None + and left_dtype.kind in "iu" + and right_dtype.kind in "iu" + and left_dtype.kind != right_dtype.kind + ): + raise TypeError( + f"Left and right arrays must have matching signedness. " + f"Got {left_dtype} and {right_dtype}." + ) with rewrite_exception("IntervalArray", cls.__name__): array = IntervalArray.from_arrays( left, right, closed, copy=copy, dtype=dtype diff --git a/pandas/tests/indexes/interval/test_interval.py b/pandas/tests/indexes/interval/test_interval.py index 006a06e529971..b302e865eebd1 100644 --- a/pandas/tests/indexes/interval/test_interval.py +++ b/pandas/tests/indexes/interval/test_interval.py @@ -882,6 +882,14 @@ def test_is_all_dates(self): assert not year_2017_index._is_all_dates +def test_from_arrays_mismatched_signedness_raises(): + # GH 55715 + left = np.array([0, 1, 2], dtype="int64") + right = np.array([1, 2, 3], dtype="uint64") + with pytest.raises(TypeError, match="matching signedness"): + IntervalIndex.from_arrays(left, right) + + def test_dir(): # GH#27571 dir(interval_index) should not raise index = IntervalIndex.from_arrays([0, 1], [1, 2]) From 439efbea17f2f6d60723a763a7d4d90eb9a9e84e Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Fri, 3 Oct 2025 19:28:21 +0530 Subject: [PATCH 02/10] BUG: Raise TypeError for mismatched signed/unsigned dtypes --- pandas/core/arrays/interval.py | 14 ++++++++++++++ pandas/core/indexes/interval.py | 14 -------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index 8d13e76c57e4f..ff1230b2e3bab 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -533,6 +533,20 @@ def from_arrays( copy: bool = False, dtype: Dtype | None = None, ) -> Self: + # Check for mismatched signed/unsigned integer dtypes + left_dtype = getattr(left, "dtype", None) + right_dtype = getattr(right, "dtype", None) + if ( + left_dtype is not None + and right_dtype is not None + and left_dtype.kind in "iu" + and right_dtype.kind in "iu" + and left_dtype.kind != right_dtype.kind + ): + raise TypeError( + f"Left and right arrays must have matching signedness. " + f"Got {left_dtype} and {right_dtype}." + ) left = _maybe_convert_platform_interval(left) right = _maybe_convert_platform_interval(right) diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py index b139a8685fab8..ad3278d3ec205 100644 --- a/pandas/core/indexes/interval.py +++ b/pandas/core/indexes/interval.py @@ -310,20 +310,6 @@ def from_arrays( copy: bool = False, dtype: Dtype | None = None, ) -> IntervalIndex: - # Check for mismatched signed/unsigned integer dtypes - left_dtype = getattr(left, "dtype", None) - right_dtype = getattr(right, "dtype", None) - if ( - left_dtype is not None - and right_dtype is not None - and left_dtype.kind in "iu" - and right_dtype.kind in "iu" - and left_dtype.kind != right_dtype.kind - ): - raise TypeError( - f"Left and right arrays must have matching signedness. " - f"Got {left_dtype} and {right_dtype}." - ) with rewrite_exception("IntervalArray", cls.__name__): array = IntervalArray.from_arrays( left, right, closed, copy=copy, dtype=dtype From ed887d9ea1caddab3dc0aa3fc31f23243ddf90b6 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Thu, 9 Oct 2025 23:36:05 +0530 Subject: [PATCH 03/10] BUG: Raise TypeError for mismatched signed/unsigned dtypes --- doc/source/whatsnew/v3.0.0.rst | 2 +- pandas/core/arrays/interval.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index f91d40c4d9ea9..09353a0436697 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -958,7 +958,7 @@ 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 :func:`interval_range` where start and end numeric types were always cast to 64 bit (:issue:`57268`) -- +- Construction of :class:`IntervalArray` and :class:`IntervalIndex` from arrays with mismatched signed/unsigned integer dtypes (e.g., ``int64`` and ``uint64``) now raises a :exc:`TypeError` instead of proceeding silently. (:issue:`55715`) Indexing ^^^^^^^^ diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index ff1230b2e3bab..0cbdd2aff9430 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -533,6 +533,9 @@ def from_arrays( copy: bool = False, dtype: Dtype | None = None, ) -> Self: + left = _maybe_convert_platform_interval(left) + right = _maybe_convert_platform_interval(right) + # Check for mismatched signed/unsigned integer dtypes left_dtype = getattr(left, "dtype", None) right_dtype = getattr(right, "dtype", None) @@ -547,8 +550,6 @@ def from_arrays( f"Left and right arrays must have matching signedness. " f"Got {left_dtype} and {right_dtype}." ) - left = _maybe_convert_platform_interval(left) - right = _maybe_convert_platform_interval(right) left, right, dtype = cls._ensure_simple_new_inputs( left, From f7433c8376b49b208f3499d683ffe8fae6096069 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Fri, 10 Oct 2025 09:04:17 +0530 Subject: [PATCH 04/10] BUG: Raise TypeError for mismatched signed/unsigned dtypes --- pandas/core/arrays/interval.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index 0cbdd2aff9430..392a3a0c0b6c1 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -537,12 +537,10 @@ def from_arrays( right = _maybe_convert_platform_interval(right) # Check for mismatched signed/unsigned integer dtypes - left_dtype = getattr(left, "dtype", None) - right_dtype = getattr(right, "dtype", None) + left_dtype = left.dtype + right_dtype = right.dtype if ( - left_dtype is not None - and right_dtype is not None - and left_dtype.kind in "iu" + left_dtype.kind in "iu" and right_dtype.kind in "iu" and left_dtype.kind != right_dtype.kind ): From 5b67c6ee0522affc93ea07a7c127e1711b3fed57 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Mon, 13 Oct 2025 09:23:35 +0530 Subject: [PATCH 05/10] Fix type-ignore --- pandas/io/excel/_xlsxwriter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/io/excel/_xlsxwriter.py b/pandas/io/excel/_xlsxwriter.py index 5874f720e3bd0..4a7b8eee2bfce 100644 --- a/pandas/io/excel/_xlsxwriter.py +++ b/pandas/io/excel/_xlsxwriter.py @@ -213,7 +213,7 @@ def __init__( # pyright: ignore[reportInconsistentConstructor] ) try: - self._book = Workbook(self._handles.handle, **engine_kwargs) # type: ignore[arg-type] + self._book = Workbook(self._handles.handle, **engine_kwargs) except TypeError: self._handles.handle.close() raise From c75bec09b00ab4ea2bb3558546fb518b20073ecb Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Mon, 13 Oct 2025 21:18:32 +0530 Subject: [PATCH 06/10] BUG: Raise TypeError for mismatched signed/unsigned dtypes --- pandas/core/arrays/interval.py | 8 ++------ pandas/tests/indexes/interval/test_interval.py | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index 392a3a0c0b6c1..54fe83f61f9fa 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -539,13 +539,9 @@ def from_arrays( # Check for mismatched signed/unsigned integer dtypes left_dtype = left.dtype right_dtype = right.dtype - if ( - left_dtype.kind in "iu" - and right_dtype.kind in "iu" - and left_dtype.kind != right_dtype.kind - ): + if left_dtype != right_dtype: raise TypeError( - f"Left and right arrays must have matching signedness. " + f"Left and right arrays must have matching dtypes. " f"Got {left_dtype} and {right_dtype}." ) diff --git a/pandas/tests/indexes/interval/test_interval.py b/pandas/tests/indexes/interval/test_interval.py index b302e865eebd1..f4fc9dddfc7fc 100644 --- a/pandas/tests/indexes/interval/test_interval.py +++ b/pandas/tests/indexes/interval/test_interval.py @@ -886,7 +886,7 @@ def test_from_arrays_mismatched_signedness_raises(): # GH 55715 left = np.array([0, 1, 2], dtype="int64") right = np.array([1, 2, 3], dtype="uint64") - with pytest.raises(TypeError, match="matching signedness"): + with pytest.raises(TypeError, match="matching dtypes"): IntervalIndex.from_arrays(left, right) From 9b6dafc4b1a642c311ab39c36d9d5e58c91db108 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Mon, 13 Oct 2025 21:49:03 +0530 Subject: [PATCH 07/10] Revert "BUG: Raise TypeError for mismatched signed/unsigned dtypes" This reverts commit c75bec09b00ab4ea2bb3558546fb518b20073ecb. --- pandas/core/arrays/interval.py | 8 ++++++-- pandas/tests/indexes/interval/test_interval.py | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index 54fe83f61f9fa..392a3a0c0b6c1 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -539,9 +539,13 @@ def from_arrays( # Check for mismatched signed/unsigned integer dtypes left_dtype = left.dtype right_dtype = right.dtype - if left_dtype != right_dtype: + if ( + left_dtype.kind in "iu" + and right_dtype.kind in "iu" + and left_dtype.kind != right_dtype.kind + ): raise TypeError( - f"Left and right arrays must have matching dtypes. " + f"Left and right arrays must have matching signedness. " f"Got {left_dtype} and {right_dtype}." ) diff --git a/pandas/tests/indexes/interval/test_interval.py b/pandas/tests/indexes/interval/test_interval.py index f4fc9dddfc7fc..b302e865eebd1 100644 --- a/pandas/tests/indexes/interval/test_interval.py +++ b/pandas/tests/indexes/interval/test_interval.py @@ -886,7 +886,7 @@ def test_from_arrays_mismatched_signedness_raises(): # GH 55715 left = np.array([0, 1, 2], dtype="int64") right = np.array([1, 2, 3], dtype="uint64") - with pytest.raises(TypeError, match="matching dtypes"): + with pytest.raises(TypeError, match="matching signedness"): IntervalIndex.from_arrays(left, right) From 2261af15a26160cdadbd4b02514b710b508455b7 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Tue, 14 Oct 2025 00:14:09 +0530 Subject: [PATCH 08/10] BUG: Raise TypeError for mismatched signed/unsigned dtypes --- pandas/core/arrays/interval.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index 392a3a0c0b6c1..221d91818a6d5 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -263,6 +263,19 @@ def __new__( dtype=dtype, ) + # Check for mismatched signed/unsigned integer dtypes after casting + left_dtype = left.dtype + right_dtype = right.dtype + if ( + left_dtype.kind in "iu" + and right_dtype.kind in "iu" + and left_dtype.kind != right_dtype.kind + ): + raise TypeError( + f"Left and right arrays must have matching signedness. " + f"Got {left_dtype} and {right_dtype}." + ) + if verify_integrity: cls._validate(left, right, dtype=dtype) @@ -536,19 +549,6 @@ def from_arrays( left = _maybe_convert_platform_interval(left) right = _maybe_convert_platform_interval(right) - # Check for mismatched signed/unsigned integer dtypes - left_dtype = left.dtype - right_dtype = right.dtype - if ( - left_dtype.kind in "iu" - and right_dtype.kind in "iu" - and left_dtype.kind != right_dtype.kind - ): - raise TypeError( - f"Left and right arrays must have matching signedness. " - f"Got {left_dtype} and {right_dtype}." - ) - left, right, dtype = cls._ensure_simple_new_inputs( left, right, From 6a6b2c49c82061290405e2abdfca4ca136545fc0 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Fri, 17 Oct 2025 05:16:23 +0530 Subject: [PATCH 09/10] BUG: Raise TypeError for mismatched signed/unsigned dtypes --- pandas/core/arrays/interval.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index 221d91818a6d5..0561aa2ea8f36 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -263,19 +263,6 @@ def __new__( dtype=dtype, ) - # Check for mismatched signed/unsigned integer dtypes after casting - left_dtype = left.dtype - right_dtype = right.dtype - if ( - left_dtype.kind in "iu" - and right_dtype.kind in "iu" - and left_dtype.kind != right_dtype.kind - ): - raise TypeError( - f"Left and right arrays must have matching signedness. " - f"Got {left_dtype} and {right_dtype}." - ) - if verify_integrity: cls._validate(left, right, dtype=dtype) @@ -394,6 +381,18 @@ def _ensure_simple_new_inputs( dtype = IntervalDtype(left.dtype, closed=closed) + # Check for mismatched signed/unsigned integer dtypes after casting + left_dtype = left.dtype + right_dtype = right.dtype + if ( + left_dtype.kind in "iu" + and right_dtype.kind in "iu" + and left_dtype.kind != right_dtype.kind + ): + raise TypeError( + f"Left and right arrays must have matching signedness. " + f"Got {left_dtype} and {right_dtype}." + ) return left, right, dtype @classmethod From eb9cfa74bed4a5a2c99e825e9524f898363719bf Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Wed, 29 Oct 2025 15:49:12 +0530 Subject: [PATCH 10/10] fix-pre-commit --- doc/source/whatsnew/v3.0.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 20f1d51e8eece..69dd8ef49c526 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -1048,8 +1048,8 @@ 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`) -- Construction of :class:`IntervalArray` and :class:`IntervalIndex` from arrays with mismatched signed/unsigned integer dtypes (e.g., ``int64`` and ``uint64``) now raises a :exc:`TypeError` instead of proceeding silently. (:issue:`55715`) - Bug in :meth:`IntervalIndex.get_indexer` and :meth:`IntervalIndex.drop` when one of the sides of the index is non-unique (:issue:`52245`) +- Construction of :class:`IntervalArray` and :class:`IntervalIndex` from arrays with mismatched signed/unsigned integer dtypes (e.g., ``int64`` and ``uint64``) now raises a :exc:`TypeError` instead of proceeding silently. (:issue:`55715`) Indexing ^^^^^^^^