Hey! These docs are for version 2.10, which is no longer officially supported. Click here for the latest version, 2.18!

## Activating MyPy

To opt-in, add `pants.backend.python.typecheck.mypy` to `backend_packages` in your config file.

This will register a new `check` goal:

Benefit of Pants: typecheck Python 2-only and Python 3-only code at the same time

MyPy determines which Python version to use based on its `python_version` option. If that's undefined, MyPy uses the interpreter the tool is run with. Because you can only use one config file at a time with MyPy, you cannot normally say to use `2.7` for part of your codebase but `3.6` for the rest; you must choose a single version.

Instead, Pants will group your targets based on their [interpreter constraints](🔗), and run all the Python 2 targets together and all the Python 3 targets together. It will automatically set `python_version` to the minimum compatible interpreter, such as a constraint like `["==2.7.*", ">3.6"]` using `2.7`.

To turn this off, you can still set `python_version` in `mypy.ini` or `--python-version`/`--py2` in `--mypy-args`; Pants will respect the value you set.

### Hook up a MyPy config file

Pants will automatically include your config file if it's located at `mypy.ini`, `.mypy.ini`, `setup.cfg`, or `pyproject.toml`.

Otherwise, you must set the option `[mypy].config` for Pants to include the config file in the process's sandbox and to instruct MyPy to load it.

### Change the MyPy version

Use the `version` option in the `[mypy]` scope:

If you change this option, Pants's default lockfile for MyPy will not work. Either set the `lockfile` option to a custom path or `"<none>"` to opt out. See [Third-party dependencies](🔗).

### Incrementally adopt MyPy with `skip_mypy=True`

You can tell Pants to skip running MyPy on certain files by adding `skip_mypy=True` to the relevant targets.

When you run `./pants check ::`, Pants will skip any files belonging to skipped targets.

MyPy may still try to check the skipped files!

The `skip_mypy` field only tells Pants not to provide the skipped files as direct input to MyPy. But MyPy, by default, will still try to check files that are [dependencies of the direct inputs](🔗). So if your skipped files are dependencies of unskipped files, they may still be checked.

To change this behavior, use MyPy's [`--follow-imports` option](🔗), typically by setting it to `silent`. You can do so either by adding it to the [`args` option](🔗) in the `[mypy]` section of your Pants config file, or by setting it in [`mypy.ini`](🔗).

### First-party type stubs (`.pyi` files)

You can use [`.pyi` files](🔗) for both first-party and third-party code. Include the `.pyi` files in the `sources` field for `python_source` / `python_sources` and `python_test` / `python_tests` targets. MyPy will use these stubs rather than looking at the implementation.

Pants's dependency inference knows to infer a dependency both on the implementation and the type stub. You can verify this by running `./pants dependencies path/to/file.py`.

When writing stubs for third-party libraries, you may need the set up the `[source].root_patterns` option so that [source roots](🔗) are properly stripped. For example:

### Third-party type stubs

You can install third-party type stubs (e.g. `types-requests`) like [normal Python requirements](🔗). Pants will infer a dependency on both the type stub and the actual dependency, e.g. both `types-requests` and `requests`, which you can confirm by running `./pants dependencies path/to/f.py`.

You can also install the type stub via the option `[mypy].extra_type_stubs`, which ensures the stubs are only used when running MyPy and are not included when, for example, [packaging a PEX](🔗).

### Add a third-party plugin

Add the plugin to the `extra_requirements` option in the `[mypy]` scope, then update your `mypy.ini` to load the plugin:

If you change this option, Pants's default lockfile for MyPy will not work. Either set the `lockfile` option to a custom path or `"<none>"` to opt out. See [Third-party dependencies](🔗).

For some plugins, like `django-stubs`, you may need to always load certain source files, such as a `settings.py` file. You can make sure that this source file is always used by hijacking the `source_plugins` option, which allows you to specify targets whose `sources` should always be used when running MyPy. See the below section for more information about source plugins.

Some MyPy plugins also include type stubs, such as `django-stubs`. For type stubs to be used, the requirement must either be included in `[mypy].extra_type_stubs` or be loaded like a normal [third-party dependency](🔗), such as including in a `requirements.txt` file.

For example, to fully use the `django-stubs` plugin, your setup might look like this:

MyPy Protobuf support

Add `mypy_plugin = true` to the `[python-protobuf]` scope. See [Protobuf](🔗) for more information.

### Add a first-party plugin

To add a [MyPy plugin](🔗) you wrote, add a `python_source` or `python_sources` target with the plugin's Python file(s) included in the `sources` field.

Then, add `plugins = path.to.module` to your MyPy config file, using the name of the module without source roots. For example, if your Python file is called `pants-plugins/mypy_plugins/custom_plugin.py`, and you set `pants-plugins` as a source root, then set `plugins = mypy_plugins.custom_plugin`. Set the `config` option in the `[mypy]` scope in your `pants.toml` to point to your MyPy config file.

Finally, set the option `source_plugins` in the `[mypy]` scope to include this target's address, e.g. `source_plugins = ["pants-plugins/mypy_plugins:plugin"]`. This will ensure that your plugin's sources are always included in the subprocess.

For example:

Because this is a `python_source` or `python_sources` target, Pants will treat this code like your other Python files, such as running linters on it or allowing you to write a `python_distribution` target to distribute the plugin externally.

### Reports

MyPy can generate [various report files](🔗).

For Pants to properly preserve the reports, instruct MyPy to write to the `reports/` folder by updating its config file or `--mypy-args`. For example, in your pants.toml:

Pants will copy all reports into the folder `dist/check/mypy`.

## Known limitations

### Performance is often slower than normal

Pants does not yet leverage MyPy's caching mechanism and daemon, so a typical run with Pants will likely be slower than using MyPy directly.

We are [working to figure out](🔗) how to leverage MyPy's cache in a way that is safe and allows for things like remote execution.

## Tip: only run over changed files and their dependees

When changing type hints code, you not only need to run over the changed files, but also any code that depends on the changed files:

See [Advanced target selection](🔗) for more information.