From af9d5b5fe9bb6aac7e738eb2216b9737aba6bbb1 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 28 Oct 2025 11:41:11 +0000 Subject: [PATCH 1/8] type rangeindex --- pandas-stubs/core/indexes/range.pyi | 39 ++++++++++------------------- tests/indexes/test_rangeindex.py | 18 +++++++++++++ 2 files changed, 31 insertions(+), 26 deletions(-) create mode 100644 tests/indexes/test_rangeindex.py diff --git a/pandas-stubs/core/indexes/range.pyi b/pandas-stubs/core/indexes/range.pyi index 781123313..078d052a5 100644 --- a/pandas-stubs/core/indexes/range.pyi +++ b/pandas-stubs/core/indexes/range.pyi @@ -16,6 +16,7 @@ from pandas.core.indexes.base import ( from typing_extensions import Self from pandas._typing import ( + Dtype, HashableT, MaskType, np_1darray, @@ -25,16 +26,17 @@ from pandas._typing import ( class RangeIndex(_IndexSubclassBase[int, np.int64]): def __new__( cls, - start: int | RangeIndex | range = ..., - stop: int = ..., - step: int = ..., - dtype=..., - copy: bool = ..., - name: Hashable = ..., + start: int | RangeIndex | range | None = None, + stop: int | None = None, + step: int | None = None, + dtype: Dtype | None = None, + copy: bool = False, + name: Hashable | None = None, ): ... @classmethod - def from_range(cls, data, name: Hashable = ..., dtype=...) -> Self: ... - def __reduce__(self): ... + def from_range( + cls, data: range, name: Hashable | None = None, dtype: Dtype | None = None + ) -> Self: ... @property def start(self) -> int: ... @property @@ -55,29 +57,14 @@ class RangeIndex(_IndexSubclassBase[int, np.int64]): @property def has_duplicates(self) -> bool: ... def __contains__(self, key: int | np.integer) -> bool: ... - @final - def get_indexer(self, target, method=..., limit=..., tolerance=...): ... - def tolist(self): ... - def min(self, axis=..., skipna: bool = ..., *args: Any, **kwargs: Any): ... - def max(self, axis=..., skipna: bool = ..., *args: Any, **kwargs: Any): ... - def argsort(self, *args: Any, **kwargs: Any): ... def factorize( self, sort: bool = False, use_na_sentinel: bool = True ) -> tuple[np_1darray[np.intp], RangeIndex]: ... - def equals(self, other): ... - @final - def join( - self, - other, - *, - how: str = ..., - level=..., - return_indexers: bool = ..., - sort: bool = ..., - ): ... @property def size(self) -> int: ... - def __floordiv__(self, other): ... + def __floordiv__( + self, other: float | Sequence[float] | Index[int] | Index[float] + ) -> Index[int]: ... def all(self, *args: Any, **kwargs: Any) -> bool: ... def any(self, *args: Any, **kwargs: Any) -> bool: ... @final diff --git a/tests/indexes/test_rangeindex.py b/tests/indexes/test_rangeindex.py new file mode 100644 index 000000000..11104e628 --- /dev/null +++ b/tests/indexes/test_rangeindex.py @@ -0,0 +1,18 @@ +from __future__ import annotations + +import pandas as pd +from typing_extensions import ( + assert_type, +) + +from tests import ( + check, +) + + +def test_rangeindex_floordiv() -> None: + ri = pd.RangeIndex(3) + check( + assert_type(ri // 2, "pd.Index[int]"), + pd.Index, + ) From 56ba992b9d53522b6dbb9e49e64109f5db622369 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 28 Oct 2025 11:46:28 +0000 Subject: [PATCH 2/8] add tests --- tests/indexes/test_rangeindex.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/indexes/test_rangeindex.py b/tests/indexes/test_rangeindex.py index 11104e628..a5aafc548 100644 --- a/tests/indexes/test_rangeindex.py +++ b/tests/indexes/test_rangeindex.py @@ -16,3 +16,31 @@ def test_rangeindex_floordiv() -> None: assert_type(ri // 2, "pd.Index[int]"), pd.Index, ) + + +def test_rangeindex_min_max() -> None: + ri = pd.RangeIndex(3) + check( + assert_type(ri.min(), int), + int, + ) + check( + assert_type(ri.max(axis=0), int), + int, + ) + + +def test_rangeindex_equals() -> None: + ri = pd.RangeIndex(3) + check( + assert_type(ri.equals(ri), bool), + bool, + ) + + +def test_rangeindex_tolist() -> None: + ri = pd.RangeIndex(3) + check( + assert_type(ri.tolist(), list[int]), + list[int], + ) From 9023943ba6b376a25fd77e12ffcf7cb96902928a Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 28 Oct 2025 13:57:09 +0000 Subject: [PATCH 3/8] get_indexer --- pandas-stubs/core/indexes/base.pyi | 9 +++++++-- pandas-stubs/core/indexes/range.pyi | 3 ++- tests/indexes/test_rangeindex.py | 12 +++++++++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 40129638a..cfe6ff26a 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -66,6 +66,7 @@ from pandas._typing import ( S2_NSDT, T_COMPLEX, AnyAll, + AnyArrayLike, ArrayLike, AxesData, CategoryDtypeArg, @@ -418,8 +419,12 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): ) -> Self: ... def get_loc(self, key: Label) -> int | slice | np_1darray[np.bool]: ... def get_indexer( - self, target, method: ReindexMethod | None = ..., limit=..., tolerance=... - ): ... + self, + target: Index, + method: ReindexMethod | None = None, + limit: int | None = None, + tolerance: Scalar | AnyArrayLike | Sequence[Scalar] | None = None, + ) -> np_1darray[np.intp]: ... def reindex( self, target, diff --git a/pandas-stubs/core/indexes/range.pyi b/pandas-stubs/core/indexes/range.pyi index 078d052a5..c55e7f844 100644 --- a/pandas-stubs/core/indexes/range.pyi +++ b/pandas-stubs/core/indexes/range.pyi @@ -62,7 +62,8 @@ class RangeIndex(_IndexSubclassBase[int, np.int64]): ) -> tuple[np_1darray[np.intp], RangeIndex]: ... @property def size(self) -> int: ... - def __floordiv__( + # Base class returns `Self`, but for `RangeIndex` that's not true. + def __floordiv__( # type: ignore[override] self, other: float | Sequence[float] | Index[int] | Index[float] ) -> Index[int]: ... def all(self, *args: Any, **kwargs: Any) -> bool: ... diff --git a/tests/indexes/test_rangeindex.py b/tests/indexes/test_rangeindex.py index a5aafc548..8cad30156 100644 --- a/tests/indexes/test_rangeindex.py +++ b/tests/indexes/test_rangeindex.py @@ -1,5 +1,6 @@ from __future__ import annotations +import numpy as np import pandas as pd from typing_extensions import ( assert_type, @@ -7,6 +8,7 @@ from tests import ( check, + np_1darray, ) @@ -39,8 +41,16 @@ def test_rangeindex_equals() -> None: def test_rangeindex_tolist() -> None: - ri = pd.RangeIndex(3) + ri = pd.RangeIndex.from_range(range(3)) check( assert_type(ri.tolist(), list[int]), list[int], ) + + +def test_rangeindex_get_indexer() -> None: + ri = pd.RangeIndex.from_range(range(3)) + check( + assert_type(ri.get_indexer(ri), np_1darray[np.intp]), + np_1darray[np.intp], + ) From 0b831e37a5f28d8f7eeed3697085e52517baafbb Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 28 Oct 2025 14:01:33 +0000 Subject: [PATCH 4/8] argsort --- pandas-stubs/core/indexes/base.pyi | 2 +- tests/indexes/test_rangeindex.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index cfe6ff26a..917a79512 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -479,7 +479,7 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): ): ... @final def sort(self, *args: Any, **kwargs: Any) -> None: ... - def argsort(self, *args: Any, **kwargs: Any): ... + def argsort(self, *args: Any, **kwargs: Any) -> np_1darray[np.intp]: ... def get_indexer_non_unique(self, target): ... @final def get_indexer_for(self, target, **kwargs: Any): ... diff --git a/tests/indexes/test_rangeindex.py b/tests/indexes/test_rangeindex.py index 8cad30156..5056982d4 100644 --- a/tests/indexes/test_rangeindex.py +++ b/tests/indexes/test_rangeindex.py @@ -54,3 +54,11 @@ def test_rangeindex_get_indexer() -> None: assert_type(ri.get_indexer(ri), np_1darray[np.intp]), np_1darray[np.intp], ) + + +def test_rangeindex_argsort() -> None: + ri = pd.RangeIndex.from_range(range(3)) + check( + assert_type(ri.argsort(), np_1darray[np.intp]), + np_1darray[np.intp], + ) From 872dba88e723cc7aa75b07b29ce97171b969f505 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 28 Oct 2025 14:29:49 +0000 Subject: [PATCH 5/8] type join --- pandas-stubs/core/indexes/base.pyi | 24 ++++++++++++++++++------ tests/indexes/test_rangeindex.py | 15 +++++++++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 917a79512..3e036f4c4 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -79,6 +79,7 @@ from pandas._typing import ( GenericT_co, HashableT, IgnoreRaise, + JoinHow, Just, Label, Level, @@ -433,15 +434,26 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): limit=..., tolerance=..., ): ... + @overload def join( self, - other, + other: Index, *, - how: _str = ..., - level=..., - return_indexers: bool = ..., - sort: bool = ..., - ): ... + how: JoinHow = "left", + level: Level | None = None, + return_indexers: Literal[True], + sort: bool = False, + ) -> tuple[Index, np_1darray[np.intp] | None, np_1darray[np.intp] | None]: ... + @overload + def join( + self, + other: Index, + *, + how: JoinHow = "left", + level: Level | None = None, + return_indexers: Literal[False] = ..., + sort: bool = False, + ) -> Index: ... @property def values(self) -> np_1darray: ... def memory_usage(self, deep: bool = False): ... diff --git a/tests/indexes/test_rangeindex.py b/tests/indexes/test_rangeindex.py index 5056982d4..1b30e83ae 100644 --- a/tests/indexes/test_rangeindex.py +++ b/tests/indexes/test_rangeindex.py @@ -62,3 +62,18 @@ def test_rangeindex_argsort() -> None: assert_type(ri.argsort(), np_1darray[np.intp]), np_1darray[np.intp], ) + + +def test_rangeindex_join() -> None: + ri = pd.RangeIndex.from_range(range(3)) + check( + assert_type(ri.join(ri), pd.Index), + pd.Index, + ) + check( + assert_type( + ri.join(ri, return_indexers=True), + tuple[pd.Index, np_1darray[np.intp] | None, np_1darray[np.intp] | None], + ), + tuple[pd.Index, np_1darray[np.intp] | None, np_1darray[np.intp] | None], + ) From 628e123465695e18352020ad647b48b08643ff97 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 28 Oct 2025 14:30:34 +0000 Subject: [PATCH 6/8] update roof --- pyproject.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 91591a5e2..3876f5c77 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -204,10 +204,6 @@ ignore = [ "PYI042", # https://docs.astral.sh/ruff/rules/snake-case-type-alias/ "ERA001", "PLR0402", "PLC0105" ] -"*range.pyi" = [ - # TODO: remove when pandas-dev/pandas-stubs#1442 is resolved - "ANN001", "ANN201", "ANN204", "ANN206", -] "*category.pyi" = [ # TODO: remove when pandas-dev/pandas-stubs#1443 is resolved "ANN001", "ANN201", "ANN204", "ANN206", From dd98369d4e04345297177f2dd10e8c80da99f9e7 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 28 Oct 2025 14:41:50 +0000 Subject: [PATCH 7/8] consistency --- pandas-stubs/core/indexes/interval.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas-stubs/core/indexes/interval.pyi b/pandas-stubs/core/indexes/interval.pyi index 628d588ec..9007c345e 100644 --- a/pandas-stubs/core/indexes/interval.pyi +++ b/pandas-stubs/core/indexes/interval.pyi @@ -226,7 +226,7 @@ class IntervalIndex(ExtensionIndex[IntervalT, np.object_], IntervalMixin): method: FillnaOptions | Literal["nearest"] | None = ..., limit: int | None = ..., tolerance=..., - ) -> npt.NDArray[np.intp]: ... + ) -> np_1darray[np.intp]: ... def get_indexer_non_unique( self, target: Index ) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]]: ... From dfa1e1d8d9e421f025525f6b49e97c6915a05585 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Wed, 29 Oct 2025 11:34:49 +0000 Subject: [PATCH 8/8] type default --- pandas-stubs/core/indexes/base.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 3e036f4c4..25c975eff 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -451,7 +451,7 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): *, how: JoinHow = "left", level: Level | None = None, - return_indexers: Literal[False] = ..., + return_indexers: Literal[False] = False, sort: bool = False, ) -> Index: ... @property