Repository: pandas-dev/pandas

Issue:
Fix Type Annotations in pandas.core.dtypes
Part of #25882

pandas.core.dtypes.dtypes and .missing have the following errors:
```
pandas/core/dtypes/dtypes.py:112: error: Need type annotation for 'shape'
pandas/core/dtypes/dtypes.py:117: error: Need type annotation for '_cache'
pandas/core/dtypes/dtypes.py:175: error: Definition of "type" in base class "PandasExtensionDtype" is incompatible with definition in base class "ExtensionDtype"
pandas/core/dtypes/dtypes.py:175: error: Definition of "kind" in base class "PandasExtensionDtype" is incompatible with definition in base class "ExtensionDtype"
pandas/core/dtypes/dtypes.py:220: error: Incompatible types in assignment (expression has type "Type[CategoricalDtypeType]", base class "PandasExtensionDtype" defined the type as "None")
pandas/core/dtypes/dtypes.py:221: error: Incompatible types in assignment (expression has type "str", base class "PandasExtensionDtype" defined the type as "None")
pandas/core/dtypes/dtypes.py:222: error: Incompatible types in assignment (expression has type "str", base class "PandasExtensionDtype" defined the type as "None")
pandas/core/dtypes/dtypes.py:224: error: Incompatible types in assignment (expression has type "Tuple[str, str]", base class "_DtypeOpsMixin" defined the type as "Tuple[]")
pandas/core/dtypes/dtypes.py:225: error: Need type annotation for '_cache'
pandas/core/dtypes/dtypes.py:577: error: Definition of "type" in base class "PandasExtensionDtype" is incompatible with definition in base class "ExtensionDtype"
pandas/core/dtypes/dtypes.py:577: error: Definition of "kind" in base class "PandasExtensionDtype" is incompatible with definition in base class "ExtensionDtype"
pandas/core/dtypes/dtypes.py:588: error: Incompatible types in assignment (expression has type "str", base class "PandasExtensionDtype" defined the type as "None")
pandas/core/dtypes/dtypes.py:589: error: Incompatible types in assignment (expression has type "str", base class "PandasExtensionDtype" defined the type as "None")
pandas/core/dtypes/dtypes.py:593: error: Incompatible types in assignment (expression has type "Tuple[str, str]", base class "_DtypeOpsMixin" defined the type as "Tuple[]")
pandas/core/dtypes/dtypes.py:595: error: Need type annotation for '_cache'
pandas/core/dtypes/dtypes.py:732: error: Definition of "kind" in base class "ExtensionDtype" is incompatible with definition in base class "PandasExtensionDtype"
pandas/core/dtypes/dtypes.py:732: error: Definition of "type" in base class "ExtensionDtype" is incompatible with definition in base class "PandasExtensionDtype"
pandas/core/dtypes/dtypes.py:740: error: Incompatible types in assignment (expression has type "str", base class "PandasExtensionDtype" defined the type as "None")
pandas/core/dtypes/dtypes.py:741: error: Incompatible types in assignment (expression has type "str", base class "PandasExtensionDtype" defined the type as "None")
pandas/core/dtypes/dtypes.py:744: error: Incompatible types in assignment (expression has type "Tuple[str]", base class "_DtypeOpsMixin" defined the type as "Tuple[]")
pandas/core/dtypes/dtypes.py:746: error: Need type annotation for '_cache'
pandas/core/dtypes/dtypes.py:855: error: Definition of "type" in base class "PandasExtensionDtype" is incompatible with definition in base class "ExtensionDtype"
pandas/core/dtypes/dtypes.py:855: error: Definition of "kind" in base class "PandasExtensionDtype" is incompatible with definition in base class "ExtensionDtype"
pandas/core/dtypes/dtypes.py:864: error: Incompatible types in assignment (expression has type "str", base class "PandasExtensionDtype" defined the type as "None")
pandas/core/dtypes/dtypes.py:867: error: Incompatible types in assignment (expression has type "Tuple[str]", base class "_DtypeOpsMixin" defined the type as "Tuple[]")
pandas/core/dtypes/dtypes.py:869: error: Need type annotation for '_cache'

pandas/core/dtypes/missing.py:6: error: Module 'pandas._libs' has no attribute 'missing'
```
Working on a PR to fix these.


Discussion:

Resolving patch:
diff --git a/pandas/core/dtypes/base.py b/pandas/core/dtypes/base.py
--- a/pandas/core/dtypes/base.py
+++ b/pandas/core/dtypes/base.py
@@ -1,5 +1,5 @@
 """Extend pandas with custom array types"""
-from typing import List, Optional, Type
+from typing import List, Optional, Tuple, Type
 
 import numpy as np
 
@@ -24,7 +24,7 @@ class _DtypeOpsMixin(object):
     # of the NA value, not the physical NA vaalue for storage.
     # e.g. for JSONArray, this is an empty dictionary.
     na_value = np.nan
