feat(pip_parse): support referencing dependencies to packages via hub (#1856)
With this change we can in theory have multi-platform libraries in the
dependency cycle and use the pip hub repo for the dependencies. With
this we can also make the contents of `whl_library` not depend on what
platform the actual dependencies are. This allows us to support the
following topologies:
* A platform-specific wheel depends on cross-platform wheel.
* A cross-platform wheel depends on cross-platform wheel.
* A whl_library can have `select` dependencies based on the interpreter
version, e.g. pull in a `tomli` dependency only when the Python
interpreter is less than 3.11.
Relates to #1663.
Work towards #735.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b481832..415b936 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -74,6 +74,13 @@
the downloading of metadata is done in parallel can be done using
`parallel_download` attribute.
* (deps): `rules_python` depends now on `rules_cc` 0.0.9
+* (pip_parse): A new flag `use_hub_alias_dependencies` has been added that is going
+ to become default in the next release. This makes use of `dep_template` flag
+ in the `whl_library` rule. This also affects the
+ `experimental_requirement_cycles` feature where the dependencies that are in
+ a group would be only accessible via the hub repo aliases. If you still
+ depend on legacy labels instead of the hub repo aliases and you use the
+ `experimental_requirement_cycles`, now is a good time to migrate.
[0.XX.0]: https://github.com/bazelbuild/rules_python/releases/tag/0.XX.0
[python_default_visibility]: gazelle/README.md#directive-python_default_visibility
diff --git a/python/pip_install/pip_repository.bzl b/python/pip_install/pip_repository.bzl
index 55d61fc..db67368 100644
--- a/python/pip_install/pip_repository.bzl
+++ b/python/pip_install/pip_repository.bzl
@@ -365,9 +365,12 @@
"python_interpreter": _get_python_interpreter_attr(rctx),
"quiet": rctx.attr.quiet,
"repo": rctx.attr.name,
- "repo_prefix": "{}_".format(rctx.attr.name),
"timeout": rctx.attr.timeout,
}
+ if rctx.attr.use_hub_alias_dependencies:
+ config["dep_template"] = "@{}//{{name}}:{{target}}".format(rctx.attr.name)
+ else:
+ config["repo_prefix"] = "{}_".format(rctx.attr.name)
if rctx.attr.python_interpreter_target:
config["python_interpreter_target"] = str(rctx.attr.python_interpreter_target)
@@ -387,6 +390,13 @@
rctx.file("BUILD.bazel", _BUILD_FILE_CONTENTS)
rctx.template("requirements.bzl", rctx.attr._template, substitutions = {
+ " # %%GROUP_LIBRARY%%": """\
+ group_repo = "{name}__groups"
+ group_library(
+ name = group_repo,
+ repo_prefix = "{name}_",
+ groups = all_requirement_groups,
+ )""".format(name = rctx.attr.name) if not rctx.attr.use_hub_alias_dependencies else "",
"%%ALL_DATA_REQUIREMENTS%%": _format_repr_list([
macro_tmpl.format(p, "data")
for p in bzl_packages
@@ -595,6 +605,8 @@
"repo_prefix": attr.string(
doc = """
Prefix for the generated packages will be of the form `@<prefix><sanitized-package-name>//...`
+
+DEPRECATED. Only left for people who vendor requirements.bzl.
""",
),
# 600 is documented as default here: https://docs.bazel.build/versions/master/skylark/lib/repository_ctx.html#execute
@@ -637,6 +649,15 @@
allow_single_file = True,
doc = "Override the requirements_lock attribute when the host platform is Windows",
),
+ "use_hub_alias_dependencies": attr.bool(
+ default = False,
+ doc = """\
+Controls if the hub alias dependencies are used. If set to true, then the
+group_library will be included in the hub repo.
+
+True will become default in a subsequent release.
+""",
+ ),
"_template": attr.label(
default = ":pip_repository_requirements.bzl.tmpl",
),
@@ -886,7 +907,7 @@
entry_points[entry_point_without_py] = entry_point_script_name
build_file_contents = generate_whl_library_build_bazel(
- repo_prefix = rctx.attr.repo_prefix,
+ dep_template = rctx.attr.dep_template or "@{}{{name}}//:{{target}}".format(rctx.attr.repo_prefix),
whl_name = whl_path.basename,
dependencies = metadata["deps"],
dependencies_by_platform = metadata["deps_by_platform"],
@@ -941,6 +962,13 @@
),
allow_files = True,
),
+ "dep_template": attr.string(
+ doc = """
+The dep template to use for referencing the dependencies. It should have `{name}`
+and `{target}` tokens that will be replaced with the normalized distribution name
+and the target that we need respectively.
+""",
+ ),
"filename": attr.string(
doc = "Download the whl file to this filename. Only used when the `urls` is passed. If not specified, will be auto-detected from the `urls`.",
),
diff --git a/python/pip_install/pip_repository_requirements.bzl.tmpl b/python/pip_install/pip_repository_requirements.bzl.tmpl
index 2b88f5c..8e17720 100644
--- a/python/pip_install/pip_repository_requirements.bzl.tmpl
+++ b/python/pip_install/pip_repository_requirements.bzl.tmpl
@@ -58,12 +58,7 @@
for requirement in group_requirements
}
- group_repo = "%%NAME%%__groups"
- group_library(
- name = group_repo,
- repo_prefix = "%%NAME%%_",
- groups = all_requirement_groups,
- )
+ # %%GROUP_LIBRARY%%
# Install wheels which may be participants in a group
whl_config = dict(_config)
diff --git a/python/pip_install/private/generate_group_library_build_bazel.bzl b/python/pip_install/private/generate_group_library_build_bazel.bzl
index c122b04..5fa93e2 100644
--- a/python/pip_install/private/generate_group_library_build_bazel.bzl
+++ b/python/pip_install/private/generate_group_library_build_bazel.bzl
@@ -22,9 +22,10 @@
"WHEEL_FILE_PUBLIC_LABEL",
)
load("//python/private:normalize_name.bzl", "normalize_name")
+load("//python/private:text_util.bzl", "render")
_PRELUDE = """\
-load("@rules_python//python:defs.bzl", "py_library", "py_binary")
+load("@rules_python//python:defs.bzl", "py_library")
"""
_GROUP_TEMPLATE = """\
@@ -62,26 +63,39 @@
which make up the group.
"""
- lib_dependencies = [
- "@%s%s//:%s" % (repo_prefix, normalize_name(d), PY_LIBRARY_IMPL_LABEL)
- for d in group_members
- ]
- whl_file_deps = [
- "@%s%s//:%s" % (repo_prefix, normalize_name(d), WHEEL_FILE_IMPL_LABEL)
- for d in group_members
- ]
- visibility = [
- "@%s%s//:__pkg__" % (repo_prefix, normalize_name(d))
- for d in group_members
- ]
+ group_members = sorted(group_members)
+
+ if repo_prefix:
+ lib_dependencies = [
+ "@%s%s//:%s" % (repo_prefix, normalize_name(d), PY_LIBRARY_IMPL_LABEL)
+ for d in group_members
+ ]
+ whl_file_deps = [
+ "@%s%s//:%s" % (repo_prefix, normalize_name(d), WHEEL_FILE_IMPL_LABEL)
+ for d in group_members
+ ]
+ visibility = [
+ "@%s%s//:__pkg__" % (repo_prefix, normalize_name(d))
+ for d in group_members
+ ]
+ else:
+ lib_dependencies = [
+ "//%s:%s" % (normalize_name(d), PY_LIBRARY_IMPL_LABEL)
+ for d in group_members
+ ]
+ whl_file_deps = [
+ "//%s:%s" % (normalize_name(d), WHEEL_FILE_IMPL_LABEL)
+ for d in group_members
+ ]
+ visibility = ["//:__subpackages__"]
return _GROUP_TEMPLATE.format(
name = normalize_name(group_name),
whl_public_label = WHEEL_FILE_PUBLIC_LABEL,
- whl_deps = repr(whl_file_deps),
+ whl_deps = render.indent(render.list(whl_file_deps)).lstrip(),
lib_public_label = PY_LIBRARY_PUBLIC_LABEL,
- lib_deps = repr(lib_dependencies),
- visibility = repr(visibility),
+ lib_deps = render.indent(render.list(lib_dependencies)).lstrip(),
+ visibility = render.indent(render.list(visibility)).lstrip(),
)
def generate_group_library_build_bazel(
diff --git a/python/pip_install/private/generate_whl_library_build_bazel.bzl b/python/pip_install/private/generate_whl_library_build_bazel.bzl
index b121909..8010ccb 100644
--- a/python/pip_install/private/generate_whl_library_build_bazel.bzl
+++ b/python/pip_install/private/generate_whl_library_build_bazel.bzl
@@ -213,7 +213,7 @@
def generate_whl_library_build_bazel(
*,
- repo_prefix,
+ dep_template,
whl_name,
dependencies,
dependencies_by_platform,
@@ -226,7 +226,7 @@
"""Generate a BUILD file for an unzipped Wheel
Args:
- repo_prefix: the repo prefix that should be used for dependency lists.
+ dep_template: the dependency template that should be used for dependency lists.
whl_name: the whl_name that this is generated for.
dependencies: a list of PyPI packages that are dependencies to the py_library.
dependencies_by_platform: a dict[str, list] of PyPI packages that may vary by platform.
@@ -328,38 +328,49 @@
lib_dependencies = _render_list_and_select(
deps = dependencies,
deps_by_platform = dependencies_by_platform,
- tmpl = "@{}{{}}//:{}".format(repo_prefix, PY_LIBRARY_PUBLIC_LABEL),
+ tmpl = dep_template.format(name = "{}", target = PY_LIBRARY_PUBLIC_LABEL),
)
whl_file_deps = _render_list_and_select(
deps = dependencies,
deps_by_platform = dependencies_by_platform,
- tmpl = "@{}{{}}//:{}".format(repo_prefix, WHEEL_FILE_PUBLIC_LABEL),
+ tmpl = dep_template.format(name = "{}", target = WHEEL_FILE_PUBLIC_LABEL),
)
# 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
# implementation.
- if group_name:
- group_repo = repo_prefix + "_groups"
- label_tmpl = "\"@{}//:{}_{{}}\"".format(group_repo, normalize_name(group_name))
- impl_vis = ["@{}//:__pkg__".format(group_repo)]
+ if group_name and "//:" in dep_template:
+ # This is the legacy behaviour where the group library is outside the hub repo
+ label_tmpl = dep_template.format(
+ name = "_groups",
+ target = normalize_name(group_name) + "_{}",
+ )
+ impl_vis = [dep_template.format(
+ name = "_groups",
+ target = "__pkg__",
+ )]
additional_content.extend([
"",
render.alias(
name = PY_LIBRARY_PUBLIC_LABEL,
- actual = label_tmpl.format(PY_LIBRARY_PUBLIC_LABEL),
+ actual = repr(label_tmpl.format(PY_LIBRARY_PUBLIC_LABEL)),
),
"",
render.alias(
name = WHEEL_FILE_PUBLIC_LABEL,
- actual = label_tmpl.format(WHEEL_FILE_PUBLIC_LABEL),
+ actual = repr(label_tmpl.format(WHEEL_FILE_PUBLIC_LABEL)),
),
])
py_library_label = PY_LIBRARY_IMPL_LABEL
whl_file_label = WHEEL_FILE_IMPL_LABEL
+ elif group_name:
+ py_library_label = PY_LIBRARY_PUBLIC_LABEL
+ whl_file_label = WHEEL_FILE_PUBLIC_LABEL
+ impl_vis = [dep_template.format(name = "", target = "__subpackages__")]
+
else:
py_library_label = PY_LIBRARY_PUBLIC_LABEL
whl_file_label = WHEEL_FILE_PUBLIC_LABEL
diff --git a/python/private/BUILD.bazel b/python/private/BUILD.bazel
index f1928e2..fdbd20b 100644
--- a/python/private/BUILD.bazel
+++ b/python/private/BUILD.bazel
@@ -227,6 +227,7 @@
":normalize_name_bzl",
":text_util_bzl",
":version_label_bzl",
+ "//python/pip_install/private:generate_group_library_build_bazel_bzl",
],
)
diff --git a/python/private/bzlmod/pip.bzl b/python/private/bzlmod/pip.bzl
index 3d5c0f5..ce68125 100644
--- a/python/private/bzlmod/pip.bzl
+++ b/python/private/bzlmod/pip.bzl
@@ -18,7 +18,6 @@
load("@pythons_hub//:interpreters.bzl", "DEFAULT_PYTHON_VERSION", "INTERPRETER_LABELS")
load(
"//python/pip_install:pip_repository.bzl",
- "group_library",
"locked_requirements_label",
"pip_repository_attrs",
"use_isolated",
@@ -101,7 +100,7 @@
whl_mods = whl_mods,
)
-def _create_whl_repos(module_ctx, pip_attr, whl_map, whl_overrides, simpleapi_cache):
+def _create_whl_repos(module_ctx, pip_attr, whl_map, whl_overrides, group_map, simpleapi_cache):
python_interpreter_target = pip_attr.python_interpreter_target
# if we do not have the python_interpreter set in the attributes
@@ -129,6 +128,7 @@
hub_name,
version_label(pip_attr.python_version),
)
+ major_minor = _major_minor_version(pip_attr.python_version)
requirements_lock = locked_requirements_label(module_ctx, pip_attr)
@@ -171,12 +171,11 @@
for whl_name in group_whls
}
- group_repo = "%s__groups" % (pip_name,)
- group_library(
- name = group_repo,
- repo_prefix = pip_name + "_",
- groups = pip_attr.experimental_requirement_cycles,
- )
+ # TODO @aignas 2024-04-05: how do we support different requirement
+ # cycles for different abis/oses? For now we will need the users to
+ # assume the same groups across all versions/platforms until we start
+ # using an alternative cycle resolution strategy.
+ group_map[hub_name] = pip_attr.experimental_requirement_cycles
else:
whl_group_mapping = {}
requirement_cycles = {}
@@ -202,8 +201,6 @@
parallel_download = pip_attr.parallel_download,
)
- major_minor = _major_minor_version(pip_attr.python_version)
-
# Create a new wheel library for each of the different whls
for whl_name, requirement_line in requirements:
# We are not using the "sanitized name" because the user
@@ -220,7 +217,7 @@
repo_name = "{}_{}".format(pip_name, whl_name)
whl_library_args = dict(
repo = pip_name,
- repo_prefix = pip_name + "_",
+ dep_template = "@{}//{{name}}:{{target}}".format(hub_name),
requirement = requirement_line,
)
maybe_args = dict(
@@ -422,6 +419,7 @@
# dict[hub, dict[whl, dict[version, str pip]]]
# Where hub, whl, and pip are the repo names
hub_whl_map = {}
+ hub_group_map = {}
simpleapi_cache = {}
@@ -460,7 +458,7 @@
else:
pip_hub_map[pip_attr.hub_name].python_versions.append(pip_attr.python_version)
- _create_whl_repos(module_ctx, pip_attr, hub_whl_map, whl_overrides, simpleapi_cache)
+ _create_whl_repos(module_ctx, pip_attr, hub_whl_map, whl_overrides, hub_group_map, simpleapi_cache)
for hub_name, whl_map in hub_whl_map.items():
pip_repository(
@@ -471,6 +469,7 @@
for key, value in whl_map.items()
},
default_version = _major_minor_version(DEFAULT_PYTHON_VERSION),
+ groups = hub_group_map.get(hub_name),
)
def _pip_parse_ext_attrs():
diff --git a/python/private/bzlmod/pip_repository.bzl b/python/private/bzlmod/pip_repository.bzl
index d96131d..3a09766 100644
--- a/python/private/bzlmod/pip_repository.bzl
+++ b/python/private/bzlmod/pip_repository.bzl
@@ -32,6 +32,7 @@
for key, values in rctx.attr.whl_map.items()
},
default_version = rctx.attr.default_version,
+ requirement_cycles = rctx.attr.groups,
)
for path, contents in aliases.items():
rctx.file(path, contents)
@@ -68,6 +69,9 @@
what is setup by the 'python' extension using the 'is_default = True'
setting.""",
),
+ "groups": attr.string_list_dict(
+ mandatory = False,
+ ),
"repo_name": attr.string(
mandatory = True,
doc = "The apparent name of the repo. This is needed because in bzlmod, the name attribute becomes the canonical name.",
diff --git a/python/private/render_pkg_aliases.bzl b/python/private/render_pkg_aliases.bzl
index 5851baf..bc1bab2 100644
--- a/python/private/render_pkg_aliases.bzl
+++ b/python/private/render_pkg_aliases.bzl
@@ -16,6 +16,19 @@
This is used in bzlmod and non-bzlmod setups."""
+load(
+ "//python/pip_install/private:generate_group_library_build_bazel.bzl",
+ "generate_group_library_build_bazel",
+) # buildifier: disable=bzl-visibility
+load(
+ ":labels.bzl",
+ "DATA_LABEL",
+ "DIST_INFO_LABEL",
+ "PY_LIBRARY_IMPL_LABEL",
+ "PY_LIBRARY_PUBLIC_LABEL",
+ "WHEEL_FILE_IMPL_LABEL",
+ "WHEEL_FILE_PUBLIC_LABEL",
+)
load(":normalize_name.bzl", "normalize_name")
load(":text_util.bzl", "render")
@@ -43,13 +56,18 @@
name,
default_version,
aliases,
+ target_name,
**kwargs):
"""Render an alias for common targets."""
if len(aliases) == 1 and not aliases[0].version:
alias = aliases[0]
return render.alias(
name = name,
- actual = repr("@{repo}//:{name}".format(repo = alias.repo, name = name)),
+ actual = repr("@{repo}//:{name}".format(
+ repo = alias.repo,
+ name = target_name,
+ )),
+ **kwargs
)
# Create the alias repositories which contains different select
@@ -58,7 +76,7 @@
selects = {}
no_match_error = "_NO_MATCH_ERROR"
for alias in sorted(aliases, key = lambda x: x.version):
- actual = "@{repo}//:{name}".format(repo = alias.repo, name = name)
+ actual = "@{repo}//:{name}".format(repo = alias.repo, name = target_name)
selects.setdefault(actual, []).append(alias.config_setting)
if alias.version == default_version:
selects[actual].append("//conditions:default")
@@ -84,7 +102,7 @@
**kwargs
)
-def _render_common_aliases(*, name, aliases, default_version = None):
+def _render_common_aliases(*, name, aliases, default_version = None, group_name = None):
lines = [
"""load("@bazel_skylib//lib:selects.bzl", "selects")""",
"""package(default_visibility = ["//visibility:public"])""",
@@ -119,17 +137,37 @@
lines.extend(
[
_render_whl_library_alias(
- name = target,
+ name = name,
default_version = default_version,
aliases = aliases,
+ target_name = target_name,
+ visibility = ["//_groups:__subpackages__"] if name.startswith("_") else None,
)
- for target in ["pkg", "whl", "data", "dist_info"]
+ for target_name, name in {
+ PY_LIBRARY_PUBLIC_LABEL: PY_LIBRARY_IMPL_LABEL if group_name else PY_LIBRARY_PUBLIC_LABEL,
+ WHEEL_FILE_PUBLIC_LABEL: WHEEL_FILE_IMPL_LABEL if group_name else WHEEL_FILE_PUBLIC_LABEL,
+ DATA_LABEL: DATA_LABEL,
+ DIST_INFO_LABEL: DIST_INFO_LABEL,
+ }.items()
],
)
+ if group_name:
+ lines.extend(
+ [
+ render.alias(
+ name = "pkg",
+ actual = repr("//_groups:{}_pkg".format(group_name)),
+ ),
+ render.alias(
+ name = "whl",
+ actual = repr("//_groups:{}_whl".format(group_name)),
+ ),
+ ],
+ )
return "\n\n".join(lines)
-def render_pkg_aliases(*, aliases, default_version = None):
+def render_pkg_aliases(*, aliases, default_version = None, requirement_cycles = None):
"""Create alias declarations for each PyPI package.
The aliases should be appended to the pip_repository BUILD.bazel file. These aliases
@@ -140,6 +178,7 @@
aliases: dict, the keys are normalized distribution names and values are the
whl_alias instances.
default_version: the default version to be used for the aliases.
+ requirement_cycles: any package groups to also add.
Returns:
A dict of file paths and their contents.
@@ -150,16 +189,33 @@
elif type(aliases) != type({}):
fail("The aliases need to be provided as a dict, got: {}".format(type(aliases)))
- return {
+ whl_group_mapping = {}
+ if requirement_cycles:
+ requirement_cycles = {
+ name: [normalize_name(whl_name) for whl_name in whls]
+ for name, whls in requirement_cycles.items()
+ }
+
+ whl_group_mapping = {
+ whl_name: group_name
+ for group_name, group_whls in requirement_cycles.items()
+ for whl_name in group_whls
+ }
+
+ files = {
"{}/BUILD.bazel".format(normalize_name(name)): _render_common_aliases(
name = normalize_name(name),
aliases = pkg_aliases,
default_version = default_version,
+ group_name = whl_group_mapping.get(normalize_name(name)),
).strip()
for name, pkg_aliases in aliases.items()
}
+ if requirement_cycles:
+ files["_groups/BUILD.bazel"] = generate_group_library_build_bazel("", requirement_cycles)
+ return files
-def whl_alias(*, repo, version = None, config_setting = None):
+def whl_alias(*, repo, version = None, config_setting = None, extra_targets = None):
"""The bzl_packages value used by by the render_pkg_aliases function.
This contains the minimum amount of information required to generate correct
@@ -173,6 +229,8 @@
is no match found during a select.
config_setting: optional(Label or str), the config setting that we should use. Defaults
to "@rules_python//python/config_settings:is_python_{version}".
+ extra_targets: optional(list[str]), the extra targets that we need to create
+ aliases for.
Returns:
a struct with the validated and parsed values.
@@ -188,4 +246,5 @@
repo = repo,
version = version,
config_setting = config_setting,
+ extra_targets = extra_targets or [],
)
diff --git a/tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl b/tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl
index ddc9da7..a38d657 100644
--- a/tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl
+++ b/tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl
@@ -388,6 +388,50 @@
_tests.append(_test_aliases_are_created_for_all_wheels)
+def _test_aliases_with_groups(env):
+ actual = render_pkg_aliases(
+ default_version = "3.2",
+ aliases = {
+ "bar": [
+ whl_alias(version = "3.1", repo = "pypi_31_bar"),
+ whl_alias(version = "3.2", repo = "pypi_32_bar"),
+ ],
+ "baz": [
+ whl_alias(version = "3.1", repo = "pypi_31_baz"),
+ whl_alias(version = "3.2", repo = "pypi_32_baz"),
+ ],
+ "foo": [
+ whl_alias(version = "3.1", repo = "pypi_32_foo"),
+ whl_alias(version = "3.2", repo = "pypi_31_foo"),
+ ],
+ },
+ requirement_cycles = {
+ "group": ["bar", "baz"],
+ },
+ )
+
+ want_files = [
+ "bar/BUILD.bazel",
+ "foo/BUILD.bazel",
+ "baz/BUILD.bazel",
+ "_groups/BUILD.bazel",
+ ]
+ env.expect.that_dict(actual).keys().contains_exactly(want_files)
+
+ want_key = "_groups/BUILD.bazel"
+
+ # Just check that it contains a private whl
+ env.expect.that_str(actual[want_key]).contains("//bar:_whl")
+
+ want_key = "bar/BUILD.bazel"
+
+ # Just check that it contains a private whl
+ env.expect.that_str(actual[want_key]).contains("name = \"_whl\"")
+ env.expect.that_str(actual[want_key]).contains("name = \"whl\"")
+ env.expect.that_str(actual[want_key]).contains("\"//_groups:group_whl\"")
+
+_tests.append(_test_aliases_with_groups)
+
def render_pkg_aliases_test_suite(name):
"""Create the test suite.
diff --git a/tests/pip_install/group_library/generate_build_bazel_tests.bzl b/tests/pip_install/group_library/generate_build_bazel_tests.bzl
index e7d6b44..cf082c2 100644
--- a/tests/pip_install/group_library/generate_build_bazel_tests.bzl
+++ b/tests/pip_install/group_library/generate_build_bazel_tests.bzl
@@ -21,7 +21,7 @@
def _test_simple(env):
want = """\
-load("@rules_python//python:defs.bzl", "py_library", "py_binary")
+load("@rules_python//python:defs.bzl", "py_library")
## Group vbap
@@ -29,25 +29,72 @@
filegroup(
name = "vbap_whl",
srcs = [],
- data = ["@pypi_oletools//:_whl", "@pypi_pcodedmp//:_whl"],
- visibility = ["@pypi_oletools//:__pkg__", "@pypi_pcodedmp//:__pkg__"],
+ data = [
+ "@pypi_oletools//:_whl",
+ "@pypi_pcodedmp//:_whl",
+ ],
+ visibility = [
+ "@pypi_oletools//:__pkg__",
+ "@pypi_pcodedmp//:__pkg__",
+ ],
)
py_library(
name = "vbap_pkg",
srcs = [],
- deps = ["@pypi_oletools//:_pkg", "@pypi_pcodedmp//:_pkg"],
- visibility = ["@pypi_oletools//:__pkg__", "@pypi_pcodedmp//:__pkg__"],
+ deps = [
+ "@pypi_oletools//:_pkg",
+ "@pypi_pcodedmp//:_pkg",
+ ],
+ visibility = [
+ "@pypi_oletools//:__pkg__",
+ "@pypi_pcodedmp//:__pkg__",
+ ],
)
"""
actual = generate_group_library_build_bazel(
repo_prefix = "pypi_",
- groups = {"vbap": ["oletools", "pcodedmp"]},
+ groups = {"vbap": ["pcodedmp", "oletools"]},
)
env.expect.that_str(actual).equals(want)
_tests.append(_test_simple)
+def _test_in_hub(env):
+ want = """\
+load("@rules_python//python:defs.bzl", "py_library")
+
+
+## Group vbap
+
+filegroup(
+ name = "vbap_whl",
+ srcs = [],
+ data = [
+ "//oletools:_whl",
+ "//pcodedmp:_whl",
+ ],
+ visibility = ["//:__subpackages__"],
+)
+
+py_library(
+ name = "vbap_pkg",
+ srcs = [],
+ deps = [
+ "//oletools:_pkg",
+ "//pcodedmp:_pkg",
+ ],
+ visibility = ["//:__subpackages__"],
+)
+"""
+ actual = generate_group_library_build_bazel(
+ repo_prefix = "",
+ groups = {"vbap": ["pcodedmp", "oletools"]},
+ )
+ env.expect.that_str(actual).equals(want)
+
+_tests.append(_test_in_hub)
+
def generate_build_bazel_test_suite(name):
"""Create the test suite.
diff --git a/tests/pip_install/whl_library/generate_build_bazel_tests.bzl b/tests/pip_install/whl_library/generate_build_bazel_tests.bzl
index 11611b9..66126cf 100644
--- a/tests/pip_install/whl_library/generate_build_bazel_tests.bzl
+++ b/tests/pip_install/whl_library/generate_build_bazel_tests.bzl
@@ -71,7 +71,7 @@
)
"""
actual = generate_whl_library_build_bazel(
- repo_prefix = "pypi_",
+ dep_template = "@pypi_{name}//:{target}",
whl_name = "foo.whl",
dependencies = ["foo", "bar-baz"],
dependencies_by_platform = {},
@@ -216,7 +216,7 @@
)
"""
actual = generate_whl_library_build_bazel(
- repo_prefix = "pypi_",
+ dep_template = "@pypi_{name}//:{target}",
whl_name = "foo.whl",
dependencies = ["foo", "bar-baz"],
dependencies_by_platform = {
@@ -305,7 +305,7 @@
# SOMETHING SPECIAL AT THE END
"""
actual = generate_whl_library_build_bazel(
- repo_prefix = "pypi_",
+ dep_template = "@pypi_{name}//:{target}",
whl_name = "foo.whl",
dependencies = ["foo", "bar-baz"],
dependencies_by_platform = {},
@@ -386,7 +386,7 @@
)
"""
actual = generate_whl_library_build_bazel(
- repo_prefix = "pypi_",
+ dep_template = "@pypi_{name}//:{target}",
whl_name = "foo.whl",
dependencies = ["foo", "bar-baz"],
dependencies_by_platform = {},
@@ -482,7 +482,7 @@
)
"""
actual = generate_whl_library_build_bazel(
- repo_prefix = "pypi_",
+ dep_template = "@pypi_{name}//:{target}",
whl_name = "foo.whl",
dependencies = ["foo", "bar-baz", "qux"],
dependencies_by_platform = {
@@ -501,6 +501,98 @@
_tests.append(_test_group_member)
+def _test_group_member_deps_to_hub(env):
+ want = """\
+load("@rules_python//python:defs.bzl", "py_library", "py_binary")
+load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
+
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+ name = "dist_info",
+ srcs = glob(["site-packages/*.dist-info/**"], allow_empty = True),
+)
+
+filegroup(
+ name = "data",
+ srcs = glob(["data/**"], allow_empty = True),
+)
+
+filegroup(
+ name = "whl",
+ srcs = ["foo.whl"],
+ data = ["@pypi//bar_baz:whl"] + select(
+ {
+ "@platforms//os:linux": ["@pypi//box:whl"],
+ ":is_linux_x86_64": [
+ "@pypi//box:whl",
+ "@pypi//box_amd64:whl",
+ ],
+ "//conditions:default": [],
+ },
+ ),
+ visibility = ["@pypi//:__subpackages__"],
+)
+
+py_library(
+ name = "pkg",
+ srcs = glob(
+ ["site-packages/**/*.py"],
+ exclude=[],
+ # Empty sources are allowed to support wheels that don't have any
+ # pure-Python code, e.g. pymssql, which is written in Cython.
+ allow_empty = True,
+ ),
+ data = [] + glob(
+ ["site-packages/**/*"],
+ exclude=["**/* *", "**/*.py", "**/*.pyc", "**/*.pyc.*", "**/*.dist-info/RECORD"],
+ ),
+ # This makes this directory a top-level in the python import
+ # search path for anything that depends on this.
+ imports = ["site-packages"],
+ deps = ["@pypi//bar_baz:pkg"] + select(
+ {
+ "@platforms//os:linux": ["@pypi//box:pkg"],
+ ":is_linux_x86_64": [
+ "@pypi//box:pkg",
+ "@pypi//box_amd64:pkg",
+ ],
+ "//conditions:default": [],
+ },
+ ),
+ tags = [],
+ visibility = ["@pypi//:__subpackages__"],
+)
+
+config_setting(
+ name = "is_linux_x86_64",
+ constraint_values = [
+ "@platforms//cpu:x86_64",
+ "@platforms//os:linux",
+ ],
+ visibility = ["//visibility:private"],
+)
+"""
+ actual = generate_whl_library_build_bazel(
+ dep_template = "@pypi//{name}:{target}",
+ whl_name = "foo.whl",
+ dependencies = ["foo", "bar-baz", "qux"],
+ dependencies_by_platform = {
+ "linux_x86_64": ["box", "box-amd64"],
+ "windows_x86_64": ["fox"],
+ "@platforms//os:linux": ["box"], # buildifier: disable=unsorted-dict-items to check that we sort inside the test
+ },
+ tags = [],
+ entry_points = {},
+ data_exclude = [],
+ annotation = None,
+ group_name = "qux",
+ group_deps = ["foo", "fox", "qux"],
+ )
+ env.expect.that_str(actual.replace("@@", "@")).equals(want)
+
+_tests.append(_test_group_member_deps_to_hub)
+
def generate_build_bazel_test_suite(name):
"""Create the test suite.