diff --git a/py/BUILD.bazel b/py/BUILD.bazel index ed766bdcb..c19eb716e 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -29,6 +29,7 @@ bzl_library( deps = [ "//py/private:py_image_layer", "//py/private:py_info", + "//py/private:py_info_interop", "//py/private:py_library", "//py/private:py_pex_binary", "//py/private:py_pytest_main", diff --git a/py/defs.bzl b/py/defs.bzl index f2a32b37c..4a657c6bd 100644 --- a/py/defs.bzl +++ b/py/defs.bzl @@ -20,6 +20,12 @@ load( _py_layer_tier = "py_layer_tier", ) load("//py/private:py_info.bzl", _PyInfo = "PyInfo") +load( + "//py/private:py_info_interop.bzl", + _RulesPythonPyInfo = "RulesPythonPyInfo", + _get_py_info = "get_py_info", + _has_py_info = "has_py_info", +) load("//py/private:py_library.bzl", _py_library = "py_library") load("//py/private:py_pex_binary.bzl", _py_pex_binary = "py_pex_binary") load("//py/private:py_pytest_main.bzl", _py_pytest_main = "py_pytest_main", _pytest_paths = "pytest_paths") @@ -51,6 +57,9 @@ PyLayerTierInfo = _PyLayerTierInfo # The PyInfo provider used by rules_py PyInfo = _PyInfo +RulesPythonPyInfo = _RulesPythonPyInfo +get_py_info = _get_py_info +has_py_info = _has_py_info resolutions = _resolutions diff --git a/py/private/BUILD.bazel b/py/private/BUILD.bazel index aa1397318..a5726f208 100644 --- a/py/private/BUILD.bazel +++ b/py/private/BUILD.bazel @@ -48,6 +48,7 @@ bzl_library( srcs = ["py_image_layer.bzl"], deps = [ ":py_info", + ":py_info_interop", "@bazel_lib//lib:transitions", "@tar.bzl//tar:mtree", "@tar.bzl//tar:tar", @@ -58,7 +59,7 @@ bzl_library( name = "pth", srcs = ["pth.bzl"], deps = [ - ":py_info", + ":py_info_interop", "@bazel_skylib//lib:paths", ], ) @@ -70,6 +71,7 @@ bzl_library( ":providers", ":pth", ":py_info", + ":py_info_interop", ":py_semantics", ":py_wheel", ":transitions", @@ -124,13 +126,22 @@ bzl_library( ], ) +# keep bzl_library( name = "py_info", srcs = ["py_info.bzl"], # PyInfo is re-exported as public API from //py:defs.bzl, so its bzl_library # is public too, allowing sibling trees (e.g. //uv) to depend on it. visibility = ["//visibility:public"], - deps = ["@rules_python//python:defs_bzl"], +) + +bzl_library( + name = "py_info_interop", + srcs = ["py_info_interop.bzl"], + deps = [ + ":py_info", + "@rules_python//python:defs_bzl", + ], ) bzl_library( diff --git a/py/private/providers.bzl b/py/private/providers.bzl index c0ef29136..836a52197 100644 --- a/py/private/providers.bzl +++ b/py/private/providers.bzl @@ -144,11 +144,3 @@ def make_wheel_record( metadata_top_levels = tuple(metadata_top_levels), cs_claims = tuple(cs_claims), ) - -PyVirtualInfo = provider( - doc = "FIXME", - fields = { - "dependencies": "Depset of required virtual dependencies, independent of their resolution status", - "resolutions": "FIXME", - }, -) diff --git a/py/private/pth.bzl b/py/private/pth.bzl index 62f4f8d09..e2216bc04 100644 --- a/py/private/pth.bzl +++ b/py/private/pth.bzl @@ -1,7 +1,7 @@ """Helper functions for building imports depsets.""" load("@bazel_skylib//lib:paths.bzl", "paths") -load("//py/private:py_info.bzl", "PyInfo") +load("//py/private:py_info_interop.bzl", "get_py_info", "has_py_info") def _make_import_path(label, workspace, imp): if imp.startswith("/"): @@ -72,11 +72,15 @@ def make_imports_depset(deps, imports, workspace_name, label = None, extra_impor if label and label.workspace_name: import_paths.append(label.workspace_name) + # `deps` may carry rules_py's PyInfo or native @rules_python's; both expose + # `imports`. See py_info_interop.bzl. + transitive = [ + get_py_info(target).imports + for target in deps + if has_py_info(target) + ] + return depset( direct = import_paths, - transitive = [ - target[PyInfo].imports - for target in deps - if PyInfo in target - ] + extra_imports_depsets, + transitive = transitive + extra_imports_depsets, ) diff --git a/py/private/py_image_layer.bzl b/py/private/py_image_layer.bzl index 59c8e58bb..0ed063c34 100644 --- a/py/private/py_image_layer.bzl +++ b/py/private/py_image_layer.bzl @@ -34,6 +34,7 @@ Sharing model: load("//py/private:providers.bzl", "PyWheelsInfo") load("//py/private:py_info.bzl", "PyInfo") +load("//py/private:py_info_interop.bzl", "has_py_info") load("//py/private/toolchain:types.bzl", "PY_TOOLCHAIN") _TAR_TOOLCHAIN = "@tar.bzl//tar/toolchain:type" @@ -373,6 +374,10 @@ def _layer_aspect_impl(target, ctx): interpreter_layer = None interpreter_files = None kind = ctx.rule.kind + + # The binary being layered must be a rules_py py_binary (it carries rules_py's + # PyInfo); rules_python's py_binary is not supported. rules_python *library* + # deps within the graph are still handled by the membership checks below. is_binary = ( PyInfo in target and target[DefaultInfo].files_to_run.executable != None @@ -394,14 +399,14 @@ def _layer_aspect_impl(target, ctx): # Skip PyInfo deps (including wheel-leaf targets, which also emit PyInfo) — # they self-capture via the aspect. - if kind not in _PY_VENV_KINDS and PyInfo in target and not is_binary: + if kind not in _PY_VENV_KINDS and has_py_info(target) and not is_binary: own_parts = [target[DefaultInfo].files] for attr_name in ("data", "deps"): attr_val = getattr(ctx.rule.attr, attr_name, None) if not attr_val: continue for dep in attr_val: - if PyInfo in dep: + if has_py_info(dep): continue if DefaultInfo in dep: own_parts.append(dep[DefaultInfo].files) diff --git a/py/private/py_info.bzl b/py/private/py_info.bzl index 4721f7007..57e174397 100644 --- a/py/private/py_info.bzl +++ b/py/private/py_info.bzl @@ -1,11 +1,22 @@ -"""The `PyInfo` provider used by rules_py. +"""The `PyInfo` provider produced and consumed by rules_py targets. -This is the single seam through which rules_py imports `PyInfo`. Today it simply -re-exports `@rules_python//python:defs.bzl%PyInfo`; centralising the import here -means a future change to rules_py's own provider only touches this file, not -every load site. Re-exported from `//py:defs.bzl` as public API. +`PyInfo` carries the information rules_py needs to assemble a target's dependency +closure: the transitive set of first-party Python sources, the import roots to +place on `sys.path`, and the virtual-dependency declarations and their +resolutions. Targets in a dependency graph aggregate these fields from their +deps to build the eventual venv or wheel. """ -load("@rules_python//python:defs.bzl", _PyInfo = "PyInfo") +# First binding wins the exported name, so diagnostics say `RulesPyInfo`. +RulesPyInfo = provider( + doc = "Python source, import-path, and virtual-dependency information for a target's dependency closure.", + fields = { + "transitive_sources": "depset[File] — postorder depset of first-party `.py` sources in the transitive closure.", + "imports": "depset[str] — import roots to place on `sys.path` (rlocation-root-relative).", + "virtual_dependencies": "depset[str] — names of required virtual dependencies, independent of their resolution status.", + "virtual_resolutions": "depset[struct(virtual, target)] — virtual-dependency-name to concrete-target resolutions.", + }, +) -PyInfo = _PyInfo +# The name load sites and the public API import; same provider object. +PyInfo = RulesPyInfo diff --git a/py/private/py_info_interop.bzl b/py/private/py_info_interop.bzl new file mode 100644 index 000000000..67752ca90 --- /dev/null +++ b/py/private/py_info_interop.bzl @@ -0,0 +1,32 @@ +"""Interop between rules_py's `PyInfo` and `@rules_python`'s. + +The `deps` attribute shared by py_library/py_binary/py_test (and rules reusing +their attrs) accepts targets built by either ruleset. rules_py always emits its +own `PyInfo` (`//py/private:py_info.bzl`); native `@rules_python` targets (e.g. +a `py_proto_library`) carry `@rules_python`'s. Both expose `transitive_sources` +and `imports`, which is everything rules_py reads from a foreign dep. + +This module is the single place that knows about both providers. Rule code +calls these accessors at the API edge instead of loading `@rules_python`'s +provider directly, so a field read added for one provider cannot silently miss +the other. rules_py never *emits* `@rules_python`'s provider — the reverse +direction (a `@rules_python` rule consuming a rules_py target) is not supported. +""" + +load("@rules_python//python:defs.bzl", _RulesPythonPyInfo = "PyInfo") +load("//py/private:py_info.bzl", "PyInfo") + +# Re-exported for `providers` constraints on `deps`-style attributes. +RulesPythonPyInfo = _RulesPythonPyInfo + +def has_py_info(target): + """Whether the target carries rules_py's or `@rules_python`'s `PyInfo`.""" + return PyInfo in target or RulesPythonPyInfo in target + +def get_py_info(target): + """Return the target's `PyInfo` — rules_py's if present, else `@rules_python`'s, else `None`.""" + if PyInfo in target: + return target[PyInfo] + if RulesPythonPyInfo in target: + return target[RulesPythonPyInfo] + return None diff --git a/py/private/py_library.bzl b/py/private/py_library.bzl index 1a5c2e956..be549cab5 100644 --- a/py/private/py_library.bzl +++ b/py/private/py_library.bzl @@ -6,9 +6,10 @@ without binding them to a particular version of that package. load("@bazel_skylib//lib:new_sets.bzl", "sets") load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") -load("//py/private:providers.bzl", "PyVirtualInfo", "PyWheelsInfo") +load("//py/private:providers.bzl", "PyWheelsInfo") load("//py/private:pth.bzl", "make_imports_depset") load("//py/private:py_info.bzl", "PyInfo") +load("//py/private:py_info_interop.bzl", "RulesPythonPyInfo", "get_py_info", "has_py_info") load("//py/private:transitions.bzl", "reset_python_flags_transition") def _make_instrumented_files_info(ctx): @@ -20,13 +21,15 @@ def _make_instrumented_files_info(ctx): ) def _make_srcs_depset(ctx): + # `deps` may carry rules_py's PyInfo or native @rules_python's; both expose + # `transitive_sources`. See py_info_interop.bzl. return depset( order = "postorder", direct = ctx.files.srcs, transitive = [ - target[PyInfo].transitive_sources + get_py_info(target).transitive_sources for target in ctx.attr.deps - if PyInfo in target + if has_py_info(target) ], ) @@ -35,16 +38,17 @@ def _make_virtual_depset(ctx): order = "postorder", direct = getattr(ctx.attr, "virtual_deps", []), transitive = [ - target[PyVirtualInfo].dependencies + target[PyInfo].virtual_dependencies for target in ctx.attr.deps - if PyVirtualInfo in target + if PyInfo in target ], ) def _make_resolved_virtual_depset(target): transitive = [target[DefaultInfo].files] - if PyInfo in target: - transitive.append(target[PyInfo].transitive_sources) + info = get_py_info(target) + if info: + transitive.append(info.transitive_sources) return depset( order = "postorder", @@ -59,9 +63,9 @@ def _make_virtual_resolutions_depset(ctx): for k, v in ctx.attr.resolutions.items() ], transitive = [ - target[PyVirtualInfo].resolutions + target[PyInfo].virtual_resolutions for target in ctx.attr.deps - if PyVirtualInfo in target + if PyInfo in target ], ) @@ -85,8 +89,9 @@ def _resolve_virtuals(ctx): v_srcs.append(_make_resolved_virtual_depset(resolution.target)) v_runfiles.append(resolution.target[DefaultInfo].default_runfiles.files) - if PyInfo in resolution.target: - v_imports.append(resolution.target[PyInfo].imports) + info = get_py_info(resolution.target) + if info: + v_imports.append(info.imports) missing = sets.to_list(sets.difference(sets.make(virtual), sets.make(seen.keys()))) if len(missing) > 0: @@ -162,13 +167,8 @@ def _py_library_impl(ctx): PyInfo( imports = imports, transitive_sources = transitive_srcs, - has_py2_only_sources = False, - has_py3_only_sources = True, - uses_shared_libraries = False, - ), - PyVirtualInfo( - dependencies = virtuals, - resolutions = resolutions, + virtual_dependencies = virtuals, + virtual_resolutions = resolutions, ), PyWheelsInfo( wheels = wheels, @@ -183,7 +183,12 @@ _attrs = dict({ ), "deps": attr.label_list( doc = "Targets that produce Python code, commonly `py_library` rules.", - providers = [[PyInfo], [PyVirtualInfo], [CcInfo]], + # This attribute — shared by py_library, py_binary and py_test — is the + # public surface that supports rules_python interop: a dep may carry + # rules_py's PyInfo, or native @rules_python's PyInfo (e.g. a + # py_proto_library). Reads go through py_info_interop.bzl's accessors; + # rules_py never emits RulesPythonPyInfo. + providers = [[PyInfo], [RulesPythonPyInfo], [CcInfo]], ), "data": attr.label_list( doc = """Runtime dependencies of the program. diff --git a/py/private/py_unpacked_wheel.bzl b/py/private/py_unpacked_wheel.bzl index 28a142804..71a31a45d 100644 --- a/py/private/py_unpacked_wheel.bzl +++ b/py/private/py_unpacked_wheel.bzl @@ -73,9 +73,8 @@ def _py_unpacked_wheel_impl(ctx): PyInfo( imports = imports, transitive_sources = depset([unpack_directory]), - has_py2_only_sources = False, - has_py3_only_sources = True, - uses_shared_libraries = False, + virtual_dependencies = depset(), + virtual_resolutions = depset(), ), ] diff --git a/py/private/py_venv/py_venv_exec.bzl b/py/private/py_venv/py_venv_exec.bzl index be403cbe5..5043f31e7 100644 --- a/py/private/py_venv/py_venv_exec.bzl +++ b/py/private/py_venv/py_venv_exec.bzl @@ -136,9 +136,8 @@ def _py_venv_exec_impl(ctx): # sibling venv, not on this rule. imports = vinfo.imports, transitive_sources = vinfo.transitive_sources, - has_py2_only_sources = False, - has_py3_only_sources = True, - uses_shared_libraries = False, + virtual_dependencies = depset(), + virtual_resolutions = depset(), ), instrumented_files_info, RunEnvironmentInfo( diff --git a/py/tests/import-pathing/BUILD.bazel b/py/tests/import-pathing/BUILD.bazel index 9a7187e7a..6602e4438 100644 --- a/py/tests/import-pathing/BUILD.bazel +++ b/py/tests/import-pathing/BUILD.bazel @@ -1,11 +1,22 @@ -load("@rules_python//python:defs.bzl", "py_library") +load("@rules_python//python:defs.bzl", rules_python_py_library = "py_library") +load("//py:defs.bzl", "py_library") load(":tests.bzl", "py_library_import_pathing_test_suite") -# This is used in the py_library import pathing tests +# Used by the import-pathing tests to verify a dep's `imports` merge +# transitively through rules_py's own PyInfo. py_library( - name = "__native_rule_import_list_for_test", + name = "__import_list_for_test", imports = ["baz"], tags = ["manual"], ) +# Same, but a native @rules_python py_library: covers the interop edge where +# make_imports_depset reads `imports` from @rules_python's PyInfo +# (see //py/private:py_info_interop.bzl). +rules_python_py_library( + name = "__rules_python_import_list_for_test", + imports = ["rp_baz"], + tags = ["manual"], +) + py_library_import_pathing_test_suite() diff --git a/py/tests/import-pathing/tests.bzl b/py/tests/import-pathing/tests.bzl index ce418423d..9c37e7e21 100644 --- a/py/tests/import-pathing/tests.bzl +++ b/py/tests/import-pathing/tests.bzl @@ -71,6 +71,18 @@ def _can_resolve_path_in_workspace_test_impl(ctx): # Note that under bzlmod the import_dep's repo is _main. # We can't override or force this because we're using a real label below. asserts.equals(env, "{}/py/tests/import-pathing/baz".format(ctx.workspace_name), imports[0]) + + # The dep is a rules_py py_library, which appends the workspace root to its + # own imports, so that entry is carried transitively too. + asserts.equals(env, ctx.workspace_name, imports[1]) + asserts.equals(env, "aspect_rules_py/foo", imports[2]) + + # Transitive imports from a native @rules_python dep are merged too, read + # from @rules_python's PyInfo at the API edge (py_info_interop.bzl). Unlike + # rules_py, @rules_python does not append the workspace root to imports. + fake_ctx = _ctx_with_imports([".."], [ctx.attr.rules_python_import_dep]) + imports = py_library.make_imports_depset(fake_ctx).to_list() + asserts.equals(env, "{}/py/tests/import-pathing/rp_baz".format(ctx.workspace_name), imports[0]) asserts.equals(env, "aspect_rules_py/foo", imports[1]) return unittest.end(env) @@ -79,7 +91,10 @@ _can_resolve_path_in_workspace_test = unittest.make( _can_resolve_path_in_workspace_test_impl, attrs = { "import_dep": attr.label( - default = "@//py/tests/import-pathing:__native_rule_import_list_for_test", + default = "@//py/tests/import-pathing:__import_list_for_test", + ), + "rules_python_import_dep": attr.label( + default = "@//py/tests/import-pathing:__rules_python_import_list_for_test", ), }, ) diff --git a/py/tests/internal-deps/BUILD.bazel b/py/tests/internal-deps/BUILD.bazel index 4ed9cb2df..bd06793d8 100644 --- a/py/tests/internal-deps/BUILD.bazel +++ b/py/tests/internal-deps/BUILD.bazel @@ -18,14 +18,15 @@ rules_py_py_library( ], ) +# Forward interop: a @rules_python py_library consumed by the rules_py +# py_binary/py_test below. It can't depend on a rules_py py_library (`:init`) — +# rules_py emits its own PyInfo, not @rules_python's, which rules_python's deps +# constraint requires. py_library( name = "pi", srcs = [ "pi.py", ], - deps = [ - ":init", - ], ) py_binary( diff --git a/py/tests/public-py-info/BUILD.bazel b/py/tests/public-py-info/BUILD.bazel new file mode 100644 index 000000000..fe79b324d --- /dev/null +++ b/py/tests/public-py-info/BUILD.bazel @@ -0,0 +1,67 @@ +load("@rules_python//python:defs.bzl", rules_python_py_library = "py_library") +load("//py:defs.bzl", "py_library", "py_test") +load(":interop.bzl", "dual_py_info", "public_py_info_consumer") + +genrule( + name = "generated_source", + outs = ["native_root/generated_lib.py"], + cmd = "printf 'VALUE = 42\\n' > $@", +) + +genrule( + name = "generated_stub", + outs = ["native_root/generated_lib.pyi"], + cmd = "printf 'VALUE: int\\n' > $@", +) + +rules_python_py_library( + name = "native_library", + srcs = [":generated_source"], + imports = ["native_root"], + pyi_srcs = [":generated_stub"], +) + +py_library( + name = "rules_library", + srcs = ["rules_root/rules_lib.py"], + imports = ["rules_root"], +) + +dual_py_info( + name = "dual_library", + native = ":native_library", + rules = ":rules_library", +) + +public_py_info_consumer( + name = "native_consumer", + dep = ":native_library", + expected_import = "native_root", + expected_source = "generated_lib.py", + expected_stub = "generated_lib.pyi", +) + +public_py_info_consumer( + name = "rules_consumer", + dep = ":rules_library", + expected_import = "rules_root", + expected_source = "rules_lib.py", +) + +public_py_info_consumer( + name = "dual_consumer", + dep = ":dual_library", + expected_import = "rules_root", + expected_source = "rules_lib.py", + expected_stub = "generated_lib.pyi", +) + +py_test( + name = "test", + srcs = ["test.py"], + deps = [ + ":dual_consumer", + ":native_consumer", + ":rules_consumer", + ], +) diff --git a/py/tests/public-py-info/interop.bzl b/py/tests/public-py-info/interop.bzl new file mode 100644 index 000000000..3411bfc30 --- /dev/null +++ b/py/tests/public-py-info/interop.bzl @@ -0,0 +1,59 @@ +"""Consumes either public Python provider and forwards it to rules_py.""" + +load("//py:defs.bzl", "PyInfo", "RulesPythonPyInfo", "get_py_info", "has_py_info") + +def _dual_py_info_impl(ctx): + native = ctx.attr.native + rules = ctx.attr.rules + return [ + DefaultInfo( + files = depset(transitive = [native[DefaultInfo].files, rules[DefaultInfo].files]), + runfiles = native[DefaultInfo].default_runfiles.merge(rules[DefaultInfo].default_runfiles), + ), + native[RulesPythonPyInfo], + rules[PyInfo], + ] + +dual_py_info = rule( + implementation = _dual_py_info_impl, + attrs = { + "native": attr.label(mandatory = True, providers = [[RulesPythonPyInfo]]), + "rules": attr.label(mandatory = True, providers = [[PyInfo]]), + }, +) + +def _public_py_info_consumer_impl(ctx): + dep = ctx.attr.dep + if not has_py_info(dep): + fail("{} does not provide Python sources".format(dep.label)) + info = get_py_info(dep) + if ctx.attr.expected_source not in [source.basename for source in info.transitive_sources.to_list()]: + fail("{} dropped {} from the selected Python provider".format(dep.label, ctx.attr.expected_source)) + if not any([path.endswith("/" + ctx.attr.expected_import) for path in info.imports.to_list()]): + fail("{} dropped the {} import root".format(dep.label, ctx.attr.expected_import)) + if RulesPythonPyInfo in dep: + stubs = dep[RulesPythonPyInfo].transitive_pyi_files.to_list() + if ctx.attr.expected_stub not in [stub.basename for stub in stubs]: + fail("{} dropped native stub {}".format(dep.label, ctx.attr.expected_stub)) + return [ + DefaultInfo( + files = dep[DefaultInfo].files, + runfiles = dep[DefaultInfo].default_runfiles, + ), + PyInfo( + imports = info.imports, + transitive_sources = info.transitive_sources, + virtual_dependencies = depset(), + virtual_resolutions = depset(), + ), + ] + +public_py_info_consumer = rule( + implementation = _public_py_info_consumer_impl, + attrs = { + "dep": attr.label(mandatory = True, providers = [[PyInfo], [RulesPythonPyInfo]]), + "expected_import": attr.string(mandatory = True), + "expected_source": attr.string(mandatory = True), + "expected_stub": attr.string(), + }, +) diff --git a/py/tests/public-py-info/rules_root/rules_lib.py b/py/tests/public-py-info/rules_root/rules_lib.py new file mode 100644 index 000000000..6da00a69d --- /dev/null +++ b/py/tests/public-py-info/rules_root/rules_lib.py @@ -0,0 +1 @@ +RULES = 43 diff --git a/py/tests/public-py-info/test.py b/py/tests/public-py-info/test.py new file mode 100644 index 000000000..5208b325e --- /dev/null +++ b/py/tests/public-py-info/test.py @@ -0,0 +1,5 @@ +from generated_lib import VALUE +from rules_lib import RULES + +assert VALUE == 42 +assert RULES == 43 diff --git a/py/tests/py_venv_conflict/collision_order_test.bzl b/py/tests/py_venv_conflict/collision_order_test.bzl index 8498cca5c..320c00031 100644 --- a/py/tests/py_venv_conflict/collision_order_test.bzl +++ b/py/tests/py_venv_conflict/collision_order_test.bzl @@ -67,9 +67,8 @@ printf 'VALUE = "namespace"\n' > "$site/mixed_top/from_namespace.py" PyInfo( imports = depset([site_packages]), transitive_sources = depset([install_tree]), - has_py2_only_sources = False, - has_py3_only_sources = True, - uses_shared_libraries = False, + virtual_dependencies = depset(), + virtual_resolutions = depset(), ), PyWheelsInfo(wheels = depset([wheel])), ] @@ -194,9 +193,8 @@ printf 'native' > "$site/collision_order/native_extension.so" PyInfo( imports = depset([site_packages]), transitive_sources = depset([install_tree]), - has_py2_only_sources = False, - has_py3_only_sources = True, - uses_shared_libraries = False, + virtual_dependencies = depset(), + virtual_resolutions = depset(), ), PyWheelsInfo(wheels = depset([wheel])), ] diff --git a/py/tests/py_venv_conflict/site_merge_order_test.bzl b/py/tests/py_venv_conflict/site_merge_order_test.bzl index 0aa4d1d1f..071819fae 100644 --- a/py/tests/py_venv_conflict/site_merge_order_test.bzl +++ b/py/tests/py_venv_conflict/site_merge_order_test.bzl @@ -122,9 +122,8 @@ printf 'VALUE = %s\n' "$4" > "$site/other/from_final.py" PyInfo( imports = depset(site_packages_paths), transitive_sources = depset(install_trees), - has_py2_only_sources = False, - has_py3_only_sources = True, - uses_shared_libraries = False, + virtual_dependencies = depset(), + virtual_resolutions = depset(), ), PyWheelsInfo(wheels = depset(direct = wheels, order = "postorder")), ] @@ -232,9 +231,8 @@ printf 'VALUE = %s\n' "$4" > "$site/mixed/sibling.py" PyInfo( imports = depset(site_packages_paths), transitive_sources = depset(install_trees), - has_py2_only_sources = False, - has_py3_only_sources = True, - uses_shared_libraries = False, + virtual_dependencies = depset(), + virtual_resolutions = depset(), ), PyWheelsInfo(wheels = depset(direct = wheels, order = "postorder")), ] diff --git a/uv/private/whl_install/rule.bzl b/uv/private/whl_install/rule.bzl index 5fa3b9bba..278f0aae8 100644 --- a/uv/private/whl_install/rule.bzl +++ b/uv/private/whl_install/rule.bzl @@ -161,9 +161,8 @@ def _whl_install(ctx): install_dir, ]), imports = depset([site_packages_rfpath]), - has_py2_only_sources = False, - has_py3_only_sources = True, - uses_shared_libraries = False, + virtual_dependencies = depset(), + virtual_resolutions = depset(), ), ]