Help! My client code isn't being type checked by mypy
That was the issue I had this morning. I had written some piece of code with type annotations but obviously wrong type assignments in unit tests, but mypy was reporting that everything was OK.
I had code like this:
# lib.py
from dataclasses import dataclass
@dataclass
class Question:
text: str
options: list['Option'] | None = None
@dataclass
class Option:
text: str
correct: bool = False
And a test like this:
# test_lib.py
import unittest
import lib
class QuestionTestCase(unittest.TestCase):
def test_create_question(self):
q = lib.Question(text=1)
q.options = 2
if __name__ == "__main__":
unittest.main()
Type checking with mypy gave me no errors.
$ mypy lib.py test_lib.py
Success: no issues found in 2 source files
If you can follow the code, type checking the test code should produce
errors as I’m assigning an integer to Question.text
instead of a
a string, and similarly, Question.options
should be optional list of
Option
, whereas I assigned an integer.
A bit of digging, and I found out that I had to add annotations to the test methods as well like below. This would signal to mypy that I wanted to type check the method as well.
...
class QuestionTestCase(unittest.TestCase):
def test_create_question(self) -> None: # annotate here
q = lib.Question(text=1)
q.options = 2
...
mypy should now show errors.
$ mypy lib.py test_lib.py
test_lib.py:7: error: Argument "text" to "Question" has incompatible type "int"; expected "str" [arg-type]
test_lib.py:8: error: Incompatible types in assignment (expression has type "int", variable has type "list[Option] | None") [assignment]
Found 2 errors in 1 file (checked 2 source files)
Another option you can use, if you don’t want to go annotating all
tests you already have, is to run mypy with the flag
--check-untyped-defs
or add it in pyproject.toml
.
$ mypy --check-untyped-defs lib.py test_lib.py
test_lib.py:7: error: Argument "text" to "Question" has incompatible type "int"; expected "str" [arg-type]
test_lib.py:8: error: Incompatible types in assignment (expression has type "int", variable has type "list[Option] | None") [assignment]
Found 2 errors in 1 file (checked 2 source files)
This is explained on the page of Common Issues and solutions. The whole of it is worth reading.
I don’t know why I haven’t encountered this issue before over the
years, probably because the projects I’ve worked on didn’t type check
unit tests or already had check-untyped-defs
set.
It’s probably useful every once in a while setting up a small projects by hand from scratch to identify such kinds of issues.