Skip to content

Commit 1c63944

Browse files
committed
sketch from mypy PR
aspect-build/rules_py#235
1 parent 86ffdea commit 1c63944

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

mypy.bzl

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ MyPyAspectInfo = provider(
1414

1515
# Switch to True only during debugging and development.
1616
# All releases should have this as False.
17-
DEBUG = False
17+
DEBUG = True
1818

1919
VALID_EXTENSIONS = ["py", "pyi"]
2020

@@ -72,16 +72,38 @@ def _extract_transitive_deps(deps):
7272
transitive_deps.append(dep[PyInfo].transitive_sources)
7373
return transitive_deps
7474

75+
def _extract_transitive_inputs(deps):
76+
input_depsets = []
77+
for dep in deps:
78+
# # Supply the --cache-map files from transitives
79+
# if MypyInfo in dep:
80+
# input_depsets.append(dep[MypyInfo].transitive_cache_map)
81+
82+
# TODO: relies on PyInfo being a Bazel global symbol.
83+
# When https://github.com/bazelbuild/rules_python/issues/1645 is fixed we can flip that flag to keep us honest.
84+
if PyInfo in dep:
85+
# TODO: maybe we can avoid passing .py source files when the cache-map files were found?
86+
input_depsets.append(dep[PyInfo].transitive_sources)
87+
88+
# rules_python puts .pyi files into the data attribute of a py_library
89+
# so the transitive_sources is not sufficient.
90+
# TODO: should we change rules_python to pass .pyi files in some provider?
91+
if dep.label.workspace_root.startswith("external/"):
92+
input_depsets.append(dep[DefaultInfo].default_runfiles.files)
93+
return input_depsets
94+
7595
def _extract_stub_deps(deps):
7696
# Need to add the .py files AND the .pyi files that are
7797
# deps of the rule
7898
stub_files = []
99+
print('deps', deps)
79100
for dep in deps:
80101
if MyPyStubsInfo in dep:
81102
for stub_srcs_target in dep[MyPyStubsInfo].srcs:
82103
for src_f in stub_srcs_target.files.to_list():
83104
if src_f.extension == "pyi":
84105
stub_files.append(src_f)
106+
print('stub_files', stub_files)
85107
return stub_files
86108

87109
def _extract_imports(imports, label):
@@ -113,9 +135,12 @@ def _mypy_rule_impl(ctx, is_aspect = False):
113135
if hasattr(base_rule.attr, "srcs"):
114136
direct_src_files = _extract_srcs(base_rule.attr.srcs)
115137

138+
transitive_imports = depset()
116139
if hasattr(base_rule.attr, "deps"):
117140
transitive_srcs_depsets = _extract_transitive_deps(base_rule.attr.deps)
118141
stub_files = _extract_stub_deps(base_rule.attr.deps)
142+
transitive_imports = depset(transitive = [dep[PyInfo].imports for dep in base_rule.attr.deps if PyInfo in dep])
143+
print('transitive_imports', transitive_imports)
119144

120145
if hasattr(base_rule.attr, "imports"):
121146
mypypath_parts = _extract_imports(base_rule.attr.imports, ctx.label)
@@ -128,6 +153,7 @@ def _mypy_rule_impl(ctx, is_aspect = False):
128153

129154
mypypath_parts += [src_f.dirname for src_f in stub_files]
130155
mypypath = ":".join(mypypath_parts)
156+
print('mypypath', mypypath)
131157

132158
# Ideally, a file should be passed into this rule. If this is an executable
133159
# rule, then we default to the implicit executable file, otherwise we create
@@ -149,18 +175,25 @@ def _mypy_rule_impl(ctx, is_aspect = False):
149175
# Compose a list of the files needed for use. Note that aspect rules can use
150176
# the project version of mypy however, other rules should fall back on their
151177
# relative runfiles.
152-
runfiles = ctx.runfiles(files = src_files + stub_files + [mypy_config_file])
178+
transitive_files = depset(transitive=_extract_transitive_inputs(base_rule.attr.deps))
179+
print('transitive_files', transitive_files)
180+
runfiles = ctx.runfiles(files = src_files + stub_files + [mypy_config_file], transitive_files = transitive_files)
181+
# runfiles = ctx.runfiles(files = src_files + stub_files + [mypy_config_file], transitive_files = transitive_files)
182+
# runfiles = runfiles.merge(transitive_imports)
153183
if not is_aspect:
154184
runfiles = runfiles.merge(ctx.attr._mypy_cli.default_runfiles)
155185

156186
src_root_paths = sets.to_list(
157187
sets.make([f.root.path for f in src_files]),
158188
)
159189

190+
print('src_root_paths', src_root_paths)
191+
160192
ctx.actions.expand_template(
161193
template = ctx.file._template,
162194
output = exe,
163195
substitutions = {
196+
"{PYTHONPATH}": ":".join(["external/" + t for t in transitive_imports.to_list()]),
164197
"{MYPY_EXE}": ctx.executable._mypy_cli.path,
165198
"{MYPY_ROOT}": ctx.executable._mypy_cli.root.path,
166199
"{CACHE_MAP_TRIPLES}": " ".join(_sources_to_cache_map_triples(src_files, is_aspect)),

templates/mypy.sh.tpl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ main() {
1717
mypy="{MYPY_EXE}"
1818

1919
# TODO(Jonathon): Consider UX improvements using https://mypy.readthedocs.io/en/stable/command_line.html#configuring-error-messages
20+
export PYTHONPATH="{PYTHONPATH}"
21+
echo $PYTHONPATH
2022

2123
export MYPYPATH="$(pwd):{MYPYPATH_PATH}"
2224

0 commit comments

Comments
 (0)