Skip to content

Commit 1a68b47

Browse files
committed
Merge branch 'venvs-single-files' into exp/distinfo-venv
2 parents b40d96a + 2fd17f8 commit 1a68b47

23 files changed

+345
-307
lines changed

.bazelrc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
# (Note, we cannot use `common --deleted_packages` because the bazel version command doesn't support it)
55
# To update these lines, execute
66
# `bazel run @rules_bazel_integration_test//tools:update_deleted_packages`
7-
build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered,tests/modules/other,tests/modules/other/nspkg_delta,tests/modules/other/nspkg_gamma
8-
query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered,tests/modules/other,tests/modules/other/nspkg_delta,tests/modules/other/nspkg_gamma
7+
build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered,tests/modules/other,tests/modules/other/nspkg_delta,tests/modules/other/nspkg_gamma,tests/modules/other/nspkg_single
8+
query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered,tests/modules/other,tests/modules/other/nspkg_delta,tests/modules/other/nspkg_gamma,tests/modules/other/nspkg_single
99

1010
test --test_output=errors
1111

python/config_settings/BUILD.bazel

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,15 @@ string_flag(
217217
visibility = ["//visibility:public"],
218218
)
219219

220+
config_setting(
221+
name = "is_venvs_site_packages",
222+
flag_values = {
223+
":venvs_site_packages": VenvsSitePackages.YES,
224+
},
225+
# NOTE: Only public because it is used in whl_library repos.
226+
visibility = ["//visibility:public"],
227+
)
228+
220229
define_pypi_internal_flags(
221230
name = "define_pypi_internal_flags",
222231
)

python/private/py_library.bzl

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ def _get_site_packages_symlinks(ctx):
253253

254254
repo_runfiles_dirname = None
255255
dirs_with_init = {} # dirname -> runfile path
256+
site_packages_symlinks = []
256257
for src in ctx.files.srcs:
257258
if src.extension not in PYTHON_FILE_EXTENSIONS:
258259
continue
@@ -261,16 +262,19 @@ def _get_site_packages_symlinks(ctx):
261262
continue
262263
path = path.removeprefix(site_packages_root)
263264
dir_name, _, filename = path.rpartition("/")
264-
if not dir_name:
265-
# This would be e.g. `site-packages/__init__.py`, which isn't valid
266-
# because it's not within a directory for an importable Python package.
267-
# However, the pypi integration over-eagerly adds a pkgutil-style
268-
# __init__.py file during the repo phase. Just ignore them for now.
269-
continue
270265

271-
if filename.startswith("__init__."):
266+
if dir_name and filename.startswith("__init__."):
272267
dirs_with_init[dir_name] = None
273268
repo_runfiles_dirname = runfiles_root_path(ctx, src.short_path).partition("/")[0]
269+
elif not dir_name:
270+
repo_runfiles_dirname = runfiles_root_path(ctx, src.short_path).partition("/")[0]
271+
272+
# This would be files that do not have directories and we just need to add
273+
# direct symlinks to them as is:
274+
site_packages_symlinks.append((
275+
paths.join(repo_runfiles_dirname, site_packages_root, filename),
276+
filename,
277+
))
274278

275279
# Sort so that we encounter `foo` before `foo/bar`. This ensures we
276280
# see the top-most explicit package first.
@@ -286,7 +290,6 @@ def _get_site_packages_symlinks(ctx):
286290
if not is_sub_package:
287291
first_level_explicit_packages.append(d)
288292

