Skip to content

Commit 6aa90ce

Browse files
Replace types.requirements() with load_stubs()
1 parent b859f41 commit 6aa90ce

File tree

11 files changed

+135
-157
lines changed

11 files changed

+135
-157
lines changed

examples/demo/MODULE.bazel

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,3 @@ pip.parse(
3737
},
3838
)
3939
use_repo(pip, "pip")
40-
41-
types = use_extension("@rules_mypy//mypy:types.bzl", "types")
42-
types.requirements(
43-
name = "pip_types",
44-
pip_requirements = "@pip//:requirements.bzl",
45-
requirements_txt = "//:requirements.txt",
46-
)
47-
use_repo(types, "pip_types")

examples/demo/py.bzl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"Custom py_library rule that also runs mypy."
22

3-
load("@pip_types//:types.bzl", "types")
4-
load("@rules_mypy//mypy:mypy.bzl", "mypy")
3+
load("@pip//:requirements.bzl", "all_requirements")
4+
load("@rules_mypy//mypy:mypy.bzl", "load_stubs", "mypy")
55

6-
mypy_aspect = mypy(types = types)
6+
stubs = load_stubs(requirements = all_requirements)
7+
8+
mypy_aspect = mypy(stubs = stubs)

examples/opt-in/MODULE.bazel

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,3 @@ pip.parse(
3737
},
3838
)
3939
use_repo(pip, "pip")
40-
41-
types = use_extension("@rules_mypy//mypy:types.bzl", "types")
42-
types.requirements(
43-
name = "pip_types",
44-
pip_requirements = "@pip//:requirements.bzl",
45-
requirements_txt = "//:requirements.txt",
46-
)
47-
use_repo(types, "pip_types")

examples/opt-in/py.bzl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
"Custom py_library rule that also runs mypy."
22

3-
load("@pip_types//:types.bzl", "types")
4-
load("@rules_mypy//mypy:mypy.bzl", "mypy")
3+
load("@pip//:requirements.bzl", "all_requirements")
4+
load("@rules_mypy//mypy:mypy.bzl", "load_stubs", "mypy")
5+
6+
stubs = load_stubs(requirements = all_requirements)
57

68
mypy_aspect = mypy(
79
# only run mypy on targets with the typecheck tag
810
opt_in_tags = ["typecheck"],
9-
types = types,
11+
stubs = stubs,
1012
)

mypy/BUILD.bazel

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,3 @@ bzl_library(
55
srcs = ["mypy.bzl"],
66
visibility = ["//visibility:public"],
77
)
8-
9-
bzl_library(
10-
name = "types",
11-
srcs = ["types.bzl"],
12-
visibility = ["//visibility:public"],
13-
)

mypy/mypy.bzl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
"Public API for interacting with the mypy rule."
22

3-
load("//mypy/private:mypy.bzl", _mypy = "mypy", _mypy_cli = "mypy_cli")
3+
load(
4+
"//mypy/private:mypy.bzl",
5+
_load_stubs = "load_stubs",
6+
_mypy = "mypy",
7+
_mypy_cli = "mypy_cli",
8+
)
9+
10+
load_stubs = _load_stubs
411

512
# re-export mypy aspect factory
613
mypy = _mypy

mypy/private/BUILD.bazel

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,6 @@ bzl_library(
1414
visibility = ["//mypy:__subpackages__"],
1515
)
1616

