From 05d514757991e55353b856f54b4c3454c8778859 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Mon, 24 Nov 2025 18:25:30 +0000 Subject: [PATCH 1/5] Type Index methods: `droplevel`, `__reduce__`, `isna`, `isnull`, `notna`, `notnull`, `fillna`, `memory_usage`, `__setitem__`, `equals`, `identical` --- pandas-stubs/core/indexes/base.pyi | 23 ++++++++++------------- pandas-stubs/core/indexes/multi.pyi | 1 + 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index e29561eb3..0972758f2 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -351,7 +351,7 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): Index, ]: ... @final - def is_(self, other: object) -> bool: ... + def is_(self, other: Any) -> bool: ... def __len__(self) -> int: ... def __array__( self, dtype: _str | np.dtype = ..., copy: bool | None = ... @@ -403,7 +403,7 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): @property def nlevels(self) -> int: ... def get_level_values(self, level: int | _str) -> Index: ... - def droplevel(self, level: Level | list[Level] = 0): ... + def droplevel(self, level: Level | Sequence[Level] = 0) -> Self: ... @property def is_monotonic_increasing(self) -> bool: ... @property @@ -414,16 +414,15 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): def has_duplicates(self) -> bool: ... @property def inferred_type(self) -> _str: ... - def __reduce__(self): ... @property def hasnans(self) -> bool: ... @final - def isna(self): ... - isnull = ... + def isna(self) -> Index[bool]: ... + isnull = isna @final - def notna(self): ... - notnull = ... - def fillna(self, value=...): ... + def notna(self) -> Index[bool]: ... + notnull = notna + def fillna(self, value: Scalar) -> Index: ... def dropna(self, how: AnyAll = "any") -> Self: ... def unique(self, level: Hashable | None = None) -> Self: ... def drop_duplicates(self, *, keep: DropKeep = ...) -> Self: ... @@ -489,7 +488,7 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): ) -> Index: ... @property def values(self) -> np_1darray: ... - def memory_usage(self, deep: bool = False): ... + def memory_usage(self, deep: bool = False) -> int: ... @overload def where( self, @@ -503,8 +502,6 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): other: Scalar | AnyArrayLike | None = None, ) -> Index: ... def __contains__(self, key: Hashable) -> bool: ... - @final - def __setitem__(self, key, value) -> None: ... @overload def __getitem__( self, @@ -519,9 +516,9 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): @overload def append(self, other: Index | Sequence[Index]) -> Index: ... def putmask(self, mask, value): ... - def equals(self, other: object) -> bool: ... + def equals(self, other: Any) -> bool: ... @final - def identical(self, other) -> bool: ... + def identical(self, other: Any) -> bool: ... @final def asof(self, label): ... def asof_locs(self, where, mask): ... diff --git a/pandas-stubs/core/indexes/multi.pyi b/pandas-stubs/core/indexes/multi.pyi index 544ff061a..93a2f1483 100644 --- a/pandas-stubs/core/indexes/multi.pyi +++ b/pandas-stubs/core/indexes/multi.pyi @@ -109,6 +109,7 @@ class MultiIndex(Index): def is_monotonic_decreasing(self) -> bool: ... def duplicated(self, keep: DropKeep = "first"): ... def dropna(self, how: AnyAll = "any") -> Self: ... + def droplevel(self, level: Level | Sequence[Level] = 0) -> MultiIndex | Index: ... def get_level_values(self, level: str | int) -> Index: ... def unique(self, level=...): ... def to_frame( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] From 46af28222a65fc1234037f90bef89ebafc4ace07 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Mon, 24 Nov 2025 18:40:35 +0000 Subject: [PATCH 2/5] add some droplevel tests --- tests/indexes/test_indexes.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/indexes/test_indexes.py b/tests/indexes/test_indexes.py index 45cd97fc1..3d60e748e 100644 --- a/tests/indexes/test_indexes.py +++ b/tests/indexes/test_indexes.py @@ -1526,7 +1526,6 @@ def test_datetimeindex_where() -> None: def test_index_set_names() -> None: - """Test Index.where with multiple types of other GH1419.""" idx = pd.Index([1, 2]) check( assert_type(idx.set_names("chinchilla"), "pd.Index[int]"), pd.Index, np.integer @@ -1546,3 +1545,15 @@ def test_index_set_names() -> None: ) mi = cast("pd.MultiIndex", pd.Index([(1,)])) check(assert_type(mi.set_names(1), pd.MultiIndex), pd.MultiIndex, tuple) + + +def test_index_droplevel() -> None: + idx = pd.Index([1, 2]) + check(assert_type(idx.droplevel([]), "pd.Index[int]"), pd.Index, np.integer) + mi = pd.MultiIndex.from_arrays([[1, 2, 3], [4, 5, 6]], names=["elk", "owl"]) + check(assert_type(mi.droplevel([]), pd.MultiIndex | pd.Index), pd.MultiIndex) + check(assert_type(mi.droplevel([0]), pd.MultiIndex | pd.Index), pd.Index) + check(assert_type(mi.droplevel((0,)), pd.MultiIndex | pd.Index), pd.Index) + check(assert_type(mi.droplevel(["elk"]), pd.MultiIndex | pd.Index), pd.Index) + check(assert_type(mi.droplevel(("elk",)), pd.MultiIndex | pd.Index), pd.Index) + check(assert_type(mi.droplevel(0), pd.MultiIndex | pd.Index), pd.Index) From c56cf804675078cd62e7649b15682e4984121df8 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Mon, 24 Nov 2025 18:43:45 +0000 Subject: [PATCH 3/5] appease mypy --- pandas-stubs/core/indexes/multi.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas-stubs/core/indexes/multi.pyi b/pandas-stubs/core/indexes/multi.pyi index 93a2f1483..3b3564295 100644 --- a/pandas-stubs/core/indexes/multi.pyi +++ b/pandas-stubs/core/indexes/multi.pyi @@ -109,7 +109,7 @@ class MultiIndex(Index): def is_monotonic_decreasing(self) -> bool: ... def duplicated(self, keep: DropKeep = "first"): ... def dropna(self, how: AnyAll = "any") -> Self: ... - def droplevel(self, level: Level | Sequence[Level] = 0) -> MultiIndex | Index: ... + def droplevel(self, level: Level | Sequence[Level] = 0) -> MultiIndex | Index: ... # type: ignore[override] def get_level_values(self, level: str | int) -> Index: ... def unique(self, level=...): ... def to_frame( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] From f003e987b4993336742c84689106544167e20435 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Mon, 24 Nov 2025 18:49:55 +0000 Subject: [PATCH 4/5] remove undocumented isnull / fillnull --- pandas-stubs/core/indexes/base.pyi | 2 -- 1 file changed, 2 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 0972758f2..584548d97 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -418,10 +418,8 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): def hasnans(self) -> bool: ... @final def isna(self) -> Index[bool]: ... - isnull = isna @final def notna(self) -> Index[bool]: ... - notnull = notna def fillna(self, value: Scalar) -> Index: ... def dropna(self, how: AnyAll = "any") -> Self: ... def unique(self, level: Hashable | None = None) -> Self: ... From 2e839c8b166b23dd1f80044744d0be5bdf6db330 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 25 Nov 2025 10:19:14 +0000 Subject: [PATCH 5/5] test invalid setitem --- tests/indexes/test_indexes.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/indexes/test_indexes.py b/tests/indexes/test_indexes.py index 3d60e748e..5b3d9416a 100644 --- a/tests/indexes/test_indexes.py +++ b/tests/indexes/test_indexes.py @@ -1557,3 +1557,9 @@ def test_index_droplevel() -> None: check(assert_type(mi.droplevel(["elk"]), pd.MultiIndex | pd.Index), pd.Index) check(assert_type(mi.droplevel(("elk",)), pd.MultiIndex | pd.Index), pd.Index) check(assert_type(mi.droplevel(0), pd.MultiIndex | pd.Index), pd.Index) + + +def test_index_setitem() -> None: + idx = pd.Index([1, 2]) + if TYPE_CHECKING_INVALID_USAGE: + idx[0] = 999 # type: ignore[index] # pyright: ignore[reportIndexIssue]