rules_mypy 0.40.0Latest published 9.2mo ago
MODULE.bazel
bazel_dep(name = "rules_mypy", version = "0.40.0")
README

rules_mypy

An aspect to instrument py_* targets with mypy type-checking.

Compared to bazel-mypy-integration, this ruleset aims to make a couple of improvements:

  • Propagation of the mypy cache between dependencies within a repository to avoid exponential type-checking work
  • Robust (and automated) support for including 3rd party types/stubs packages

[!WARNING]
rules_mypy's build actions produce mypy caches as outputs, and these may contain large file counts and that will only grow as a dependency chain grows. This may have an impact on the size and usage of build and/or remote caches.

Usage

This aspect will run over any py_binary, py_library or py_test.

Setup is significantly easier with bzlmod, we recommend and predominantly support bzlmod, though these rules should work without issue in non-bzlmod setups, albeit with more work to configure.

Bzlmod Setup

Add rules_mypy to your MODULE.bazel:

bazel_dep(name = "rules_mypy", version = "0.0.0")

Optionally, configure a types repository:

Many Python packages have separately published types/stubs packages. While mypy (and these rules) will work without including these types, this ruleset provides some utilities for leveraging these types to improve mypy's type checking.

types = use_extension("@rules_mypy//mypy:types.bzl", "types")
types.requirements(
    name = "pip_types",
    # `@pip` in the next line corresponds to the `hub_name` when using
    # rules_python's `pip.parse(...)`.
    pip_requirements = "@pip//:requirements.bzl",
    # also legal to pass a `requirements.in` here
    requirements_txt = "//:requirements.txt",
)
use_repo(types, "pip_types")

Configure mypy_aspect.

Define a new aspect in a .bzl file (such as ./tools/aspects.bzl):

load("@pip_types//:types.bzl", "types")
load("@rules_mypy//mypy:mypy.bzl", "mypy")

mypy_aspect = mypy(types = types)

Update your .bazelrc to include this new aspect:

# register mypy_aspect with Bazel
build --aspects //tools:aspects.bzl%mypy_aspect

# optionally, default enable the mypy checks
build --output_groups=+mypy

Customizing mypy

Configuring mypy with mypy.ini

mypy's behavior may be customized using a mypy config file file. To use a mypy config file, pass a label for a valid config file to the mypy aspect factory:

mypy_aspect = mypy(
    mypy_ini = "@@//:mypy.ini",
    types = types,
)

[!NOTE] The label passed to mypy_ini needs to be absolute (a prefix of @@ means the root repo).

[!NOTE] mypy.ini files should likely contain the following lines to suppress type-checking 3rd party modules.

follow_imports = silent
follow_imports_for_stubs = True

Changing the version of mypy and/or including plugins

To customize the version of mypy, use rules_python's requirements resolution and construct a custom mypy CLI:

# in a BUILD file
load("@pip//:requirements.bzl", "requirements") # '@pip' must match configured pip hub_name
load("@rules_mypy//mypy:mypy.bzl", "mypy", "mypy_cli")

mypy_cli(
    name = "mypy_cli",
    mypy_requirement = requirement("mypy"),
)

And in your aspects.bzl (or similar) file:

load("@rules_mypy//mypy:mypy.bzl", "mypy")

mypy_aspect = mypy(
    mypy_cli = ":mypy_cli",
    types = types,
)

Further, to use mypy plugins referenced in any config file, use the deps attribute of mypy_cli:

# in a BUILD file
load("@pip//:requirements.bzl", "requirement") # '@pip' must match configured pip hub_name
load("@rules_mypy//mypy:mypy.bzl", "mypy", "mypy_cli")

mypy_cli(
    name = "mypy_cli",
    mypy_requirement = requirement("mypy"),
    deps = [
        requirement("pydantic"),
    ],
)

Skipping Targets

Skip running mypy on targets by tagging with no-mypy, or customize the tags that will suppress mypy by providing a list to the suppression_tags argument of the mypy aspect initializer:

load("@rules_mypy//mypy:mypy.bzl", "mypy")

mypy_aspect = mypy(
    suppression_tags = ["no-mypy", "no-checks"],
    types = types,
)

Running in opt-in mode

To add type checking to a codebase incrementally, configure a list of opt-in tags that will suppress running mypy by default unless a target is tagged explicitly with one of the opt-in tags.

load("@rules_mypy//mypy:mypy.bzl", "mypy")

mypy_aspect = mypy(
    opt_in_tags = ["typecheck"],
    types = types,
)

About

a Bazel mypy aspect

@theoremlp/rules_mypy@theoremlp
Homepage
12stars
Tuesday, August 12, 2025

Languages

Python19.9%

Maintainers

@mark-thm
@theoremlp

Versions

0.39.0 +5d2025-08-01
0.38.0 +1.2mo2025-07-26
0.36.0 +1.6mo2025-06-19
0.32.0 +14d2025-04-30
0.31.0 +11d2025-04-16
0.30.0 +1.1mo2025-04-04
0.29.0 +7d2025-03-01
0.28.0 +8d2025-02-22
0.26.0 +15d2025-02-13
0.24.0 +4d2025-01-28
0.23.0 +15d2025-01-24
0.22.0 +19d2025-01-08
0.21.0 +6d2024-12-19
0.20.0 +3d2024-12-13
0.19.0 +18h2024-12-10
0.18.0 +10d2024-12-09
0.17.0 +7d2024-11-29
0.16.0 +3d2024-11-21
0.15.0 +3d2024-11-18
0.14.0 +21d2024-11-15
0.11.0 +7d2024-10-24
0.10.0 +6d2024-10-17
0.9.0 +28d2024-10-11
0.7.0 +16d2024-09-12
0.6.0 +7d2024-08-26
0.5.0 +3d2024-08-19
0.4.0 +7d2024-08-16
0.3.1 +2d2024-08-09
0.2.0 +15h2024-08-06
0.1.12024-08-06