17-
bzl_library(
18-
name = "types_rules",
19-
srcs = ["types.bzl"],
20-
visibility = ["//mypy:__subpackages__"],
21-
)
22-
2317
pip_compile(
2418
name = "generate_requirements_lock",
2519
requirements_in = "requirements.in",

mypy/private/mypy.bzl

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ def _mypy_impl(target, ctx):
109109

110110
depsets = []
111111

112-
type_mapping = dict(zip([k.label for k in ctx.attr._types_keys], ctx.attr._types_values))
113-
dep_with_stubs = [_.label.workspace_root + "/site-packages" for _ in ctx.attr._types_keys]
112+
type_mapping = dict(zip([k.label for k in ctx.attr._stubs_keys], ctx.attr._stubs_values))
113+
dep_with_stubs = [_.label.workspace_root + "/site-packages" for _ in ctx.attr._stubs_keys]
114114
additional_types = [
115115
type_mapping[dep.label]
116116
for dep in ctx.rule.attr.deps
@@ -230,7 +230,7 @@ def _mypy_impl(target, ctx):
230230
def mypy(
231231
mypy_cli = None,
232232
mypy_ini = None,
233-
types = None,
233+
stubs = None,
234234
cache = True,
235235
color = True,
236236
suppression_tags = None,
@@ -242,15 +242,7 @@ def mypy(
242242
mypy_cli: (optional) a replacement mypy_cli to use (recommended to produce
243243
with mypy_cli macro)
244244
mypy_ini: (optional) mypy_ini file to use
245-
types: (optional) a dict of dependency label to types dependency label
246-
example:
247-
```
248-
{
249-
requirement("cachetools"): requirement("types-cachetools"),
250-
}
251-
```
252-
Use the types extension to create this map for a requirements.in
253-
or requirements.txt file.
245+
stubs: (optional) result from load_stubs()
254246
cache: (optional, default True) propagate the mypy cache
255247
color: (optional, default True) use color in mypy output
256248
suppression_tags: (optional, default ["no-mypy"]) tags that suppress running
@@ -262,8 +254,6 @@ def mypy(
262254
Returns:
263255
a mypy aspect.
264256
"""
265-
types = types or {}
266-
267257
additional_attrs = {}
268258

269259
return aspect(
@@ -284,15 +274,61 @@ def mypy(
284274
),
285275
# pass the dict[Label, Label] in parts because Bazel doesn't have
286276
# this kind of attr to pass naturally
287-
"_types_keys": attr.label_list(default = types.keys()),
288-
"_types_values": attr.label_list(default = types.values()),
277+
"_stubs_keys": attr.label_list(default = stubs.mapping.keys() if stubs else []),
278+
"_stubs_values": attr.label_list(default = stubs.mapping.values() if stubs else []),
289279
"_suppression_tags": attr.string_list(default = suppression_tags or ["no-mypy"]),
290280
"_opt_in_tags": attr.string_list(default = opt_in_tags or []),
291281
"cache": attr.bool(default = cache),
292282
"color": attr.bool(default = color),
293283
} | additional_attrs,
294284
)
295285

286+
def _load_stubs_from_requirements(requirements):
287+
# for a package "foo-bar", maps "foo_bar" to "@pip//foo_bar:pkg"
288+
parsed_reqs = {}
289+
for req in requirements:
290+
parsed_reqs[Label(req).package] = req
291+
292+
stubs = {}
293+
for req in requirements:
294+
req_name = Label(req).package
295+
296+
if req_name.endswith("_stubs"):
297+
base_req_name = req_name.removesuffix("_stubs")
298+
elif req_name.startswith("types_"):
299+
base_req_name = req_name.removeprefix("types_")
300+
else:
301+
continue
302+
303+
if base_req_name in parsed_reqs:
304+
base_req = parsed_reqs[base_req_name]
305+
stubs[base_req] = req
306+
307+
return stubs
308+
309+
def load_stubs(requirements = [], overrides = {}):
310+
"""
311+
Generate a mapping of labels to their stubs label. For example:
312+
313+
```
314+
{
315+
requirement("cachetools"): requirement("types-cachetools"),
316+
}
317+
```
318+
319+
This can be detected automatically via `requirements`, manually via `overrides`,
320+
or a combination of both.
321+
322+
Args:
323+
requirements: (optional) the full list of requirements from "@pip//:requirements.bzl"
324+
to automatically detect stubs from.
325+
overrides: (optional) explicitly specified stubs mapping
326+
"""
327+
stubs = _load_stubs_from_requirements(requirements)
328+
return struct(
329+
mapping = stubs | overrides,
330+
)
331+
296332
def mypy_cli(name, deps = None, mypy_requirement = None, python_version = "3.12", tags = None):
297333
"""
298334
Produce a custom mypy executable for use with the mypy build rule.

mypy/private/types.bzl

Lines changed: 0 additions & 57 deletions
This file was deleted.

mypy/types.bzl

Lines changed: 0 additions & 29 deletions
This file was deleted.

0 commit comments

Comments
 (0)