1
1
""" define extension dtypes """
2
2
import re
3
- from typing import Any , Dict , Optional , Tuple , Type
3
+ import typing
4
+ from typing import Any , Dict , List , Optional , Union , Tuple , Type
4
5
import warnings
5
6
6
7
import numpy as np
11
12
12
13
from pandas .core .dtypes .generic import (
13
14
ABCCategoricalIndex , ABCDateOffset , ABCIndexClass )
15
+ from pandas .errors import AbstractMethodError
14
16
15
17
from .base import ExtensionDtype , _DtypeOpsMixin
16
18
from .inference import is_list_like
17
19
18
20
str_type = str
19
21
20
22
21
- def register_extension_dtype (cls ):
23
+ def register_extension_dtype (cls : Type ['ExtensionDtype' ],
24
+ ) -> Type ['ExtensionDtype' ]:
22
25
"""
23
26
Register an ExtensionType with pandas as class decorator.
24
27
@@ -60,20 +63,22 @@ class Registry:
60
63
These are tried in order.
61
64
"""
62
65
def __init__ (self ):
63
- self .dtypes = []
66
+ self .dtypes = [] # type: List[Type[ExtensionDtype]]
64
67
65
- def register (self , dtype ) :
68
+ def register (self , dtype : Type [ 'ExtensionDtype' ]) -> None :
66
69
"""
67
70
Parameters
68
71
----------
69
72
dtype : ExtensionDtype
70
73
"""
71
- if not issubclass (dtype , ( PandasExtensionDtype , ExtensionDtype ) ):
74
+ if not issubclass (dtype , ExtensionDtype ):
72
75
raise ValueError ("can only register pandas extension dtypes" )
73
76
74
77
self .dtypes .append (dtype )
75
78
76
- def find (self , dtype ):
79
+ def find (self ,
80
+ dtype : Type ['ExtensionDtype' ],
81
+ ) -> Optional [Type [ExtensionDtype ]]:
77
82
"""
78
83
Parameters
79
84
----------
@@ -126,16 +131,20 @@ class PandasExtensionDtype(_DtypeOpsMixin):
126
131
isnative = 0
127
132
_cache = {} # type: Dict[str_type, 'PandasExtensionDtype']
128
133
129
- def __unicode__ (self ):
134
+ def __unicode__ (self ) -> str_type :
130
135
return self .name
131
136
132
- def __str__ (self ):
137
+ @property
138
+ def name (self ) -> str_type :
139
+ raise AbstractMethodError (self )
140
+
141
+ def __str__ (self ) -> str_type :
133
142
"""
134
143
Return a string representation for a particular Object
135
144
"""
136
145
return self .__unicode__ ()
137
146
138
- def __bytes__ (self ):
147
+ def __bytes__ (self ) -> bytes :
139
148
"""
140
149
Return a string representation for a particular object.
141
150
"""
@@ -144,22 +153,22 @@ def __bytes__(self):
144
153
encoding = get_option ("display.encoding" )
145
154
return self .__unicode__ ().encode (encoding , 'replace' )
146
155
147
- def __repr__ (self ):
156
+ def __repr__ (self ) -> str_type :
148
157
"""
149
158
Return a string representation for a particular object.
150
159
"""
151
160
return str (self )
152
161
153
- def __hash__ (self ):
162
+ def __hash__ (self ) -> int :
154
163
raise NotImplementedError ("sub-classes should implement an __hash__ "
155
164
"method" )
156
165
157
- def __getstate__ (self ):
166
+ def __getstate__ (self ) -> Dict [ str_type , Any ] :
158
167
# pickle support; we don't want to pickle the cache
159
168
return {k : getattr (self , k , None ) for k in self ._metadata }
160
169
161
170
@classmethod
162
- def reset_cache (cls ):
171
+ def reset_cache (cls ) -> None :
163
172
""" clear the cache """
164
173
cls ._cache = {}
165
174
@@ -223,17 +232,24 @@ class CategoricalDtype(PandasExtensionDtype, ExtensionDtype):
223
232
_metadata = ('categories' , 'ordered' )
224
233
_cache = {} # type: Dict[str_type, PandasExtensionDtype]
225
234
226
- def __init__ (self , categories = None , ordered = None ):
235
+ def __init__ (self , categories = None , ordered : bool = None ):
227
236
self ._finalize (categories , ordered , fastpath = False )
228
237
229
238
@classmethod
230
- def _from_fastpath (cls , categories = None , ordered = None ):
239
+ def _from_fastpath (cls ,
240
+ categories = None ,
241
+ ordered : bool = None
242
+ ) -> 'CategoricalDtype' :
231
243
self = cls .__new__ (cls )
232
244
self ._finalize (categories , ordered , fastpath = True )
233
245
return self
234
246
235
247
@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' :
237
253
if categories is ordered is None :
238
254
return dtype
239
255
if categories is None :
@@ -243,8 +259,12 @@ def _from_categorical_dtype(cls, dtype, categories=None, ordered=None):
243
259
return cls (categories , ordered )
244
260
245
261
@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' :
248
268
"""
249
269
Construct dtype from the input parameters used in :class:`Categorical`.
250
270
@@ -326,7 +346,11 @@ def _from_values_or_dtype(cls, values=None, categories=None, ordered=None,
326
346
327
347
return dtype
328
348
329
- def _finalize (self , categories , ordered , fastpath = False ):
349
+ def _finalize (self ,
350
+ categories ,
351
+ ordered : Optional [bool ],
352
+ fastpath : bool = False ,
353
+ ) -> None :
330
354
331
355
if ordered is not None :
332
356
self .validate_ordered (ordered )
@@ -338,14 +362,14 @@ def _finalize(self, categories, ordered, fastpath=False):
338
362
self ._categories = categories
339
363
self ._ordered = ordered
340
364
341
- def __setstate__ (self , state ) :
365
+ def __setstate__ (self , state : 'Dict[str_type, Any]' ) -> None :
342
366
# for pickle compat. __get_state__ is defined in the
343
367
# PandasExtensionDtype superclass and uses the public properties to
344
368
# pickle -> need to set the settable private ones here (see GH26067)
345
369
self ._categories = state .pop ('categories' , None )
346
370
self ._ordered = state .pop ('ordered' , False )
347
371
348
- def __hash__ (self ):
372
+ def __hash__ (self ) -> int :
349
373
# _hash_categories returns a uint64, so use the negative
350
374
# space for when we have unknown categories to avoid a conflict
351
375
if self .categories is None :
@@ -356,7 +380,7 @@ def __hash__(self):
356
380
# We *do* want to include the real self.ordered here
357
381
return int (self ._hash_categories (self .categories , self .ordered ))
358
382
359
- def __eq__ (self , other ) :
383
+ def __eq__ (self , other : Any ) -> bool :
360
384
"""
361
385
Rules for CDT equality:
362
386
1) Any CDT is equal to the string 'category'
@@ -403,7 +427,7 @@ def __repr__(self):
403
427
return tpl .format (data , self .ordered )
404
428
405
429
@staticmethod
406
- def _hash_categories (categories , ordered = True ):
430
+ def _hash_categories (categories , ordered : Union [ bool , None ] = True ) -> int :
407
431
from pandas .core .util .hashing import (
408
432
hash_array , _combine_hash_arrays , hash_tuples
409
433
)
@@ -453,20 +477,17 @@ def construct_array_type(cls):
453
477
return Categorical
454
478
455
479
@classmethod
456
- def construct_from_string (cls , string ) :
480
+ def construct_from_string (cls , string : str_type ) -> 'CategoricalDtype' :
457
481
"""
458
482
attempt to construct this type from a string, raise a TypeError if
459
483
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" )
467
488
468
489
@staticmethod
469
- def validate_ordered (ordered ) :
490
+ def validate_ordered (ordered : bool ) -> None :
470
491
"""
471
492
Validates that we have a valid ordered parameter. If
472
493
it is not a boolean, a TypeError will be raised.
@@ -486,7 +507,7 @@ def validate_ordered(ordered):
486
507
raise TypeError ("'ordered' must either be 'True' or 'False'" )
487
508
488
509
@staticmethod
489
- def validate_categories (categories , fastpath = False ):
510
+ def validate_categories (categories , fastpath : bool = False ):
490
511
"""
491
512
Validates that we have good categories
492
513
@@ -500,7 +521,7 @@ def validate_categories(categories, fastpath=False):
500
521
-------
501
522
categories : Index
502
523
"""
503
- from pandas import Index
524
+ from pandas . core . indexes . base import Index
504
525
505
526
if not fastpath and not is_list_like (categories ):
506
527
msg = "Parameter 'categories' must be list-like, was {!r}"
@@ -519,9 +540,9 @@ def validate_categories(categories, fastpath=False):
519
540
if isinstance (categories , ABCCategoricalIndex ):
520
541
categories = categories .categories
521
542
522
- return categories
543
+ return typing . cast ( Index , categories )
523
544
524
- def update_dtype (self , dtype ) :
545
+ def update_dtype (self , dtype : 'CategoricalDtype' ) -> 'CategoricalDtype' :
525
546
"""
526
547
Returns a CategoricalDtype with categories and ordered taken from dtype
527
548
if specified, otherwise falling back to self if unspecified
@@ -560,17 +581,18 @@ def categories(self):
560
581
"""
561
582
An ``Index`` containing the unique categories allowed.
562
583
"""
563
- return self ._categories
584
+ from pandas import Index
585
+ return typing .cast (Index , self ._categories )
564
586
565
587
@property
566
- def ordered (self ):
588
+ def ordered (self ) -> Optional [ bool ] :
567
589
"""
568
590
Whether the categories have an ordered relationship.
569
591
"""
570
592
return self ._ordered
571
593
572
594
@property
573
- def _is_boolean (self ):
595
+ def _is_boolean (self ) -> bool :
574
596
from pandas .core .dtypes .common import is_bool_dtype
575
597
576
598
return is_bool_dtype (self .categories )
0 commit comments