Skip to content

Commit a2f42ac

Browse files
authored
TYP: MultiIndex (#39729)
1 parent 38f701e commit a2f42ac

File tree

4 files changed

+53
-40
lines changed

4 files changed

+53
-40
lines changed

pandas/core/frame.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -4821,7 +4821,10 @@ def set_index(
48214821
names.extend(col.names)
48224822
elif isinstance(col, (Index, Series)):
48234823
# if Index then not MultiIndex (treated above)
4824-
arrays.append(col)
4824+
4825+
# error: Argument 1 to "append" of "list" has incompatible
4826+
# type "Union[Index, Series]"; expected "Index" [arg-type]
4827+
arrays.append(col) # type:ignore[arg-type]
48254828
names.append(col.name)
48264829
elif isinstance(col, (list, np.ndarray)):
48274830
arrays.append(col)

pandas/core/indexes/base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5766,7 +5766,7 @@ def insert(self, loc: int, item):
57665766
idx = np.concatenate((arr[:loc], item, arr[loc:]))
57675767
return Index(idx, name=self.name)
57685768

5769-
def drop(self, labels, errors: str_t = "raise"):
5769+
def drop(self: _IndexT, labels, errors: str_t = "raise") -> _IndexT:
57705770
"""
57715771
Make new Index with passed list of labels deleted.
57725772

pandas/core/indexes/multi.py

+44-34
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
Sequence,
1414
Tuple,
1515
Union,
16+
cast,
1617
)
1718
import warnings
1819

@@ -71,7 +72,7 @@
7172
)
7273

7374
if TYPE_CHECKING:
74-
from pandas import Series
75+
from pandas import CategoricalIndex, Series
7576

7677
_index_doc_kwargs = dict(ibase._index_doc_kwargs)
7778
_index_doc_kwargs.update(
@@ -478,7 +479,7 @@ def from_tuples(
478479
tuples,
479480
sortorder: Optional[int] = None,
480481
names: Optional[Sequence[Hashable]] = None,
481-
):
482+
) -> MultiIndex:
482483
"""
483484
Convert list of tuples to MultiIndex.
484485
@@ -537,7 +538,9 @@ def from_tuples(
537538
return cls.from_arrays(arrays, sortorder=sortorder, names=names)
538539

539540
@classmethod
540-
def from_product(cls, iterables, sortorder=None, names=lib.no_default):
541+
def from_product(
542+
cls, iterables, sortorder=None, names=lib.no_default
543+
) -> MultiIndex:
541544
"""
542545
Make a MultiIndex from the cartesian product of multiple iterables.
543546
@@ -596,7 +599,7 @@ def from_product(cls, iterables, sortorder=None, names=lib.no_default):
596599
return cls(levels, codes, sortorder=sortorder, names=names)
597600

598601
@classmethod
599-
def from_frame(cls, df, sortorder=None, names=None):
602+
def from_frame(cls, df, sortorder=None, names=None) -> MultiIndex:
600603
"""
601604
Make a MultiIndex from a DataFrame.
602605
@@ -664,14 +667,15 @@ def from_frame(cls, df, sortorder=None, names=None):
664667
# --------------------------------------------------------------------
665668

666669
@cache_readonly
667-
def _values(self):
670+
def _values(self) -> np.ndarray:
668671
# We override here, since our parent uses _data, which we don't use.
669672
values = []
670673

671674
for i in range(self.nlevels):
672675
vals = self._get_level_values(i)
673676
if is_categorical_dtype(vals.dtype):
674-
vals = vals._internal_get_values()
677+
vals = cast("CategoricalIndex", vals)
678+
vals = vals._data._internal_get_values()
675679
if isinstance(vals.dtype, ExtensionDtype) or isinstance(
676680
vals, (ABCDatetimeIndex, ABCTimedeltaIndex)
677681
):
@@ -683,7 +687,7 @@ def _values(self):
683687
return arr
684688

685689
@property
686-
def values(self):
690+
def values(self) -> np.ndarray:
687691
return self._values
688692

689693
@property
@@ -782,7 +786,9 @@ def _set_levels(
782786

783787
self._reset_cache()
784788

785-
def set_levels(self, levels, level=None, inplace=None, verify_integrity=True):
789+
def set_levels(
790+
self, levels, level=None, inplace=None, verify_integrity: bool = True
791+
):
786792
"""
787793
Set new levels on MultiIndex. Defaults to returning new index.
788794
@@ -909,7 +915,7 @@ def nlevels(self) -> int:
909915
return len(self._levels)
910916

911917
@property
912-
def levshape(self):
918+
def levshape(self) -> Shape:
913919
"""
914920
A tuple with the length of each level.
915921
@@ -967,7 +973,7 @@ def _set_codes(
967973

968974
self._reset_cache()
969975

970-
def set_codes(self, codes, level=None, inplace=None, verify_integrity=True):
976+
def set_codes(self, codes, level=None, inplace=None, verify_integrity: bool = True):
971977
"""
972978
Set new codes on MultiIndex. Defaults to returning new index.
973979
@@ -985,7 +991,7 @@ def set_codes(self, codes, level=None, inplace=None, verify_integrity=True):
985991
If True, mutates in place.
986992
987993
.. deprecated:: 1.2.0
988-
verify_integrity : bool (default True)
994+
verify_integrity : bool, default True
989995
If True, checks that levels and codes are compatible.
990996
991997
Returns
@@ -1080,12 +1086,12 @@ def _constructor(self):
10801086
return type(self).from_tuples
10811087

10821088
@doc(Index._shallow_copy)
1083-
def _shallow_copy(self, values, name=lib.no_default):
1089+
def _shallow_copy(self, values: np.ndarray, name=lib.no_default) -> MultiIndex:
10841090
names = name if name is not lib.no_default else self.names
10851091

10861092
return type(self).from_tuples(values, sortorder=None, names=names)
10871093

1088-
def _view(self: MultiIndex) -> MultiIndex:
1094+
def _view(self) -> MultiIndex:
10891095
result = type(self)(
10901096
levels=self.levels,
10911097
codes=self.codes,
@@ -1580,7 +1586,7 @@ def is_monotonic_decreasing(self) -> bool:
15801586
return self[::-1].is_monotonic_increasing
15811587

15821588
@cache_readonly
1583-
def _inferred_type_levels(self):
1589+
def _inferred_type_levels(self) -> List[str]:
15841590
""" return a list of the inferred types, one for each level """
15851591
return [i.inferred_type for i in self.levels]
15861592

@@ -1598,7 +1604,7 @@ def fillna(self, value=None, downcast=None):
15981604
raise NotImplementedError("isna is not defined for MultiIndex")
15991605

16001606
@doc(Index.dropna)
1601-
def dropna(self, how="any"):
1607+
def dropna(self, how: str = "any") -> MultiIndex:
16021608
nans = [level_codes == -1 for level_codes in self.codes]
16031609
if how == "any":
16041610
indexer = np.any(nans, axis=0)
@@ -1610,7 +1616,7 @@ def dropna(self, how="any"):
16101616
new_codes = [level_codes[~indexer] for level_codes in self.codes]
16111617
return self.set_codes(codes=new_codes)
16121618

1613-
def _get_level_values(self, level, unique=False):
1619+
def _get_level_values(self, level: int, unique: bool = False) -> Index:
16141620
"""
16151621
Return vector of label values for requested level,
16161622
equal to the length of the index
@@ -1619,13 +1625,13 @@ def _get_level_values(self, level, unique=False):
16191625
16201626
Parameters
16211627
----------
1622-
level : int level
1628+
level : int
16231629
unique : bool, default False
16241630
if True, drop duplicated values
16251631
16261632
Returns
16271633
-------
1628-
values : ndarray
1634+
Index
16291635
"""
16301636
lev = self.levels[level]
16311637
level_codes = self.codes[level]
@@ -1759,7 +1765,7 @@ def to_frame(self, index=True, name=None):
17591765
result.index = self
17601766
return result
17611767

1762-
def to_flat_index(self):
1768+
def to_flat_index(self) -> Index:
17631769
"""
17641770
Convert a MultiIndex to an Index of Tuples containing the level values.
17651771
@@ -1862,7 +1868,7 @@ def _lexsort_depth(self) -> int:
18621868
return self.sortorder
18631869
return _lexsort_depth(self.codes, self.nlevels)
18641870

1865-
def _sort_levels_monotonic(self):
1871+
def _sort_levels_monotonic(self) -> MultiIndex:
18661872
"""
18671873
This is an *internal* function.
18681874
@@ -1929,7 +1935,7 @@ def _sort_levels_monotonic(self):
19291935
verify_integrity=False,
19301936
)
19311937

1932-
def remove_unused_levels(self):
1938+
def remove_unused_levels(self) -> MultiIndex:
19331939
"""
19341940
Create new MultiIndex from current that removes unused levels.
19351941
@@ -2065,7 +2071,9 @@ def __getitem__(self, key):
20652071
)
20662072

20672073
@Appender(_index_shared_docs["take"] % _index_doc_kwargs)
2068-
def take(self, indices, axis=0, allow_fill=True, fill_value=None, **kwargs):
2074+
def take(
2075+
self: MultiIndex, indices, axis=0, allow_fill=True, fill_value=None, **kwargs
2076+
) -> MultiIndex:
20692077
nv.validate_take((), kwargs)
20702078
indices = ensure_platform_int(indices)
20712079

@@ -2129,7 +2137,7 @@ def argsort(self, *args, **kwargs) -> np.ndarray:
21292137
return self._values.argsort(*args, **kwargs)
21302138

21312139
@Appender(_index_shared_docs["repeat"] % _index_doc_kwargs)
2132-
def repeat(self, repeats, axis=None):
2140+
def repeat(self, repeats: int, axis=None) -> MultiIndex:
21332141
nv.validate_repeat((), {"axis": axis})
21342142
repeats = ensure_platform_int(repeats)
21352143
return MultiIndex(
@@ -2200,7 +2208,7 @@ def drop(self, codes, level=None, errors="raise"):
22002208

22012209
return self.delete(inds)
22022210

2203-
def _drop_from_level(self, codes, level, errors="raise"):
2211+
def _drop_from_level(self, codes, level, errors="raise") -> MultiIndex:
22042212
codes = com.index_labels_to_array(codes)
22052213
i = self._get_level_number(level)
22062214
index = self.levels[i]
@@ -2219,7 +2227,7 @@ def _drop_from_level(self, codes, level, errors="raise"):
22192227

22202228
return self[mask]
22212229

2222-
def swaplevel(self, i=-2, j=-1):
2230+
def swaplevel(self, i=-2, j=-1) -> MultiIndex:
22232231
"""
22242232
Swap level i with level j.
22252233
@@ -2277,7 +2285,7 @@ def swaplevel(self, i=-2, j=-1):
22772285
levels=new_levels, codes=new_codes, names=new_names, verify_integrity=False
22782286
)
22792287

2280-
def reorder_levels(self, order):
2288+
def reorder_levels(self, order) -> MultiIndex:
22812289
"""
22822290
Rearrange levels using input order. May not drop or duplicate levels.
22832291
@@ -2323,7 +2331,7 @@ def reorder_levels(self, order):
23232331
levels=new_levels, codes=new_codes, names=new_names, verify_integrity=False
23242332
)
23252333

2326-
def _get_codes_for_sorting(self):
2334+
def _get_codes_for_sorting(self) -> List[Categorical]:
23272335
"""
23282336
we are categorizing our codes by using the
23292337
available categories (all, not just observed)
@@ -2343,7 +2351,9 @@ def cats(level_codes):
23432351
for level_codes in self.codes
23442352
]
23452353

2346-
def sortlevel(self, level=0, ascending=True, sort_remaining=True):
2354+
def sortlevel(
2355+
self, level=0, ascending: bool = True, sort_remaining: bool = True
2356+
) -> Tuple[MultiIndex, np.ndarray]:
23472357
"""
23482358
Sort MultiIndex at the requested level.
23492359
@@ -3396,7 +3406,7 @@ def _reorder_indexer(
33963406
ind = np.lexsort(keys)
33973407
return indexer[ind]
33983408

3399-
def truncate(self, before=None, after=None):
3409+
def truncate(self, before=None, after=None) -> MultiIndex:
34003410
"""
34013411
Slice index between two labels / tuples, return new MultiIndex
34023412
@@ -3517,7 +3527,7 @@ def _union(self, other, sort):
35173527
def _is_comparable_dtype(self, dtype: DtypeObj) -> bool:
35183528
return is_object_dtype(dtype)
35193529

3520-
def _get_reconciled_name_object(self, other):
3530+
def _get_reconciled_name_object(self, other) -> MultiIndex:
35213531
"""
35223532
If the result of a set operation will be self,
35233533
return self, unless the names change, in which
@@ -3662,7 +3672,7 @@ def _validate_fill_value(self, item):
36623672
raise ValueError("Item must have length equal to number of levels.")
36633673
return item
36643674

3665-
def insert(self, loc: int, item):
3675+
def insert(self, loc: int, item) -> MultiIndex:
36663676
"""
36673677
Make new MultiIndex inserting new item at location
36683678
@@ -3702,7 +3712,7 @@ def insert(self, loc: int, item):
37023712
levels=new_levels, codes=new_codes, names=self.names, verify_integrity=False
37033713
)
37043714

3705-
def delete(self, loc):
3715+
def delete(self, loc) -> MultiIndex:
37063716
"""
37073717
Make new index with passed location deleted
37083718
@@ -3719,7 +3729,7 @@ def delete(self, loc):
37193729
)
37203730

37213731
@doc(Index.isin)
3722-
def isin(self, values, level=None):
3732+
def isin(self, values, level=None) -> np.ndarray:
37233733
if level is None:
37243734
values = MultiIndex.from_tuples(values, names=self.names)._values
37253735
return algos.isin(self._values, values)
@@ -3800,7 +3810,7 @@ def _get_na_rep(dtype) -> str:
38003810
return {np.datetime64: "NaT", np.timedelta64: "NaT"}.get(dtype, "NaN")
38013811

38023812

3803-
def maybe_droplevels(index, key):
3813+
def maybe_droplevels(index: Index, key) -> Index:
38043814
"""
38053815
Attempt to drop level or levels from the given index.
38063816

pandas/tests/groupby/test_categorical.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -1639,8 +1639,8 @@ def test_series_groupby_first_on_categorical_col_grouped_on_2_categoricals(
16391639
val = [0, 1, 1, 0]
16401640
df = DataFrame({"a": cat, "b": cat, "c": val})
16411641

1642-
idx = Categorical([0, 1])
1643-
idx = pd.MultiIndex.from_product([idx, idx], names=["a", "b"])
1642+
cat2 = Categorical([0, 1])
1643+
idx = pd.MultiIndex.from_product([cat2, cat2], names=["a", "b"])
16441644
expected_dict = {
16451645
"first": Series([0, np.NaN, np.NaN, 1], idx, name="c"),
16461646
"last": Series([1, np.NaN, np.NaN, 0], idx, name="c"),
@@ -1664,8 +1664,8 @@ def test_df_groupby_first_on_categorical_col_grouped_on_2_categoricals(
16641664
val = [0, 1, 1, 0]
16651665
df = DataFrame({"a": cat, "b": cat, "c": val})
16661666

1667-
idx = Categorical([0, 1])
1668-
idx = pd.MultiIndex.from_product([idx, idx], names=["a", "b"])
1667+
cat2 = Categorical([0, 1])
1668+
idx = pd.MultiIndex.from_product([cat2, cat2], names=["a", "b"])
16691669
expected_dict = {
16701670
"first": Series([0, np.NaN, np.NaN, 1], idx, name="c"),
16711671
"last": Series([1, np.NaN, np.NaN, 0], idx, name="c"),

0 commit comments

Comments
 (0)