289-
site_packages_symlinks = []
290293
for dirname in first_level_explicit_packages:
291294
site_packages_symlinks.append((
292295
paths.join(repo_runfiles_dirname, site_packages_root, dirname),

python/private/pypi/BUILD.bazel

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ package(default_visibility = ["//:__subpackages__"])
1818

1919
licenses(["notice"])
2020

21+
exports_files(
22+
srcs = ["namespace_pkg_tmpl.py"],
23+
visibility = ["//visibility:public"],
24+
)
25+
2126
filegroup(
2227
name = "distribution",
2328
srcs = glob(
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# __path__ manipulation added by bazel-contrib/rules_python to support namespace pkgs.
2+
__path__ = __import__("pkgutil").extend_path(__path__, __name__)
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
"""Utilities to get where we should write namespace pkg paths."""
2+
3+
load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
4+
5+
_ext = struct(
6+
py = ".py",
7+
pyd = ".pyd",
8+
so = ".so",
9+
pyc = ".pyc",
10+
)
11+
12+
_TEMPLATE = Label("//python/private/pypi:namespace_pkg_tmpl.py")
13+
14+
def _add_all(dirname, dirs):
15+
dir_path = "."
16+
for dir_name in dirname.split("/"):
17+
dir_path = "{}/{}".format(dir_path, dir_name)
18+
dirs[dir_path[2:]] = None
19+
20+
def get_files(*, srcs, ignored_dirnames = [], root = None):
21+
"""Get the list of filenames to write the namespace pkg files.
22+
23+
Args:
24+
srcs: {type}`src` a list of files to be passed to {bzl:obj}`py_library`
25+
as `srcs` and `data`. This is usually a result of a {obj}`glob`.
26+
ignored_dirnames: {type}`str` a list of patterns to ignore.
27+
root: {type}`str` the prefix to use as the root.
28+
29+
Returns:
30+
{type}`src` a list of paths to write the namespace pkg `__init__.py` file.
31+
"""
32+
dirs = {}
33+
ignored = {i: None for i in ignored_dirnames}
34+
35+
if root:
36+
_add_all(root, ignored)
37+
38+
for file in srcs:
39+
dirname, _, filename = file.rpartition("/")
40+
41+
if filename == "__init__.py":
42+
ignored[dirname] = None
43+
dirname, _, _ = dirname.rpartition("/")
44+
elif filename.endswith(_ext.py):
45+
pass
46+
elif filename.endswith(_ext.pyc):
47+
pass
48+
elif filename.endswith(_ext.pyd):
49+
pass
50+
elif filename.endswith(_ext.so):
51+
pass
52+
else:
53+
continue
54+
55+
if dirname in dirs or not dirname:
56+
continue
57+
58+
_add_all(dirname, dirs)
59+
60+
return sorted([d for d in dirs if d not in ignored])
61+
62+
def create_inits(**kwargs):
63+
"""Create init files and return the list to be included `py_library` srcs.
64+
65+
Args:
66+
**kwargs: passed to {obj}`get_files`.
67+
68+
Returns:
69+
{type}`list[str]` to be included as part of `py_library`.
70+
"""
71+
srcs = []
72+
for out in get_files(**kwargs):
73+
src = "{}/__init__.py".format(out)
74+
srcs.append(srcs)
75+
76+
copy_file(
77+
name = "_cp_{}_namespace".format(out),
78+
src = _TEMPLATE,
79+
out = src,
80+
**kwargs
81+
)
82+
83+
return srcs

python/private/pypi/whl_installer/arguments.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,6 @@ def parser(**kwargs: Any) -> argparse.ArgumentParser:
5757
action="store",
5858
help="Additional data exclusion parameters to add to the pip packages BUILD file.",
5959
)
60-
parser.add_argument(
61-
"--enable_implicit_namespace_pkgs",
62-
action="store_true",
63-
help="Disables conversion of implicit namespace packages into pkg-util style packages.",
64-
)
6560
parser.add_argument(
6661
"--environment",
6762
action="store",

python/private/pypi/whl_installer/wheel_installer.py

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
from pip._vendor.packaging.utils import canonicalize_name
2929

30-
from python.private.pypi.whl_installer import arguments, namespace_pkgs, wheel
30+
from python.private.pypi.whl_installer import arguments, wheel
3131

3232

3333
def _configure_reproducible_wheels() -> None:
@@ -77,35 +77,10 @@ def _parse_requirement_for_extra(
7777
return None, None
7878

7979

80-
def _setup_namespace_pkg_compatibility(wheel_dir: str) -> None:
81-
"""Converts native namespace packages to pkgutil-style packages
82-
83-
Namespace packages can be created in one of three ways. They are detailed here:
84-
https://packaging.python.org/guides/packaging-namespace-packages/#creating-a-namespace-package
85-
86-
'pkgutil-style namespace packages' (2) and 'pkg_resources-style namespace packages' (3) works in Bazel, but
87-
'native namespace packages' (1) do not.
88-
89-
We ensure compatibility with Bazel of method 1 by converting them into method 2.
90-
91-
Args:
92-
wheel_dir: the directory of the wheel to convert
93-
"""
94-
95-
namespace_pkg_dirs = namespace_pkgs.implicit_namespace_packages(
96-
wheel_dir,
97-
ignored_dirnames=["%s/bin" % wheel_dir],
98-
)
99-
100-
for ns_pkg_dir in namespace_pkg_dirs:
101-
namespace_pkgs.add_pkgutil_style_namespace_pkg_init(ns_pkg_dir)
102-
103-
10480
def _extract_wheel(
10581
wheel_file: str,
10682
extras: Dict[str, Set[str]],
10783
enable_pipstar: bool,
108-
enable_implicit_namespace_pkgs: bool,
10984
platforms: List[wheel.Platform],
11085
installation_dir: Path = Path("."),
11186
) -> None:
@@ -116,15 +91,11 @@ def _extract_wheel(
11691
installation_dir: the destination directory for installation of the wheel.
11792
extras: a list of extras to add as dependencies for the installed wheel
11893
enable_pipstar: if true, turns off certain operations.
119-
enable_implicit_namespace_pkgs: if true, disables conversion of implicit namespace packages and will unzip as-is
12094
"""
12195

12296
whl = wheel.Wheel(wheel_file)
12397
whl.unzip(installation_dir)
12498

125-
if not enable_implicit_namespace_pkgs:
126-
_setup_namespace_pkg_compatibility(installation_dir)
127-
12899
metadata = {
129100
"entry_points": [
130101
{
@@ -168,7 +139,6 @@ def main() -> None:
168139
wheel_file=whl,
169140
extras=extras,
170141
enable_pipstar=args.enable_pipstar,
171-
enable_implicit_namespace_pkgs=args.enable_implicit_namespace_pkgs,
172142
platforms=arguments.get_platforms(args),
173143
)
174144
return

python/private/pypi/whl_library.bzl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,6 @@ def _parse_optional_attrs(rctx, args, extra_pip_args = None):
173173
json.encode(struct(arg = rctx.attr.pip_data_exclude)),
174174
]
175175

176-
if rctx.attr.enable_implicit_namespace_pkgs:
177-
args.append("--enable_implicit_namespace_pkgs")
178-
179176
env = {}
180177
if rctx.attr.environment != None:
181178
for key, value in rctx.attr.environment.items():
@@ -389,6 +386,8 @@ def _whl_library_impl(rctx):
389386
metadata_name = metadata.name,
390387
metadata_version = metadata.version,
391388
requires_dist = metadata.requires_dist,
389+
# TODO @aignas 2025-05-17: maybe have a build flag for this instead
390+
enable_implicit_namespace_pkgs = rctx.attr.enable_implicit_namespace_pkgs,
392391
# TODO @aignas 2025-04-14: load through the hub:
393392
annotation = None if not rctx.attr.annotation else struct(**json.decode(rctx.read(rctx.attr.annotation))),
394393
data_exclude = rctx.attr.pip_data_exclude,
@@ -457,6 +456,8 @@ def _whl_library_impl(rctx):
457456
name = whl_path.basename,
458457
dep_template = rctx.attr.dep_template or "@{}{{name}}//:{{target}}".format(rctx.attr.repo_prefix),
459458
entry_points = entry_points,
459+
# TODO @aignas 2025-05-17: maybe have a build flag for this instead
460+
enable_implicit_namespace_pkgs = rctx.attr.enable_implicit_namespace_pkgs,
460461
# TODO @aignas 2025-04-14: load through the hub:
461462
dependencies = metadata["deps"],
462463
dependencies_by_platform = metadata["deps_by_platform"],
@@ -580,7 +581,6 @@ attr makes `extra_pip_args` and `download_only` ignored.""",
580581
Label("//python/private/pypi/whl_installer:wheel.py"),
581582
Label("//python/private/pypi/whl_installer:wheel_installer.py"),
582583
Label("//python/private/pypi/whl_installer:arguments.py"),
583-
Label("//python/private/pypi/whl_installer:namespace_pkgs.py"),
584584
] + record_files.values(),
585585
),
586586
"_rule_name": attr.string(default = "whl_library"),

0 commit comments

Comments
 (0)