Skip to content

Commit 8a3b275

Browse files
committed
inc
1 parent 924ec59 commit 8a3b275

7 files changed

Lines changed: 85 additions & 34 deletions

File tree

py/private/BUILD.bazel

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ bzl_library(
4848
srcs = ["py_image_layer.bzl"],
4949
deps = [
5050
":py_info",
51+
":py_info_interop",
5152
"@bazel_lib//lib:transitions",
52-
"@rules_python//python:defs_bzl",
5353
"@tar.bzl//tar:mtree",
5454
"@tar.bzl//tar:tar",
5555
],
@@ -59,9 +59,8 @@ bzl_library(
5959
name = "pth",
6060
srcs = ["pth.bzl"],
6161
deps = [
62-
":py_info",
62+
":py_info_interop",
6363
"@bazel_skylib//lib:paths",
64-
"@rules_python//python:defs_bzl",
6564
],
6665
)
6766

@@ -72,11 +71,11 @@ bzl_library(
7271
":providers",
7372
":pth",
7473
":py_info",
74+
":py_info_interop",
7575
":py_semantics",
7676
":py_wheel",
7777
"@bazel_skylib//lib:new_sets",
7878
"@bazel_skylib//lib:types",
79-
"@rules_python//python:defs_bzl",
8079
],
8180
)
8281

@@ -135,6 +134,15 @@ bzl_library(
135134
visibility = ["//visibility:public"],
136135
)
137136

