Skip to content
Jukka Lehtosalo edited this page Jun 29, 2022 · 2 revisions

The build manager (mypy/build.py) is responsible for orchestrating a mypy run.

The main entry point is the function mypy.build.build. It is given a set of files to process and the options/flags.

The build manager does these primary things:

  1. Resolve imports to find all files that need to be processed (including stub files). Build an import dependency graph.
  2. Figure out the order in which to process the files. We process import dependencies first before processing a module, so that we can resolve references to names defined in the imported modules.
  3. Detect cyclic import dependencies, i.e. import cycles or strongly connected components (SCCs). Each SCC is processed as a unit, since each file in an import cycle could contains a reference to any other file within the cycle. (Note that each module is part of some SCC -- the simplest case is a SCC with a single file.)
  4. Run the various mypy passes on the files. This includes the Python Parser, Semantic Analyzer and Type Checker passes.
  5. If running in incremental mode, deserialize each SCC instead of processing them if neither the SCC nor any transitive dependency has changed since the previous run (and config options haven't changed).
  6. Return the ASTs of processed files, inferred types and any reported errors or notes to the caller.

Strongly connected components (SCCs)

Assume these properties:

  • Module a imports b.
  • Module b imports c and d.
  • Module c imports b.

Now we have an SCC dependency graph that looks like this:

  a → (b ↔ c) → d

Modules a and d form single-file SCCs. Modules b and c together form another SCC, since they depend on each other and form an import cycle.

Mypy will process the SCCs in this order:

  1. d
  2. b and c (conceptually together as a unit)
  3. a

(Each build will also include the builtins module and a few other stdlib modules, but we've omitted them from the above example for brevity.)