Skip to content

Implementation Overview

Jukka Lehtosalo edited this page Oct 5, 2016 · 16 revisions

This is a general introduction to the mypy implementation. The linked subpages have more detailed information. The file links point to the mypy git repository.

Tests

The file runtests.py runs all the tests. Test suites for individual components are in the files mypy/test/test*.py. You can run many of these individually by doing runtests.py testfoobar. Type checker test cases (testcheck.py) have been migrated to pytest and you can run them using py.test mypy. (We are planning to migrate all test cases to pytest eventually -- any help is appreciated here.)

Many test suites store test case descriptions in text files (test-data/unit/*.test). The module mypy.test.data parses these descriptions. The package mypy.myunit contains the test framework used for the non-checker test cases. The unit tests use minimal stubs for builtins, so a lot of operations are not possible. You should define any needed functionality within the test case (see below for more about this). This way tests run much faster and don't break if the stubs change. If your test crashes mysteriously even though the code works otherwise, you should make sure you have all the stubs you need for your test case, including built-in classes such as list or dict, as these are not included by default.

Notes about test cases:

  • Python evaluation test cases are a little different from unit tests (mypy/test/testpythoneval.py, test-data/unit/pythoneval.test). These type check programs and run them. Unlike the unit tests, these use the full builtins and library stubs instead of minimal ones. Run them using runtests.py testpythoneval.

More things (this should be expanded):

  • You can run just a subset of tests by giving a wildcard argument, e.g. runtests.py unit-test -a "*Overload*" to run all unit tests with Overload as a substring.
  • The builtins used by default in unit tests live in test-data/unit/lib-stub. Individual tests cases can override the stubs by using [builtins fixtures/foo.py]; this targets files in mypy/test/data/fixtures. You are free add additional stubs to this directory, but generally don't update files in lib-stub without first discussing the addition with other mypy developers, as additions could slow down the test suite.

Structure of the type checker

Common passes:

  1. Lexical Analyzer (mypy/lex.py)
  • Transform a string that represents mypy source code into a list of tokens
  1. Python Parser (mypy/parse.py)
  • Transform a list of tokens into an abstract syntax tree (AST)
  • Parse tree is defined in the files mypy/nodes.py, mypy/types.py (also noderepr.py and typerepr.py)
  1. Semantic Analyzer (mypy/semanal.py, mypy/typeanal.py)
  • Bind names to definitions
  • Perform various consistency checks
  1. Type Checker (mypy/checker.py, mypy/checkexpr.py, mypy/checkmember.py)
  • Type check the program
  • Perform type inference

Other important files

  • Build Manager (mypy/build.py)
    • Coordinate a build, manage dependencies between modules and perform compilation passes in the correct order.
  • The driver (mypy/main.py)
    • Perform all the build steps and run the program. Most of the work is done by the build manager.