137+
bzl_library(
138+
name = "py_info_interop",
139+
srcs = ["py_info_interop.bzl"],
140+
deps = [
141+
":py_info",
142+
"@rules_python//python:defs_bzl",
143+
],
144+
)
145+
138146
bzl_library(
139147
name = "providers",
140148
srcs = ["providers.bzl"],

py/private/pth.bzl

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
"""Helper functions for building imports depsets."""
22

33
load("@bazel_skylib//lib:paths.bzl", "paths")
4-
5-
# API edge: deps may expose rules_py's PyInfo or native `@rules_python`'s.
6-
load("@rules_python//python:defs.bzl", RulesPythonPyInfo = "PyInfo")
7-
load("//py/private:py_info.bzl", "PyInfo")
4+
load("//py/private:py_info_interop.bzl", "get_py_info", "has_py_info")
85

96
def _make_import_path(label, workspace, imp):
107
if imp.startswith("/"):
@@ -75,13 +72,12 @@ def make_imports_depset(deps, imports, workspace_name, label = None, extra_impor
7572
if label and label.workspace_name:
7673
import_paths.append(label.workspace_name)
7774

78-
# `deps` come from py_library/py_binary/py_test, whose deps attribute accepts
79-
# both rules_py (PyInfo) and native @rules_python (RulesPythonPyInfo) targets;
80-
# both expose `imports`.
75+
# `deps` may carry rules_py's PyInfo or native @rules_python's; both expose
76+
# `imports`. See py_info_interop.bzl.
8177
transitive = [
82-
(target[PyInfo] if PyInfo in target else target[RulesPythonPyInfo]).imports
78+
get_py_info(target).imports
8379
for target in deps
84-
if PyInfo in target or RulesPythonPyInfo in target
80+
if has_py_info(target)
8581
]
8682

8783
return depset(

py/private/py_image_layer.bzl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ Sharing model:
3232
- Ungrouped pip packages: squashed by the rule into one per-rule tar.
3333
"""
3434

35-
load("@rules_python//python:defs.bzl", RulesPythonPyInfo = "PyInfo")
3635
load("//py/private:providers.bzl", "PyWheelsInfo")
3736
load("//py/private:py_info.bzl", "PyInfo")
37+
load("//py/private:py_info_interop.bzl", "has_py_info")
3838
load("//py/private/toolchain:types.bzl", "PY_TOOLCHAIN")
3939

4040
_TAR_TOOLCHAIN = "@tar.bzl//tar/toolchain:type"
@@ -399,14 +399,14 @@ def _layer_aspect_impl(target, ctx):
399399

400400
# Skip PyInfo deps (including wheel-leaf targets, which also emit PyInfo) —
401401
# they self-capture via the aspect.
402-
if kind not in _PY_VENV_KINDS and (PyInfo in target or RulesPythonPyInfo in target) and not is_binary:
402+
if kind not in _PY_VENV_KINDS and has_py_info(target) and not is_binary:
403403
own_parts = [target[DefaultInfo].files]
404404
for attr_name in ("data", "deps"):
405405
attr_val = getattr(ctx.rule.attr, attr_name, None)
406406
if not attr_val:
407407
continue
408408
for dep in attr_val:
409-
if PyInfo in dep or RulesPythonPyInfo in dep:
409+
if has_py_info(dep):
410410
continue
411411
if DefaultInfo in dep:
412412
own_parts.append(dep[DefaultInfo].files)

py/private/py_info_interop.bzl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""Interop between rules_py's `PyInfo` and `@rules_python`'s.
2+
3+
The `deps` attribute shared by py_library/py_binary/py_test (and rules reusing
4+
their attrs) accepts targets built by either ruleset. rules_py always emits its
5+
own `PyInfo` (`//py/private:py_info.bzl`); native `@rules_python` targets (e.g.
6+
a `py_proto_library`) carry `@rules_python`'s. Both expose `transitive_sources`
7+
and `imports`, which is everything rules_py reads from a foreign dep.
8+
9+
This module is the single place that knows about both providers. Rule code
10+
calls these accessors at the API edge instead of loading `@rules_python`'s
11+
provider directly, so a field read added for one provider cannot silently miss
12+
the other. rules_py never *emits* `@rules_python`'s provider — the reverse
13+
direction (a `@rules_python` rule consuming a rules_py target) is not supported.
14+
"""
15+
16+
load("@rules_python//python:defs.bzl", _RulesPythonPyInfo = "PyInfo")
17+
load("//py/private:py_info.bzl", "PyInfo")
18+
19+
# Re-exported for `providers` constraints on `deps`-style attributes.
20+
RulesPythonPyInfo = _RulesPythonPyInfo
21+
22+
def has_py_info(target):
23+
"""Whether the target carries rules_py's or `@rules_python`'s `PyInfo`."""
24+
return PyInfo in target or RulesPythonPyInfo in target
25+
26+
def get_py_info(target):
27+
"""Return the target's `PyInfo` — rules_py's if present, else `@rules_python`'s, else `None`."""
28+
if PyInfo in target:
29+
return target[PyInfo]
30+
if RulesPythonPyInfo in target:
31+
return target[RulesPythonPyInfo]
32+
return None

py/private/py_library.bzl

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,10 @@ without binding them to a particular version of that package.
66

77
load("@bazel_skylib//lib:new_sets.bzl", "sets")
88
load("@rules_cc//cc/common:cc_info.bzl", "CcInfo")
9-
10-
# rules_python's PyInfo, referenced in the `deps` provider constraint so native
11-
# `@rules_python` targets (e.g. py_proto_library) are accepted as deps. rules_py
12-
# emits its own PyInfo; it reads a dep's sources/imports from either provider via
13-
# the accessors below.
14-
load("@rules_python//python:defs.bzl", RulesPythonPyInfo = "PyInfo")
159
load("//py/private:providers.bzl", "PyWheelsInfo")
1610
load("//py/private:pth.bzl", "make_imports_depset")
1711
load("//py/private:py_info.bzl", "PyInfo")
12+
load("//py/private:py_info_interop.bzl", "RulesPythonPyInfo", "get_py_info", "has_py_info")
1813

1914
def _make_instrumented_files_info(ctx):
2015
return coverage_common.instrumented_files_info(
@@ -25,15 +20,15 @@ def _make_instrumented_files_info(ctx):
2520
)
2621

2722
def _make_srcs_depset(ctx):
28-
# `deps` accepts rules_py targets (PyInfo) and native @rules_python targets
29-
# (RulesPythonPyInfo); both expose `transitive_sources`.
23+
# `deps` may carry rules_py's PyInfo or native @rules_python's; both expose
24+
# `transitive_sources`. See py_info_interop.bzl.
3025
return depset(
3126
order = "postorder",
3227
direct = ctx.files.srcs,
3328
transitive = [
34-
(target[PyInfo] if PyInfo in target else target[RulesPythonPyInfo]).transitive_sources
29+
get_py_info(target).transitive_sources
3530
for target in ctx.attr.deps
36-
if PyInfo in target or RulesPythonPyInfo in target
31+
if has_py_info(target)
3732
],
3833
)
3934

@@ -50,8 +45,8 @@ def _make_virtual_depset(ctx):
5045

5146
def _make_resolved_virtual_depset(target):
5247
transitive = [target[DefaultInfo].files]
53-
if PyInfo in target or RulesPythonPyInfo in target:
54-
info = target[PyInfo] if PyInfo in target else target[RulesPythonPyInfo]
48+
info = get_py_info(target)
49+
if info:
5550
transitive.append(info.transitive_sources)
5651

5752
return depset(
@@ -93,8 +88,8 @@ def _resolve_virtuals(ctx):
9388
v_srcs.append(_make_resolved_virtual_depset(resolution.target))
9489
v_runfiles.append(resolution.target[DefaultInfo].default_runfiles.files)
9590

96-
if PyInfo in resolution.target or RulesPythonPyInfo in resolution.target:
97-
info = resolution.target[PyInfo] if PyInfo in resolution.target else resolution.target[RulesPythonPyInfo]
91+
info = get_py_info(resolution.target)
92+
if info:
9893
v_imports.append(info.imports)
9994

10095
missing = sets.to_list(sets.difference(sets.make(virtual), sets.make(seen.keys())))
@@ -190,8 +185,8 @@ _attrs = dict({
190185
# This attribute — shared by py_library, py_binary and py_test — is the
191186
# public surface that supports rules_python interop: a dep may carry
192187
# rules_py's PyInfo, or native @rules_python's PyInfo (e.g. a
193-
# py_proto_library). RulesPythonPyInfo appears here and at the reads in
194-
# this file for exactly that reason; rules_py never emits it.
188+
# py_proto_library). Reads go through py_info_interop.bzl's accessors;
189+
# rules_py never emits RulesPythonPyInfo.
195190
providers = [[PyInfo], [RulesPythonPyInfo], [CcInfo]],
196191
),
197192
"data": attr.label_list(
Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
1+
load("@rules_python//python:defs.bzl", rules_python_py_library = "py_library")
12
load("//py:defs.bzl", "py_library")
23
load(":tests.bzl", "py_library_import_pathing_test_suite")
34

45
# Used by the import-pathing tests to verify a dep's `imports` merge
5-
# transitively. A rules_py py_library: rules_py reads import roots only from its
6-
# own PyInfo, so transitive-imports coverage uses a rules_py dep.
6+
# transitively through rules_py's own PyInfo.
77
py_library(
88
name = "__import_list_for_test",
99
imports = ["baz"],
1010
tags = ["manual"],
1111
)
1212

13+
# Same, but a native @rules_python py_library: covers the interop edge where
14+
# make_imports_depset reads `imports` from @rules_python's PyInfo
15+
# (see //py/private:py_info_interop.bzl).
16+
rules_python_py_library(
17+
name = "__rules_python_import_list_for_test",
18+
imports = ["rp_baz"],
19+
tags = ["manual"],
20+
)
21+
1322
py_library_import_pathing_test_suite()

py/tests/import-pathing/tests.bzl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ def _can_resolve_path_in_workspace_test_impl(ctx):
7777
asserts.equals(env, ctx.workspace_name, imports[1])
7878
asserts.equals(env, "aspect_rules_py/foo", imports[2])
7979

80+
# Transitive imports from a native @rules_python dep are merged too, read
81+
# from @rules_python's PyInfo at the API edge (py_info_interop.bzl). Unlike
82+
# rules_py, @rules_python does not append the workspace root to imports.
83+
fake_ctx = _ctx_with_imports([".."], [ctx.attr.rules_python_import_dep])
84+
imports = py_library.make_imports_depset(fake_ctx).to_list()
85+
asserts.equals(env, "{}/py/tests/import-pathing/rp_baz".format(ctx.workspace_name), imports[0])
86+
asserts.equals(env, "aspect_rules_py/foo", imports[1])
87+
8088
return unittest.end(env)
8189

8290
_can_resolve_path_in_workspace_test = unittest.make(
@@ -85,6 +93,9 @@ _can_resolve_path_in_workspace_test = unittest.make(
8593
"import_dep": attr.label(
8694
default = "@//py/tests/import-pathing:__import_list_for_test",
8795
),
96+
"rules_python_import_dep": attr.label(
97+
default = "@//py/tests/import-pathing:__rules_python_import_list_for_test",
98+
),
8899
},
89100
)
90101

0 commit comments

Comments
 (0)