-    _metadata = ()
+    _metadata = ()  # type: Tuple[str, ...]
 
     def __eq__(self, other):
         """Check whether 'other' is equal to self.
@@ -219,8 +219,7 @@ def type(self) -> Type:
         raise AbstractMethodError(self)
 
     @property
-    def kind(self):
-        # type () -> str
+    def kind(self) -> str:
         """
         A character code (one of 'biufcmMOSUV'), default 'O'
 
diff --git a/pandas/core/dtypes/dtypes.py b/pandas/core/dtypes/dtypes.py
--- a/pandas/core/dtypes/dtypes.py
+++ b/pandas/core/dtypes/dtypes.py
@@ -1,5 +1,6 @@
 """ define extension dtypes """
 import re
+from typing import Any, Dict, Optional, Tuple, Type
 import warnings
 
 import numpy as np
@@ -16,6 +17,8 @@
 from .base import ExtensionDtype, _DtypeOpsMixin
 from .inference import is_list_like
 
+str_type = str
+
 
 def register_extension_dtype(cls):
     """
@@ -104,17 +107,21 @@ class PandasExtensionDtype(_DtypeOpsMixin):
 
     THIS IS NOT A REAL NUMPY DTYPE
     """
-    type = None
+    type = None  # type: Any
+    kind = None  # type: Any
+    # The Any type annotations above are here only because mypy seems to have a
+    # problem dealing with with multiple inheritance from PandasExtensionDtype
+    # and ExtensionDtype's @properties in the subclasses below. The kind and
+    # type variables in those subclasses are explicitly typed below.
     subdtype = None
-    kind = None
-    str = None
+    str = None  # type: Optional[str_type]
     num = 100
-    shape = tuple()
+    shape = tuple()  # type: Tuple[int, ...]
     itemsize = 8
     base = None
     isbuiltin = 0
     isnative = 0
-    _cache = {}
+    _cache = {}  # type: Dict[str_type, 'PandasExtensionDtype']
 
     def __unicode__(self):
         return self.name
@@ -217,12 +224,12 @@ class CategoricalDtype(PandasExtensionDtype, ExtensionDtype):
     """
     # TODO: Document public vs. private API
     name = 'category'
-    type = CategoricalDtypeType
-    kind = 'O'
+    type = CategoricalDtypeType  # type: Type[CategoricalDtypeType]
+    kind = 'O'  # type: str_type
     str = '|O08'
     base = np.dtype('O')
     _metadata = ('categories', 'ordered')
-    _cache = {}
+    _cache = {}  # type: Dict[str_type, PandasExtensionDtype]
 
     def __init__(self, categories=None, ordered=None):
         self._finalize(categories, ordered, fastpath=False)
@@ -584,15 +591,15 @@ class DatetimeTZDtype(PandasExtensionDtype, ExtensionDtype):
     THIS IS NOT A REAL NUMPY DTYPE, but essentially a sub-class of
     np.datetime64[ns]
     """
-    type = Timestamp
-    kind = 'M'
+    type = Timestamp  # type: Type[Timestamp]
+    kind = 'M'  # type: str_type
     str = '|M8[ns]'
     num = 101
     base = np.dtype('M8[ns]')
     na_value = NaT
     _metadata = ('unit', 'tz')
     _match = re.compile(r"(datetime64|M8)\[(?P<unit>.+), (?P<tz>.+)\]")
-    _cache = {}
+    _cache = {}  # type: Dict[str_type, PandasExtensionDtype]
 
     def __init__(self, unit="ns", tz=None):
         """
@@ -736,14 +743,14 @@ class PeriodDtype(ExtensionDtype, PandasExtensionDtype):
 
     THIS IS NOT A REAL NUMPY DTYPE, but essentially a sub-class of np.int64.
     """
-    type = Period
-    kind = 'O'
+    type = Period  # type: Type[Period]
+    kind = 'O'  # type: str_type
     str = '|O08'
     base = np.dtype('O')
     num = 102
     _metadata = ('freq',)
     _match = re.compile(r"(P|p)eriod\[(?P<freq>.+)\]")
-    _cache = {}
+    _cache = {}  # type: Dict[str_type, PandasExtensionDtype]
 
     def __new__(cls, freq=None):
         """
@@ -860,13 +867,13 @@ class IntervalDtype(PandasExtensionDtype, ExtensionDtype):
     THIS IS NOT A REAL NUMPY DTYPE
     """
     name = 'interval'
-    kind = None
+    kind = None  # type: Optional[str_type]
     str = '|O08'
     base = np.dtype('O')
     num = 103
     _metadata = ('subtype',)
     _match = re.compile(r"(I|i)nterval\[(?P<subtype>.+)\]")
-    _cache = {}
+    _cache = {}  # type: Dict[str_type, PandasExtensionDtype]
 
     def __new__(cls, subtype=None):
         """
diff --git a/pandas/core/dtypes/missing.py b/pandas/core/dtypes/missing.py
--- a/pandas/core/dtypes/missing.py
+++ b/pandas/core/dtypes/missing.py
@@ -3,7 +3,8 @@
 """
 import numpy as np
 
-from pandas._libs import lib, missing as libmissing
+from pandas._libs import lib
+import pandas._libs.missing as libmissing
 from pandas._libs.tslibs import NaT, iNaT
 
 from .common import (


Test patch: