Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix type annotations in pandas.core.dtypes #26029

Merged
merged 4 commits into from
Apr 12, 2019

Conversation

gwrome
Copy link
Contributor

@gwrome gwrome commented Apr 8, 2019

This one was more complicated than other annotation corrections I've done. The following errors persisted even if the two type definitions in PandasExtensionDtype and ExtensionDtype were identical:

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: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: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: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"

I suspect this has something to do with how mypy handles classes with multiple inheritance and maybe even @property-decorated accessors. See, e.g., python/mypy#6585.

So to address the issue, I left the annotations in pandas.core.dtypes.base.ExtensionDtype.type and .kind (abstract-ish with @Property decorators) alone but for a format change. I set the corresponding type and kind variables in PandasExtensionDtype to take the Any type explicitly to "correct" the mypy error. Then to provide actual type checking I explicitly typed the kind and type variables in the subclasses, i.e., CategoricalDtype, DatetimeTZDtype, etc.

Not sure if this is the best approach, but it is a functioning approach that provides static type checking.

This commit addresses all 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'

@codecov
Copy link

codecov bot commented Apr 8, 2019

Codecov Report

Merging #26029 into master will decrease coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master   #26029      +/-   ##
==========================================
- Coverage   91.82%   91.82%   -0.01%     
==========================================
  Files         175      175              
  Lines       52540    52544       +4     
==========================================
  Hits        48247    48247              
- Misses       4293     4297       +4
Flag Coverage Δ
#multiple 90.38% <100%> (ø) ⬆️
#single 40.73% <100%> (-0.13%) ⬇️
Impacted Files Coverage Δ
pandas/core/dtypes/base.py 100% <100%> (ø) ⬆️
pandas/core/dtypes/missing.py 93.33% <100%> (+0.04%) ⬆️
pandas/core/dtypes/dtypes.py 96.12% <100%> (+0.01%) ⬆️
pandas/io/gbq.py 75% <0%> (-12.5%) ⬇️
pandas/core/frame.py 96.79% <0%> (-0.12%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 0610a60...845808b. Read the comment docs.

@codecov
Copy link

codecov bot commented Apr 8, 2019

Codecov Report

Merging #26029 into master will decrease coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master   #26029      +/-   ##
==========================================
- Coverage    91.9%   91.89%   -0.01%     
==========================================
  Files         175      175              
  Lines       52485    52489       +4     
==========================================
- Hits        48235    48234       -1     
- Misses       4250     4255       +5
Flag Coverage Δ
#multiple 90.45% <100%> (ø) ⬆️
#single 40.76% <100%> (-0.13%) ⬇️
Impacted Files Coverage Δ
pandas/core/dtypes/base.py 100% <100%> (ø) ⬆️
pandas/core/dtypes/missing.py 93.33% <100%> (+0.04%) ⬆️
pandas/core/dtypes/dtypes.py 96.12% <100%> (+0.01%) ⬆️
pandas/io/gbq.py 75% <0%> (-12.5%) ⬇️
pandas/core/frame.py 96.79% <0%> (-0.12%) ⬇️
pandas/util/testing.py 90.62% <0%> (-0.11%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6d9b702...85ef4b4. Read the comment docs.

Copy link
Member

@WillAyd WillAyd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you provide the errors this was resolving?

pandas/core/dtypes/dtypes.py Outdated Show resolved Hide resolved
pandas/core/dtypes/dtypes.py Show resolved Hide resolved
pandas/core/dtypes/dtypes.py Outdated Show resolved Hide resolved
pandas/core/dtypes/missing.py Show resolved Hide resolved
@WillAyd WillAyd added the Typing type annotations, mypy/pyright type checking label Apr 9, 2019
pandas/core/dtypes/dtypes.py Show resolved Hide resolved
pandas/core/dtypes/dtypes.py Outdated Show resolved Hide resolved
@@ -1,5 +1,7 @@
""" define extension dtypes """
import builtins
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I found some more information on this error:

python/mypy#1775

The suggested approach there is to alias the type rather than import builtins.

However, this comment by Guido might also be of importance:

python/mypy#1775 (comment)

His example cites a method where a subsequent annotation mangles a method with the name of bytes with the builtin. I imagine this is the same with the static variable (if you could confirm would be great) so we would have to be pretty careful when typing this module with str and type to avoid nuanced errors

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can confirm that within the body of the classes, the class variables str and type are clobbering the builtins. So, e.g, in the class itself (but not in its methods, which each have their own scope) isintance("asdf", str) will throw a TypeError because the second argument isn't a type or tuple of types. Likewise, isinstance(int, type) in that location will throw the same error.

Within the methods, things work normally, see e.g.,

if isinstance(dtype, str) and dtype == 'category':

Copy link
Member

@WillAyd WillAyd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned in comment would prefer a type alias to importing builtins based off of approach suggested in referenced issue

@jreback jreback added this to the 0.25.0 milestone Apr 12, 2019
@jreback
Copy link
Contributor

jreback commented Apr 12, 2019

lgtm. @WillAyd merge when satisfied

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Typing type annotations, mypy/pyright type checking
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Fix Type Annotations in pandas.core.dtypes
3 participants