Skip to content

feat(pypi): generate filegroup with all extracted wheel files #3011

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ END_UNRELEASED_TEMPLATE
* (pypi) To configure the environment for `requirements.txt` evaluation, use the newly added
developer preview of the `pip.default` tag class. Only `rules_python` and root modules can use
this feature. You can also configure custom `config_settings` using `pip.default`.
* (pypi) PyPI dependencies now expose an `:extracted_whl_files` filegroup target
of all the files extracted from the wheel. This can be used in lieu of
{obj}`whl_filegroup` to avoid copying/extracting wheel multiple times to
get a subset of their files.

{#v0-0-0-removed}
### Removed
Expand Down
7 changes: 7 additions & 0 deletions docs/pypi/use.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,16 @@ Note that the hub repo contains the following targets for each package:
* `@pypi//numpy:data` - the {obj}`filegroup` for all of the extra files that are included
as data in the `pkg` target.
* `@pypi//numpy:dist_info` - the {obj}`filegroup` for all of the files in the `<pkg prefix with version>.distinfo` directory.
* `@pypi//numpy:extracted_whl_files` - a {obj}`filegroup` of all the files
extracted from the whl file.
* `@pypi//numpy:whl` - the {obj}`filegroup` that is the `.whl` file itself, which includes all
transitive dependencies via the {attr}`filegroup.data` attribute.

:::{versionadded} VERSION_NEXT_FEATURE

The `:extracted_whl_files` target was added
:::

## Entry points

If you would like to access [entry points][whl_ep], see the `py_console_script_binary` rule documentation,
Expand Down
1 change: 1 addition & 0 deletions python/private/pypi/labels.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

"""Constants used by parts of pip_repository for naming libraries and wheels."""

EXTRACTED_WHEEL_FILES = "extracted_whl_files"
WHEEL_FILE_PUBLIC_LABEL = "whl"
WHEEL_FILE_IMPL_LABEL = "_whl"
PY_LIBRARY_PUBLIC_LABEL = "pkg"
Expand Down
2 changes: 2 additions & 0 deletions python/private/pypi/pkg_aliases.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ load(
":labels.bzl",
"DATA_LABEL",
"DIST_INFO_LABEL",
"EXTRACTED_WHEEL_FILES",
"PY_LIBRARY_IMPL_LABEL",
"PY_LIBRARY_PUBLIC_LABEL",
"WHEEL_FILE_IMPL_LABEL",
Expand Down Expand Up @@ -151,6 +152,7 @@ def pkg_aliases(
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,
EXTRACTED_WHEEL_FILES: EXTRACTED_WHEEL_FILES,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: add a test for this. Just need to have some that references it.

} | {
x: x
for x in extra_aliases or []
Expand Down
5 changes: 5 additions & 0 deletions python/private/pypi/whl_library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ def _whl_library_impl(rctx):
environment = _create_repository_execution_environment(rctx, python_interpreter, logger = logger)

whl_path = None
sdist_filename = None
if rctx.attr.whl_file:
whl_path = rctx.path(rctx.attr.whl_file)

Expand Down Expand Up @@ -276,6 +277,8 @@ def _whl_library_impl(rctx):
if filename.endswith(".whl"):
whl_path = rctx.path(filename)
else:
sdist_filename = filename

# It is an sdist and we need to tell PyPI to use a file in this directory
# and, allow getting build dependencies from PYTHONPATH, which we
# setup in this repository rule, but still download any necessary
Expand Down Expand Up @@ -381,6 +384,7 @@ def _whl_library_impl(rctx):

build_file_contents = generate_whl_library_build_bazel(
name = whl_path.basename,
sdist_filename = sdist_filename,
dep_template = rctx.attr.dep_template or "@{}{{name}}//:{{target}}".format(rctx.attr.repo_prefix),
entry_points = entry_points,
metadata_name = metadata.name,
Expand Down Expand Up @@ -454,6 +458,7 @@ def _whl_library_impl(rctx):

build_file_contents = generate_whl_library_build_bazel(
name = whl_path.basename,
sdist_filename = sdist_filename,
dep_template = rctx.attr.dep_template or "@{}{{name}}//:{{target}}".format(rctx.attr.repo_prefix),
entry_points = entry_points,
# TODO @aignas 2025-05-17: maybe have a build flag for this instead
Expand Down
44 changes: 36 additions & 8 deletions python/private/pypi/whl_library_targets.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ load(
":labels.bzl",
"DATA_LABEL",
"DIST_INFO_LABEL",
"EXTRACTED_WHEEL_FILES",
"PY_LIBRARY_IMPL_LABEL",
"PY_LIBRARY_PUBLIC_LABEL",
"WHEEL_ENTRY_POINT_PREFIX",
Expand All @@ -33,6 +34,16 @@ load(
load(":namespace_pkgs.bzl", "create_inits")
load(":pep508_deps.bzl", "deps")

# Files that are special to the Bazel processing of things.
_BAZEL_REPO_FILE_GLOBS = [
"BUILD",
"BUILD.bazel",
"REPO.bazel",
"WORKSPACE",
"WORKSPACE",
"WORKSPACE.bazel",
]

def whl_library_targets_from_requires(
*,
name,
Expand Down Expand Up @@ -100,11 +111,8 @@ def whl_library_targets(
data_exclude = [],
srcs_exclude = [],
tags = [],
filegroups = {
DIST_INFO_LABEL: ["site-packages/*.dist-info/**"],
DATA_LABEL: ["data/**"],
},
dependencies = [],
filegroups = None,
dependencies_by_platform = {},
dependencies_with_markers = {},
group_deps = [],
Expand All @@ -126,6 +134,8 @@ def whl_library_targets(
Args:
name: {type}`str` The file to match for including it into the `whl`
filegroup. This may be also parsed to generate extra metadata.
sdist_filename: {type}`str | None` If the wheel was built from an sdist,
the filename of the sdist.
dep_template: {type}`str` The dep_template to use for dependency
interpolation.
tags: {type}`list[str]` The tags set on the `py_library`.
Expand All @@ -134,8 +144,8 @@ def whl_library_targets(
dependencies by platform key.
dependencies_with_markers: {type}`dict[str, str]` A marker to evaluate
in order for the dep to be included.
filegroups: {type}`dict[str, list[str]]` A dictionary of the target
names and the glob matches.
filegroups: {type}`dict[str, list[str]] | None` A dictionary of the target
names and the glob matches. If `None`, defaults will be used.
group_name: {type}`str` name of the dependency group (if any) which
contains this library. If set, this library will behave as a shim
to group implementation rules which will provide simultaneously
Expand Down Expand Up @@ -168,10 +178,28 @@ def whl_library_targets(
tags = sorted(tags)
data = [] + data

for filegroup_name, glob in filegroups.items():
if filegroups == None:
filegroups = {
EXTRACTED_WHEEL_FILES: dict(
include = ["**"],
exclude = (
_BAZEL_REPO_FILE_GLOBS +
[sdist_filename] if sdist_filename else []
),
),
DIST_INFO_LABEL: dict(
include = ["site-packages/*.dist-info/**"],
),
DATA_LABEL: dict(
include = ["data/**"],
),
}

for filegroup_name, glob_kwargs in filegroups.items():
glob_kwargs = {"allow_empty": True} | glob_kwargs
native.filegroup(
name = filegroup_name,
srcs = native.glob(glob, allow_empty = True),
srcs = native.glob(**glob_kwargs),
visibility = ["//visibility:public"],
)

Expand Down
7 changes: 7 additions & 0 deletions python/private/whl_filegroup/whl_filegroup.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,14 @@ cc_library(
includes = ["numpy_includes/numpy/core/include"],
deps = ["@rules_python//python/cc:current_py_cc_headers"],
)

```

:::{seealso}

The `:extracted_whl_files` target, which is a filegroup of all the files
from the already extracted whl file.
:::
""",
attrs = {
"pattern": attr.string(default = "", doc = "Only file paths matching this regex pattern will be extracted."),
Expand Down