11""" define extension dtypes """
22import re
3- from typing import Any , Dict , Optional , Tuple , Type
3+ import typing
4+ from typing import Any , Dict , List , Optional , Tuple , Type , Union
45import warnings
56
67import numpy as np
78import pytz
89
910from pandas ._libs .interval import Interval
1011from pandas ._libs .tslibs import NaT , Period , Timestamp , timezones
12+ from pandas .errors import AbstractMethodError
1113
1214from pandas .core .dtypes .generic import (
1315 ABCCategoricalIndex , ABCDateOffset , ABCIndexClass )
1820str_type = str
1921
2022
21- def register_extension_dtype (cls ):
23+ def register_extension_dtype (cls : Type ['ExtensionDtype' ],
24+ ) -> Type ['ExtensionDtype' ]:
2225 """
2326 Register an ExtensionType with pandas as class decorator.
2427
@@ -60,24 +63,26 @@ class Registry:
6063 These are tried in order.
6164 """
6265 def __init__ (self ):
63- self .dtypes = []
66+ self .dtypes = [] # type: List[Type[ExtensionDtype]]
6467
65- def register (self , dtype ) :
68+ def register (self , dtype : Type [ 'ExtensionDtype' ]) -> None :
6669 """
6770 Parameters
6871 ----------
6972 dtype : ExtensionDtype
7073 """
71- if not issubclass (dtype , ( PandasExtensionDtype , ExtensionDtype ) ):
74+ if not issubclass (dtype , ExtensionDtype ):
7275 raise ValueError ("can only register pandas extension dtypes" )
7376
7477 self .dtypes .append (dtype )
7578
76- def find (self , dtype ):
79+ def find (self ,
80+ dtype : Union [Type ['ExtensionDtype' ], str ],
81+ ) -> Optional [Type [ExtensionDtype ]]:
7782 """
7883 Parameters
7984 ----------
80- dtype : PandasExtensionDtype or string
85+ dtype : Type[ExtensionDtype] or string
8186
8287 Returns
8388 -------
@@ -126,16 +131,20 @@ class PandasExtensionDtype(_DtypeOpsMixin):
126131 isnative = 0
127132 _cache = {} # type: Dict[str_type, 'PandasExtensionDtype']
128133
129- def __unicode__ (self ):
134+ def __unicode__ (self ) -> str_type :
130135 return self .name
131136
132- def __str__ (self ):
137+ @property
138+ def name (self ) -> str_type :
139+ raise AbstractMethodError (self )
140+
141+ def __str__ (self ) -> str_type :
133142 """
134143 Return a string representation for a particular Object
135144 """
136145 return self .__unicode__ ()
137146
138- def __bytes__ (self ):
147+ def __bytes__ (self ) -> bytes :
139148 """
140149 Return a string representation for a particular object.
141150 """
@@ -144,22 +153,22 @@ def __bytes__(self):
144153 encoding = get_option ("display.encoding" )
145154 return self .__unicode__ ().encode (encoding , 'replace' )
146155
147- def __repr__ (self ):
156+ def __repr__ (self ) -> str_type :
148157 """
149158 Return a string representation for a particular object.
150159 """
151160 return str (self )
152161
153- def __hash__ (self ):
162+ def __hash__ (self ) -> int :
154163 raise NotImplementedError ("sub-classes should implement an __hash__ "
155164 "method" )
156165
157- def __getstate__ (self ):
166+ def __getstate__ (self ) -> Dict [ str_type , Any ] :
158167 # pickle support; we don't want to pickle the cache
159168 return {k : getattr (self , k , None ) for k in self ._metadata }
160169
161170 @classmethod
162- def reset_cache (cls ):
171+ def reset_cache (cls ) -> None :
163172 """ clear the cache """
164173 cls ._cache = {}
165174
@@ -223,17 +232,24 @@ class CategoricalDtype(PandasExtensionDtype, ExtensionDtype):
223232 _metadata = ('categories' , 'ordered' )
224233 _cache = {} # type: Dict[str_type, PandasExtensionDtype]
225234
226- def __init__ (self , categories = None , ordered = None ):
235+ def __init__ (self , categories = None , ordered : bool = None ):
227236 self ._finalize (categories , ordered , fastpath = False )
228237
229238 @classmethod
230- def _from_fastpath (cls , categories = None , ordered = None ):
239+ def _from_fastpath (cls ,
240+ categories = None ,
241+ ordered : bool = None
242+ ) -> 'CategoricalDtype' :
231243 self = cls .__new__ (cls )
232244 self ._finalize (categories , ordered , fastpath = True )
233245 return self
234246
235247 @classmethod
236- def _from_categorical_dtype (cls , dtype , categories = None , ordered = None ):
248+ def _from_categorical_dtype (cls ,
249+ dtype : 'CategoricalDtype' ,
250+ categories = None ,
251+ ordered : bool = None ,
252+ ) -> 'CategoricalDtype' :
237253 if categories is ordered is None :
238254 return dtype
239255 if categories is None :
@@ -243,8 +259,12 @@ def _from_categorical_dtype(cls, dtype, categories=None, ordered=None):
243259 return cls (categories , ordered )
244260
245261 @classmethod
246- def _from_values_or_dtype (cls , values = None , categories = None , ordered = None ,
247- dtype = None ):
262+ def _from_values_or_dtype (cls ,
263+ values = None ,
264+ categories = None ,
265+ ordered : bool = None ,
266+ dtype : 'CategoricalDtype' = None ,
267+ ) -> 'CategoricalDtype' :
248268 """
249269 Construct dtype from the input parameters used in :class:`Categorical`.
250270
@@ -326,7 +346,11 @@ def _from_values_or_dtype(cls, values=None, categories=None, ordered=None,
326346
327347 return dtype
328348
329- def _finalize (self , categories , ordered , fastpath = False ):
349+ def _finalize (self ,
350+ categories ,
351+ ordered : Optional [bool ],
352+ fastpath : bool = False ,
353+ ) -> None :
330354
331355 if ordered is not None :
332356 self .validate_ordered (ordered )
@@ -338,14 +362,14 @@ def _finalize(self, categories, ordered, fastpath=False):
338362 self ._categories = categories
339363 self ._ordered = ordered
340364
341- def __setstate__ (self , state ) :
365+ def __setstate__ (self , state : 'Dict[str_type, Any]' ) -> None :
342366 # for pickle compat. __get_state__ is defined in the
343367 # PandasExtensionDtype superclass and uses the public properties to
344368 # pickle -> need to set the settable private ones here (see GH26067)
345369 self ._categories = state .pop ('categories' , None )
346370 self ._ordered = state .pop ('ordered' , False )
347371
348- def __hash__ (self ):
372+ def __hash__ (self ) -> int :
349373 # _hash_categories returns a uint64, so use the negative
350374 # space for when we have unknown categories to avoid a conflict
351375 if self .categories is None :
@@ -356,7 +380,7 @@ def __hash__(self):
356380 # We *do* want to include the real self.ordered here
357381 return int (self ._hash_categories (self .categories , self .ordered ))
358382
359- def __eq__ (self , other ) :
383+ def __eq__ (self , other : Any ) -> bool :
360384 """
361385 Rules for CDT equality:
362386 1) Any CDT is equal to the string 'category'
@@ -403,7 +427,7 @@ def __repr__(self):
403427 return tpl .format (data , self .ordered )
404428
405429 @staticmethod
406- def _hash_categories (categories , ordered = True ):
430+ def _hash_categories (categories , ordered : Union [ bool , None ] = True ) -> int :
407431 from pandas .core .util .hashing import (
408432 hash_array , _combine_hash_arrays , hash_tuples
409433 )
@@ -453,20 +477,17 @@ def construct_array_type(cls):
453477 return Categorical
454478
455479 @classmethod
456- def construct_from_string (cls , string ) :
480+ def construct_from_string (cls , string : str_type ) -> 'CategoricalDtype' :
457481 """
458482 attempt to construct this type from a string, raise a TypeError if
459483 it's not possible """
460- try :
461- if string == 'category' :
462- return cls ()
463- else :
464- raise TypeError ("cannot construct a CategoricalDtype" )
465- except AttributeError :
466- pass
484+ if string == 'category' :
485+ return cls ()
486+ else :
487+ raise TypeError ("cannot construct a CategoricalDtype" )
467488
468489 @staticmethod
469- def validate_ordered (ordered ) :
490+ def validate_ordered (ordered : bool ) -> None :
470491 """
471492 Validates that we have a valid ordered parameter. If
472493 it is not a boolean, a TypeError will be raised.
@@ -486,7 +507,7 @@ def validate_ordered(ordered):
486507 raise TypeError ("'ordered' must either be 'True' or 'False'" )
487508
488509 @staticmethod
489- def validate_categories (categories , fastpath = False ):
510+ def validate_categories (categories , fastpath : bool = False ):
490511 """
491512 Validates that we have good categories
492513
@@ -500,7 +521,7 @@ def validate_categories(categories, fastpath=False):
500521 -------
501522 categories : Index
502523 """
503- from pandas import Index
524+ from pandas . core . indexes . base import Index
504525
505526 if not fastpath and not is_list_like (categories ):
506527 msg = "Parameter 'categories' must be list-like, was {!r}"
@@ -519,9 +540,9 @@ def validate_categories(categories, fastpath=False):
519540 if isinstance (categories , ABCCategoricalIndex ):
520541 categories = categories .categories
521542
522- return categories
543+ return typing . cast ( Index , categories )
523544
524- def update_dtype (self , dtype ) :
545+ def update_dtype (self , dtype : 'CategoricalDtype' ) -> 'CategoricalDtype' :
525546 """
526547 Returns a CategoricalDtype with categories and ordered taken from dtype
527548 if specified, otherwise falling back to self if unspecified
@@ -560,17 +581,18 @@ def categories(self):
560581 """
561582 An ``Index`` containing the unique categories allowed.
562583 """
563- return self ._categories
584+ from pandas import Index
585+ return typing .cast (Index , self ._categories )
564586
565587 @property
566- def ordered (self ):
588+ def ordered (self ) -> Optional [ bool ] :
567589 """
568590 Whether the categories have an ordered relationship.
569591 """
570592 return self ._ordered
571593
572594 @property
573- def _is_boolean (self ):
595+ def _is_boolean (self ) -> bool :
574596 from pandas .core .dtypes .common import is_bool_dtype
575597
576598 return is_bool_dtype (self .categories )
0 commit comments