-
-
Notifications
You must be signed in to change notification settings - Fork 698
feat: data and pyi files in the venv #2936
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
Changes from 8 commits
9dd7589
1381bf8
42e5059
d59f85a
714b245
31e16ee
e0affec
c844aa0
f726341
ef8114e
fa1249a
30c1d01
dfa24b6
6405e4c
4d73e04
0c594e5
c70f05a
4c497f0
20d3c25
1d34260
a966f28
e82af52
db169c5
16f835a
5b7fb40
0abb1df
bcb2310
7b99ff7
e873c7e
02cae11
5df2411
2cf9688
15c73f3
c269638
9f58c91
18b1edf
507985b
d1142be
c298f3c
7ec284b
4f4e5fb
fbcbe6d
6cfa441
2081232
cdd6105
c1abbeb
65632f8
0c4dacd
eac2bba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,6 +41,7 @@ load( | |
| "runfiles_root_path", | ||
| ) | ||
| load(":flags.bzl", "AddSrcsToRunfilesFlag", "PrecompileFlag", "VenvsSitePackages") | ||
| load(":normalize_name.bzl", "normalize_name") | ||
| load(":precompile.bzl", "maybe_precompile") | ||
| load(":py_cc_link_params_info.bzl", "PyCcLinkParamsInfo") | ||
| load(":py_info.bzl", "PyInfo", "VenvSymlinkEntry", "VenvSymlinkKind") | ||
|
|
@@ -206,16 +207,32 @@ Source files are no longer added to the runfiles directly. | |
| ::: | ||
| """ | ||
|
|
||
| def _get_distinfo_metadata(ctx): | ||
| data = ctx.files.data or [] | ||
| for d in data: | ||
| # work on case insensitive FSes | ||
| if d.basename.lower() != "metadata": | ||
| continue | ||
|
|
||
| if d.dirname.endswith(".dist-info"): | ||
| return d | ||
|
|
||
| return None | ||
|
|
||
| def _get_imports_and_venv_symlinks(ctx, semantics): | ||
| imports = depset() | ||
| venv_symlinks = depset() | ||
|
aignas marked this conversation as resolved.
Outdated
|
||
| if VenvsSitePackages.is_enabled(ctx): | ||
| venv_symlinks = _get_venv_symlinks(ctx) | ||
| dist_info_metadata = _get_distinfo_metadata(ctx) | ||
|
aignas marked this conversation as resolved.
Outdated
|
||
| venv_symlinks = _get_venv_symlinks( | ||
|
aignas marked this conversation as resolved.
Outdated
|
||
| ctx, | ||
| dist_info_metadata, | ||
| ) | ||
| else: | ||
| imports = collect_imports(ctx, semantics) | ||
| return imports, venv_symlinks | ||
|
|
||
| def _get_venv_symlinks(ctx): | ||
| def _get_venv_symlinks(ctx, dist_info_metadata): | ||
| imports = ctx.attr.imports | ||
| if len(imports) == 0: | ||
| fail("When venvs_site_packages is enabled, exactly one `imports` " + | ||
|
|
@@ -254,16 +271,41 @@ def _get_venv_symlinks(ctx): | |
| repo_runfiles_dirname = None | ||
| dirs_with_init = {} # dirname -> runfile path | ||
| venv_symlinks = [] | ||
| for src in ctx.files.srcs: | ||
| if src.extension not in PYTHON_FILE_EXTENSIONS: | ||
| continue | ||
| package = None | ||
| if dist_info_metadata: | ||
| # in order to be able to have replacements in the venv, we have to add a | ||
| # third value into the venv_symlinks, which would be the normalized | ||
| # package name. This allows us to ensure that we can replace the `dist-info` | ||
| # directories by checking if the package key is there. | ||
| dist_info_dir = paths.basename(dist_info_metadata.dirname) | ||
| package, _, _suffix = dist_info_dir.rpartition(".dist-info") | ||
| package, _, _version = package.rpartition("-") | ||
| package = normalize_name(package) | ||
|
|
||
| repo_runfiles_dirname = runfiles_root_path(ctx, dist_info_metadata.short_path).partition("/")[0] | ||
| venv_symlinks.append(VenvSymlinkEntry( | ||
|
aignas marked this conversation as resolved.
Outdated
|
||
| kind = VenvSymlinkKind.LIB, | ||
| link_to_path = paths.join(repo_runfiles_dirname, site_packages_root, dist_info_dir), | ||
| src = package, | ||
| venv_path = dist_info_dir, | ||
| )) | ||
|
|
||
| for src in ctx.files.srcs + ctx.files.data: | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something seems wrong here, but I can't quite put my finger on it. Files in srcs have to have the init.py logic applied to detect namespace package boundaries to auto-detect the proper paths to create. Files in data shouldn't be part of that logic. If the file is within a directory covered by something in srcs (i.e *.py), then there's no need to look at the data file. If the data file isn't in a directory covered by something in srcs, then it shouldn't treat a .so/.pyi/.pyc file as some sort of boundary marker.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Talking about special treatment, I don't think I understand why we need it. We could just treat everything as just files and interleave the directories? There is nothing special in my mind here. Beforehand we had the auto-generated
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
You mean, for every file, create a venv_symlink entry? That won't scale because it doubles the number of files a binary has to materialize, when all that's really needed is e.g. one symlink to a directory. However, because of namespace packages, we can't simply use the directories directly under
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if we treat everything as
I am wondering how we can do this? |
||
| path = _repo_relative_short_path(src.short_path) | ||
| if not path.startswith(site_packages_root): | ||
| continue | ||
| path = path.removeprefix(site_packages_root) | ||
| dir_name, _, filename = path.rpartition("/") | ||
|
|
||
| if dir_name and filename.startswith("__init__."): | ||
| if src.extension not in PYTHON_FILE_EXTENSIONS: | ||
| if dir_name.endswith(".dist-info"): | ||
| # we have already handled the stuff | ||
| pass | ||
| elif dir_name: | ||
| # TODO @aignas 2025-05-30: is this the right way? | ||
| dirs_with_init[dir_name] = None | ||
| repo_runfiles_dirname = runfiles_root_path(ctx, src.short_path).partition("/")[0] | ||
| elif dir_name and filename.startswith("__init__."): | ||
| dirs_with_init[dir_name] = None | ||
| repo_runfiles_dirname = runfiles_root_path(ctx, src.short_path).partition("/")[0] | ||
| elif not dir_name: | ||
|
|
@@ -274,6 +316,7 @@ def _get_venv_symlinks(ctx): | |
| venv_symlinks.append(VenvSymlinkEntry( | ||
| kind = VenvSymlinkKind.LIB, | ||
| link_to_path = paths.join(repo_runfiles_dirname, site_packages_root, filename), | ||
| src = package, | ||
| venv_path = filename, | ||
| )) | ||
|
|
||
|
|
@@ -295,6 +338,7 @@ def _get_venv_symlinks(ctx): | |
| venv_symlinks.append(VenvSymlinkEntry( | ||
| kind = VenvSymlinkKind.LIB, | ||
| link_to_path = paths.join(repo_runfiles_dirname, site_packages_root, dirname), | ||
| src = package, | ||
| venv_path = dirname, | ||
| )) | ||
| return venv_symlinks | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| load("@rules_python//python:py_library.bzl", "py_library") | ||
|
|
||
| package(default_visibility = ["//visibility:public"]) | ||
|
|
||
| py_library( | ||
| name = "simple_v1", | ||
| srcs = glob(["site-packages/**/*.py"]), | ||
| data = glob( | ||
| ["**/*"], | ||
| exclude = ["site-packages/**/*.py"], | ||
| ), | ||
| experimental_venvs_site_packages = "@rules_python//python/config_settings:venvs_site_packages", | ||
| imports = [package_name() + "/site-packages"], | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| inside is v1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| __version__ = "1.0.0" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| # Intentionally empty |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| load("@rules_python//python:py_library.bzl", "py_library") | ||
|
|
||
| package(default_visibility = ["//visibility:public"]) | ||
|
|
||
| py_library( | ||
| name = "simple_v2", | ||
| srcs = glob(["site-packages/**/*.py"]), | ||
| data = glob( | ||
| ["**/*"], | ||
| exclude = ["site-packages/**/*.py"], | ||
| ), | ||
| experimental_venvs_site_packages = "@rules_python//python/config_settings:venvs_site_packages", | ||
| imports = [package_name() + "/site-packages"], | ||
| pyi_srcs = glob(["**/*.pyi"]), | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| inside is v1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Intentionally empty | ||
|
rickeylev marked this conversation as resolved.
Outdated
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| __version__ = "2.0.0" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| # Intentionally empty |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type description makes it clear they're keyed by package, so no need to restate it in prose.