Skip to content

Commit eb45eca

Browse files
authored
fix: write __init__ shim for pip runfiles helper (#519)
Fixes #377 Even though messing with __init__.py is a little risky, in this case its safer since we only generate it while symlinking files from external repositories into venv, and since https://github.com/bazelbuild/rules_python/blob/18f76f9cc4c3c6c4470f7a881e6ea4e8b80d7bab/python/runfiles/__init__.py#L15 is simple line, i can't think of easier fix than this. ### Changes are visible to end-users: no - Searched for relevant documentation and updated as needed: yes - Breaking change (forces users to change their own code or config): no - Suggested release notes appear below: no ### Test plan - New test cases added
1 parent 7b45c59 commit eb45eca

File tree

7 files changed

+70
-2
lines changed

7 files changed

+70
-2
lines changed

gazelle_python.yaml

+3-1
Original file line numberDiff line numberDiff line change
@@ -3833,6 +3833,8 @@ manifest:
38333833
rfc3986_validator: rfc3986_validator
38343834
rpds: rpds_py
38353835
rpds.rpds: rpds_py
3836+
runfiles: bazel_runfiles
3837+
runfiles.runfiles: bazel_runfiles
38363838
s3transfer: s3transfer
38373839
s3transfer.bandwidth: s3transfer
38383840
s3transfer.compat: s3transfer
@@ -4030,4 +4032,4 @@ manifest:
40304032
yaml.tokens: PyYAML
40314033
pip_repository:
40324034
name: pypi
4033-
integrity: 6359bc010056b6e19ee6cbb2fc9a8ac841449521e3b4997fec58163e5c635496
4035+
integrity: 7049b81983381a0118bd63ae8cb7f19126d0034fcbb256281453ee5cbf3499be

py/tests/py-binary/BUILD.bazel

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
load("@aspect_bazel_lib//lib:run_binary.bzl", "run_binary")
22
load("@aspect_bazel_lib//lib:testing.bzl", "assert_contains")
3-
load("//py:defs.bzl", "py_binary")
3+
load("@pypi//:requirements.bzl", "requirement")
4+
load("//py:defs.bzl", "py_binary", "py_test")
45

56
#################
67
# Case 1: main can be a string referencing some source file
@@ -48,3 +49,13 @@ assert_contains(
4849
actual = "main_from_name.out",
4950
expected = "running main_from_name",
5051
)
52+
53+
#################
54+
# Case 3: Runfiles from pip works
55+
py_test(
56+
name = "runfiles_from_pip_test",
57+
srcs = ["runfiles_from_pip.py"],
58+
data = ["test_data.txt"],
59+
main = "runfiles_from_pip.py",
60+
deps = [requirement("bazel-runfiles")],
61+
)
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import os
2+
import pathlib
3+
import unittest
4+
5+
import runfiles # requirement("bazel-runfiles")
6+
7+
class RunfilesTest(unittest.TestCase):
8+
def test_runfiles(self) -> None:
9+
r = runfiles.Runfiles.Create()
10+
path = pathlib.Path(r.Rlocation(os.getenv("BAZEL_WORKSPACE")+"/py/tests/py-binary/test_data.txt"))
11+
self.assertEquals(path.read_text(), "42\n")
12+
13+
if __name__ == "__main__":
14+
unittest.main()

py/tests/py-binary/test_data.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
42

py/tools/py/src/pth.rs

+36
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,29 @@ use std::{
66

77
use miette::{miette, Context, IntoDiagnostic, LabeledSpan, MietteDiagnostic, Severity};
88

9+
const RULES_PYTHON_INIT_PATH: &str = "runfiles/__init__.py";
10+
const RULES_PYTHON_RUNFILES_INIT_SHIM: &str = r#"
11+
# Generated by rules_py venv for rules_python compatibility
12+
# See: https://github.com/bazelbuild/rules_python/pull/2115
13+
# See: https://github.com/aspect-build/rules_py/issues/377
14+
from . import runfiles
15+
def _FindPythonRunfilesRoot():
16+
root = __file__
17+
# The original implementation of this function in rules_python expects the runfiles root to be 4 directories up from the current file.
18+
# but in rules_py there is additional two segments that it needs to go up to find the runfiles root.
19+
# bazel-bin/py/tests/external-deps/foo.runfiles/.foo.venv/lib/python3.9/site-packages/runfiles
20+
# ╰─────────────────────┬─────────────────────╯╰───┬───╯╰─────────────┬─────────────╯╰───┬───╯
21+
# bazel runfiles root venv root Python packages root Python package
22+
23+
for _ in range("rules_python/python/runfiles/runfiles.py".count("/") + 3):
24+
root = os.path.dirname(root)
25+
return root
26+
27+
runfiles._FindPythonRunfilesRoot = _FindPythonRunfilesRoot
28+
29+
from .runfiles import *
30+
"#;
31+
932
/// Strategy that will be used when creating the virtual env symlink and
1033
/// a collision is found.
1134
#[derive(Default, Debug)]
@@ -121,6 +144,19 @@ fn create_symlinks(
121144
// itself is not a regular package and is not supposed to have an `__init__.py` file.
122145
if path.is_dir() {
123146
create_symlinks(&path, root_dir, dst_dir, collision_strategy)?;
147+
}
148+
// rules_python runfiles helper needs some special handling when consumed as pip dependency.
149+
// See: https://github.com/aspect-build/rules_py/issues/377
150+
// See: https://github.com/bazelbuild/rules_python/pull/2115
151+
else if path.as_path().ends_with(RULES_PYTHON_INIT_PATH) {
152+
// Instead of symlinking the __init__.py file from its original location to the venv site-packages,
153+
// we write a shim __init__.py that makes the runfiles pypi library work with rules_py.
154+
fs::write(
155+
dst_dir.join(RULES_PYTHON_INIT_PATH),
156+
RULES_PYTHON_RUNFILES_INIT_SHIM,
157+
)
158+
.into_diagnostic()
159+
.wrap_err("Unable to write to runfiles __init__.py file")?;
124160
} else if dir != root_dir || entry.file_name() != "__init__.py" {
125161
create_symlink(&entry, root_dir, dst_dir, collision_strategy)?;
126162
}

requirements.in

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ snakesay
88
ftfy==6.2.0
99
neptune==1.10.2
1010
six
11+
bazel-runfiles

requirements.txt

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ attrs==23.2.0 \
1818
# via
1919
# jsonschema
2020
# referencing
21+
bazel-runfiles==1.1.0 \
22+
--hash=sha256:37f59ea505b86ada391ef94e0949ff38a6fd6c111c9a8338065b16b355d0efae
23+
# via -r requirements.in
2124
boto3==1.34.93 \
2225
--hash=sha256:b59355bf4a1408563969526f314611dbeacc151cf90ecb22af295dcc4fe18def \
2326
--hash=sha256:e39516e4ca21612932599819662759c04485d53ca457996a913163da11f052a4

0 commit comments

Comments
 (0)