Search code examples
pythonlintmypypep

Linting variable annotation typo from PEP 526


I just had to debug a problem in production that boils down to the following behavior.

What I should have typed:

>>> import pandas as pd
>>> from io import StringIO
>>> a: pd.DataFrame = pd.read_csv(StringIO('a,b,c\n1,2,3'))
>>> isinstance(a, pd.DataFrame)
True

What I actually typed:

>>> a = pd.DataFrame = pd.read_csv(StringIO('a,b,c\n1,2,3'))
>>> isinstance(a, pd.DataFrame)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: isinstance() arg 2 must be a type or tuple of types

This was hard to track, because the isinstance() check was added months after the typo was made. The original code worked because pd.DataFrame wasn't used anywhere else in the scope.

Is there any way to catch this nasty typo? mypy doesn't see a problem with it.


Edit: the original question used list instead of pd.DataFrame, but as pointed out by some users, both this flake8 plugin and pylint W0622 can detect redefined builtins.


Solution

  • TL;DR

    pip install pandas-stubs
    

    And mypy should start failing with:

    error: Cannot assign to a type
    

    Long answer

    You are correct in assuming that mypy should have blocked this. But the problem is that the pandas project does not includes type information yet. By now (March 2021) the pandas team has it's own stub project in progress see https://pypi.org/project/pandas-stubs/.