Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 11 additions & 36 deletions python/private/pypi/generate_whl_library_build_bazel.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,13 @@ _RENDER = {
"copy_files": render.dict,
"data": render.list,
"data_exclude": render.list,
"dependencies": render.list,
"dependencies_by_platform": lambda x: render.dict(x, value_repr = render.list),
"entry_points": render.dict_dict,
"extras": render.list,
"group_deps": render.list,
"include": str,
"requires_dist": render.list,
"srcs_exclude": render.list,
"tags": render.list,
"target_platforms": render.list,
}

# NOTE @aignas 2024-10-25: We have to keep this so that files in
Expand All @@ -55,15 +52,17 @@ package_metadata(
def generate_whl_library_build_bazel(
*,
annotation = None,
default_python_version = None,
config_load,
purl = None,
requires_dist = [],
**kwargs):
"""Generate a BUILD file for an unzipped Wheel

Args:
annotation: The annotation for the build file.
default_python_version: The python version to use to parse the METADATA.
config_load: {type}`str` The location from where to load the config.
purl: The purl.
requires_dist: {type}`list[str]` The list of dependencies from the METADATA file.
**kwargs: Extra args serialized to be passed to the
{obj}`whl_library_targets`.

Expand All @@ -75,36 +74,14 @@ def generate_whl_library_build_bazel(
"""load("@package_metadata//rules:package_metadata.bzl", "package_metadata")""",
]

if kwargs.get("tags"):
fn = "whl_library_targets"

# legacy path
unsupported_args = [
"requires",
"metadata_name",
"metadata_version",
"packages",
"include",
]
fn = "whl_library_targets_from_requires"
if not requires_dist:
# no deps, we can leave the extra loads out
pass
else:
fn = "whl_library_targets_from_requires"
unsupported_args = [
"dependencies",
"dependencies_by_platform",
"target_platforms",
"default_python_version",
]
packages_load = kwargs.pop("config_load")
if not kwargs.get("requires_dist"):
# no deps, we can leave the extra loads out
pass
else:
loads.append("""load("{}", "{}")""".format(packages_load, "packages"))
kwargs["include"] = "packages"

for arg in unsupported_args:
if kwargs.get(arg):
fail("BUG, unsupported arg: '{}'".format(arg))
loads.append("""load("{}", "{}")""".format(config_load, "packages"))
kwargs["include"] = "packages"
Comment thread
aignas marked this conversation as resolved.
kwargs["requires_dist"] = requires_dist

loads.extend([
"""load("@rules_python//python/private/pypi:whl_library_targets.bzl", "{}")""".format(fn),
Expand All @@ -119,8 +96,6 @@ def generate_whl_library_build_bazel(
kwargs["srcs_exclude"] = annotation.srcs_exclude_glob
if annotation.additive_build_content:
additional_content.append(annotation.additive_build_content)
if default_python_version:
kwargs["default_python_version"] = default_python_version

contents = "\n".join(
[
Expand Down
1 change: 1 addition & 0 deletions python/private/pypi/pkg_aliases.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ def multiplatform_whl_aliases(
ret[alias] = repo
continue

# This is if we are using `whl_config_setting` struct
config_settings = get_config_settings(
target_platforms = alias.target_platforms,
python_version = alias.version,
Expand Down
107 changes: 3 additions & 104 deletions python/private/pypi/whl_library_targets.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,8 @@ def whl_library_targets(
tags = [],
dependencies = [],
filegroups = None,
dependencies_by_platform = {},
dependencies_with_markers = {},
entry_points = {},
group_deps = [],
group_name = "",
data = [],
copy_files = {},
Expand Down Expand Up @@ -151,8 +149,6 @@ def whl_library_targets(
the filename of the sdist.
tags: {type}`list[str]` The tags set on the `py_library`.
dependencies: {type}`list[str]` A list of dependencies.
dependencies_by_platform: {type}`dict[str, list[str]]` A list of
dependencies by platform key.
dependencies_with_markers: {type}`dict[str, str]` A marker to evaluate
in order for the dep to be included.
entry_points: {type}`list[dict]` A list of parsed entry point definitions.
Expand All @@ -162,10 +158,6 @@ def whl_library_targets(
contains this library. If set, this library will behave as a shim
to group implementation rules which will provide simultaneously
installed dependencies which would otherwise form a cycle.
group_deps: {type}`list[str]` names of fellow members of the group (if
any). These will be excluded from generated deps lists so as to avoid
direct cycles. These dependencies will be provided at runtime by the
group rules which wrap this library and its fellows together.
copy_executables: {type}`dict[str, str]` The mapping between src and
dest locations for the targets.
copy_files: {type}`dict[str, str]` The mapping between src and
Expand All @@ -183,10 +175,6 @@ def whl_library_targets(
rules: {type}`struct` A struct with references to rules for creating targets.
"""
dependencies = sorted([normalize_name(d) for d in dependencies])
dependencies_by_platform = {
platform: sorted([normalize_name(d) for d in deps])
for platform, deps in dependencies_by_platform.items()
}
tags = sorted(tags)
data = [] + data

Expand Down Expand Up @@ -267,9 +255,7 @@ def whl_library_targets(
data.append(dest)

_config_settings(
dependencies_by_platform = dependencies_by_platform.keys(),
dependencies_with_markers = dependencies_with_markers,
native = native,
rules = rules,
visibility = ["//visibility:private"],
)
Expand All @@ -278,25 +264,6 @@ def whl_library_targets(
for d in dependencies_with_markers
}

# Ensure this list is normalized
# Note: mapping used as set
group_deps = {
normalize_name(d): True
for d in group_deps
}

dependencies = [
d
for d in dependencies
if d not in group_deps
]
dependencies_by_platform = {
p: deps
for p, deps in dependencies_by_platform.items()
for deps in [[d for d in deps if d not in group_deps]]
if deps
}

# If this library is a member of a group, its public label aliases need to
# point to the group implementation rule not the implementation rules. We
# also need to mark the implementation rules as visible to the group
Expand Down Expand Up @@ -351,7 +318,6 @@ def whl_library_targets(
srcs = [name],
data = _deps(
deps = dependencies,
deps_by_platform = dependencies_by_platform,
deps_conditional = deps_conditional,
tmpl = dep_template.format(name = "{}", target = WHEEL_FILE_PUBLIC_LABEL),
),
Expand Down Expand Up @@ -418,7 +384,6 @@ def whl_library_targets(
imports = ["site-packages"],
deps = _deps(
deps = dependencies,
deps_by_platform = dependencies_by_platform,
deps_conditional = deps_conditional,
tmpl = dep_template.format(name = "{}", target = PY_LIBRARY_PUBLIC_LABEL),
),
Expand All @@ -428,22 +393,13 @@ def whl_library_targets(
namespace_package_files = namespace_package_files,
)

def _config_settings(dependencies_by_platform, dependencies_with_markers, rules, native = native, **kwargs):
def _config_settings(dependencies_with_markers, rules, **kwargs):
"""Generate config settings for the targets.

Args:
dependencies_by_platform: {type}`list[str]` platform keys, can be
one of the following formats:
* `//conditions:default`
* `@platforms//os:{value}`
* `@platforms//cpu:{value}`
* `@//python/config_settings:is_python_3.{minor_version}`
* `{os}_{cpu}`
* `cp3{minor_version}_{os}_{cpu}`
dependencies_with_markers: {type}`dict[str, str]` The markers to evaluate by
each dep.
rules: used for testing
native: {type}`native` The native struct for overriding in tests.
**kwargs: Extra kwargs to pass to the rule.
"""
for dep, expression in dependencies_with_markers.items():
Expand All @@ -453,46 +409,7 @@ def _config_settings(dependencies_by_platform, dependencies_with_markers, rules,
**kwargs
)

for p in dependencies_by_platform:
if p.startswith("@") or p.endswith("default"):
continue

# TODO @aignas 2025-04-20: add tests here
abi, _, tail = p.partition("_")
if not abi.startswith("cp"):
tail = p
abi = ""
os, _, arch = tail.partition("_")

_kwargs = dict(kwargs)
_kwargs["constraint_values"] = [
"@platforms//cpu:{}".format(arch),
"@platforms//os:{}".format(os),
]

if abi:
_kwargs["flag_values"] = {
Label("//python/config_settings:python_version"): "3.{}".format(abi[len("cp3"):]),
}

native.config_setting(
name = "is_{name}".format(
name = p.replace("cp3", "python_3."),
),
**_kwargs
)

def _plat_label(plat):
if plat.endswith("default"):
return plat
elif plat.startswith("@//"):
return Label(plat.strip("@"))
elif plat.startswith("@"):
return plat
else:
return ":is_" + plat.replace("cp3", "python_3.")

def _deps(deps, deps_by_platform, deps_conditional, tmpl):
def _deps(deps, deps_conditional, tmpl):
deps = [tmpl.format(d) for d in sorted(deps)]

for dep, setting in deps_conditional.items():
Expand All @@ -501,22 +418,4 @@ def _deps(deps, deps_by_platform, deps_conditional, tmpl):
"//conditions:default": [],
})

if not deps_by_platform:
return deps

deps_by_platform = {
_plat_label(p): [
tmpl.format(d)
for d in sorted(deps)
]
for p, deps in sorted(deps_by_platform.items())
}

# Add the default, which means that we will be just using the dependencies in
# `deps` for platforms that are not handled in a special way by the packages
deps_by_platform.setdefault("//conditions:default", [])

if not deps:
return select(deps_by_platform)
else:
return deps + select(deps_by_platform)
return deps
Original file line number Diff line number Diff line change
Expand Up @@ -19,71 +19,6 @@ load("//python/private/pypi:generate_whl_library_build_bazel.bzl", "generate_whl

_tests = []

def _test_all_legacy(env):
want = """\
load("@package_metadata//rules:package_metadata.bzl", "package_metadata")
load("@rules_python//python/private/pypi:whl_library_targets.bzl", "whl_library_targets")

package(default_visibility = ["//visibility:public"])

package_metadata(
name = "package_metadata",
purl = None,
visibility = ["//:__subpackages__"],
)

whl_library_targets(
copy_executables = {
"exec_src": "exec_dest",
},
copy_files = {
"file_src": "file_dest",
},
data = ["extra_target"],
data_exclude = [
"exclude_via_attr",
"data_exclude_all",
],
dep_template = "@pypi_{name}//:{target}",
dependencies = ["foo"],
dependencies_by_platform = {
"baz": ["bar"],
},
group_deps = [
"foo",
"fox",
"qux",
],
group_name = "qux",
name = "foo.whl",
srcs_exclude = ["srcs_exclude_all"],
tags = ["tag1"],
)

# SOMETHING SPECIAL AT THE END
"""
actual = generate_whl_library_build_bazel(
dep_template = "@pypi_{name}//:{target}",
name = "foo.whl",
dependencies = ["foo"],
dependencies_by_platform = {"baz": ["bar"]},
data_exclude = ["exclude_via_attr"],
annotation = struct(
copy_files = {"file_src": "file_dest"},
copy_executables = {"exec_src": "exec_dest"},
data = ["extra_target"],
data_exclude_glob = ["data_exclude_all"],
srcs_exclude_glob = ["srcs_exclude_all"],
additive_build_content = """# SOMETHING SPECIAL AT THE END""",
),
group_name = "qux",
group_deps = ["foo", "fox", "qux"],
tags = ["tag1"],
)
env.expect.that_str(actual.replace("@@", "@")).equals(want)

_tests.append(_test_all_legacy)

def _test_all_workspace(env):
want = """\
load("@package_metadata//rules:package_metadata.bzl", "package_metadata")
Expand Down
Loading