Skip to content

Commit 8979c5b

Browse files
topper-123quintusdias
authored andcommitted
TYPING: Partial typing of Categorical (pandas-dev#27318)
1 parent a6722a7 commit 8979c5b

File tree

3 files changed

+36
-27
lines changed

3 files changed

+36
-27
lines changed

pandas/_typing.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from pathlib import Path
2-
from typing import IO, TYPE_CHECKING, AnyStr, TypeVar, Union
2+
from typing import IO, TYPE_CHECKING, AnyStr, Optional, TypeVar, Union
33

44
import numpy as np
55

@@ -27,3 +27,4 @@
2727
FrameOrSeries = TypeVar("FrameOrSeries", "Series", "DataFrame")
2828
Scalar = Union[str, int, float]
2929
Axis = Union[str, int]
30+
Ordered = Optional[bool]

pandas/core/arrays/categorical.py

+15-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from shutil import get_terminal_size
22
import textwrap
3+
from typing import Type, Union, cast
34
from warnings import warn
45

56
import numpy as np
@@ -42,6 +43,7 @@
4243
from pandas.core.dtypes.inference import is_hashable
4344
from pandas.core.dtypes.missing import isna, notna
4445

46+
from pandas._typing import ArrayLike, Dtype, Ordered
4547
from pandas.core import ops
4648
from pandas.core.accessor import PandasDelegate, delegate_names
4749
import pandas.core.algorithms as algorithms
@@ -455,7 +457,7 @@ def categories(self, categories):
455457
self._dtype = new_dtype
456458

457459
@property
458-
def ordered(self):
460+
def ordered(self) -> Ordered:
459461
"""
460462
Whether the categories have an ordered relationship.
461463
"""
@@ -469,11 +471,11 @@ def dtype(self) -> CategoricalDtype:
469471
return self._dtype
470472

471473
@property
472-
def _ndarray_values(self):
474+
def _ndarray_values(self) -> np.ndarray:
473475
return self.codes
474476

475477
@property
476-
def _constructor(self):
478+
def _constructor(self) -> Type["Categorical"]:
477479
return Categorical
478480

479481
@classmethod
@@ -484,15 +486,15 @@ def _formatter(self, boxed=False):
484486
# Defer to CategoricalFormatter's formatter.
485487
return None
486488

487-
def copy(self):
489+
def copy(self) -> "Categorical":
488490
"""
489491
Copy constructor.
490492
"""
491493
return self._constructor(
492494
values=self._codes.copy(), dtype=self.dtype, fastpath=True
493495
)
494496

495-
def astype(self, dtype, copy=True):
497+
def astype(self, dtype: Dtype, copy: bool = True) -> ArrayLike:
496498
"""
497499
Coerce this type to another dtype
498500
@@ -505,6 +507,8 @@ def astype(self, dtype, copy=True):
505507
object is returned.
506508
"""
507509
if is_categorical_dtype(dtype):
510+
dtype = cast(Union[str, CategoricalDtype], dtype)
511+
508512
# GH 10696/18593
509513
dtype = self.dtype.update_dtype(dtype)
510514
self = self.copy() if copy else self
@@ -514,27 +518,27 @@ def astype(self, dtype, copy=True):
514518
return np.array(self, dtype=dtype, copy=copy)
515519

516520
@cache_readonly
517-
def ndim(self):
521+
def ndim(self) -> int:
518522
"""
519523
Number of dimensions of the Categorical
520524
"""
521525
return self._codes.ndim
522526

523527
@cache_readonly
524-
def size(self):
528+
def size(self) -> int:
525529
"""
526530
return the len of myself
527531
"""
528532
return len(self)
529533

530534
@cache_readonly
531-
def itemsize(self):
535+
def itemsize(self) -> int:
532536
"""
533537
return the size of a single category
534538
"""
535539
return self.categories.itemsize
536540

537-
def tolist(self):
541+
def tolist(self) -> list:
538542
"""
539543
Return a list of the values.
540544
@@ -547,7 +551,7 @@ def tolist(self):
547551
to_list = tolist
548552

549553
@property
550-
def base(self):
554+
def base(self) -> None:
551555
"""
552556
compat, we are always our own object
553557
"""
@@ -694,8 +698,6 @@ def from_codes(cls, codes, categories=None, ordered=None, dtype=None):
694698

695699
return cls(codes, dtype=dtype, fastpath=True)
696700

697-
_codes = None
698-
699701
def _get_codes(self):
700702
"""
701703
Get the codes.
@@ -755,7 +757,7 @@ def _set_categories(self, categories, fastpath=False):
755757

756758
self._dtype = new_dtype
757759

758-
def _set_dtype(self, dtype):
760+
def _set_dtype(self, dtype: CategoricalDtype) -> "Categorical":
759761
"""
760762
Internal method for directly updating the CategoricalDtype
761763

pandas/core/dtypes/dtypes.py

+19-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
""" define extension dtypes """
22
import re
3-
from typing import Any, Dict, List, Optional, Tuple, Type, Union
3+
from typing import Any, Dict, List, Optional, Tuple, Type, Union, cast
44
import warnings
55

66
import numpy as np
@@ -11,6 +11,8 @@
1111

1212
from pandas.core.dtypes.generic import ABCCategoricalIndex, ABCDateOffset, ABCIndexClass
1313

14+
from pandas._typing import Ordered
15+
1416
from .base import ExtensionDtype
1517
from .inference import is_bool, is_list_like
1618

@@ -20,9 +22,6 @@
2022
# CategoricalDtype constructor to detect when ordered=None is explicitly passed
2123
ordered_sentinel = object() # type: object
2224

23-
# TODO(GH26403): Replace with Optional[bool] or bool
24-
OrderedType = Union[None, bool, object]
25-
2625

2726
def register_extension_dtype(cls: Type[ExtensionDtype],) -> Type[ExtensionDtype]:
2827
"""
@@ -222,7 +221,11 @@ class CategoricalDtype(PandasExtensionDtype, ExtensionDtype):
222221
_metadata = ("categories", "ordered", "_ordered_from_sentinel")
223222
_cache = {} # type: Dict[str_type, PandasExtensionDtype]
224223

225-
def __init__(self, categories=None, ordered: OrderedType = ordered_sentinel):
224+
def __init__(
225+
self, categories=None, ordered: Union[Ordered, object] = ordered_sentinel
226+
):
227+
# TODO(GH26403): Set type of ordered to Ordered
228+
ordered = cast(Ordered, ordered)
226229
self._finalize(categories, ordered, fastpath=False)
227230

228231
@classmethod
@@ -235,7 +238,7 @@ def _from_fastpath(
235238

236239
@classmethod
237240
def _from_categorical_dtype(
238-
cls, dtype: "CategoricalDtype", categories=None, ordered: OrderedType = None
241+
cls, dtype: "CategoricalDtype", categories=None, ordered: Ordered = None
239242
) -> "CategoricalDtype":
240243
if categories is ordered is None:
241244
return dtype
@@ -336,9 +339,7 @@ def _from_values_or_dtype(
336339

337340
return dtype
338341

339-
def _finalize(
340-
self, categories, ordered: OrderedType, fastpath: bool = False
341-
) -> None:
342+
def _finalize(self, categories, ordered: Ordered, fastpath: bool = False) -> None:
342343

343344
if ordered is not None and ordered is not ordered_sentinel:
344345
self.validate_ordered(ordered)
@@ -423,7 +424,7 @@ def __repr__(self):
423424
return tpl.format(data, self._ordered)
424425

425426
@staticmethod
426-
def _hash_categories(categories, ordered: OrderedType = True) -> int:
427+
def _hash_categories(categories, ordered: Ordered = True) -> int:
427428
from pandas.core.util.hashing import (
428429
hash_array,
429430
_combine_hash_arrays,
@@ -475,7 +476,7 @@ def construct_array_type(cls):
475476
return Categorical
476477

477478
@staticmethod
478-
def validate_ordered(ordered: OrderedType) -> None:
479+
def validate_ordered(ordered: Ordered) -> None:
479480
"""
480481
Validates that we have a valid ordered parameter. If
481482
it is not a boolean, a TypeError will be raised.
@@ -529,7 +530,9 @@ def validate_categories(categories, fastpath: bool = False):
529530

530531
return categories
531532

532-
def update_dtype(self, dtype: "CategoricalDtype") -> "CategoricalDtype":
533+
def update_dtype(
534+
self, dtype: Union[str_type, "CategoricalDtype"]
535+
) -> "CategoricalDtype":
533536
"""
534537
Returns a CategoricalDtype with categories and ordered taken from dtype
535538
if specified, otherwise falling back to self if unspecified
@@ -551,6 +554,9 @@ def update_dtype(self, dtype: "CategoricalDtype") -> "CategoricalDtype":
551554
"got {dtype!r}"
552555
).format(dtype=dtype)
553556
raise ValueError(msg)
557+
else:
558+
# from here on, dtype is a CategoricalDtype
559+
dtype = cast(CategoricalDtype, dtype)
554560

555561
# dtype is CDT: keep current categories/ordered if None
556562
new_categories = dtype.categories
@@ -583,7 +589,7 @@ def categories(self):
583589
return self._categories
584590

585591
@property
586-
def ordered(self) -> OrderedType:
592+
def ordered(self) -> Ordered:
587593
"""
588594
Whether the categories have an ordered relationship.
589595
"""

0 commit comments

Comments
 (0)