bazel-contrib / bazel-contrib/rules_python

Runfiles `Rlocation()` call without `source_repo` param fails in custom python package

Open
#3,725 4 comments 0 reactions 0 assignees View on GitHub
Dominant language
Starlark
Stars
688
Forks
721
Avg merge
14h 49m
Merged PRs (30d)
81

Description

# 🐞 bug report

### Affected Rule

`python.runfiles` `Rlocation()`

### Is this a regression?

No

### Description

When we call `Rlocation()` inside of a custom python package without passing in the `source_repo=` parameter and import our package for use elsewhere, if `sys.path` includes a path to our package's code that is outside the runfiles directory, then the `Rlocation()` call will fail.

Specifically, this is caused by the code [here](https://github.com/bazel-contrib/rules_python/blob/afab5ed2a6bc587676d9ab4022bccf977cc8566a/python/runfiles/runfiles.py#L433-L437), which attempts to look up runfiles using the repository mapping of the caller of the `Rlocation()` method. If `sys.path` has found and run the copy of our python package that resides outside of the runfiles directory, then the `Rlocation()` call is legitimately coming from outside the runfiles directory, causing the underlying call to `self.CurrentRepository()` to fail.

A custom package which calls `Rlocation()` shouldn't be required to provide the `source_repo=` parameter or else run the risk of error due to being found outside of the runfiles directory due to the configuration of `sys.path`.

## 🔬 Minimal Reproduction

`MODULE.bazel`

```
module(name = "reproducer")

bazel_dep(
name = "rules_python",
version = "1.9.0"
)

python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
python_version = "3.14",
)
```

`BUILD.bazel`

```
load("@rules_python//python:py_binary.bzl", "py_binary")
load("@rules_python//python:py_library.bzl", "py_library")

py_binary(
name = "binary",
srcs = ["binary.py"],
deps = [":library"],
visibility = ["//visibility:public"],
)

py_library(
name = "library",
srcs = ["library/__init__.py"],
deps = ["@rules_python//python/runfiles"],
visibility = ["//visibility:public"],
)
```

`binary.py`

```
from library import rlocation_wrapper

if __name__ == "__main__":
rlocation_wrapper()
```

`library/__init__.py`

```
from python.runfiles import Runfiles

def rlocation_wrapper() -> None:
runfiles_obj = Runfiles.Create()
print(runfiles_obj.Rlocation("library/__init__"))
```

In order to have `sys.path` find the package outside the runfiles directory, we can set the `PYTHONPATH` environment variable to the outer folder containing the package.
To reproduce the failure, run:
```
export PYTHONPATH=/home//
bazelisk run //:binary
```

## 🔥 Exception or Error

```
ValueError: /home///library/__init__.py does not lie under the runfiles root /home//.cache/bazel/_bazel_/0123456789abcdef0123456789abcdef/execroot/_main/bazel-out/k8-fastbuild/bin/binary.runfiles
```

Full traceback:
```
Traceback (most recent call last):
File "/home//.cache/bazel/_bazel_/0123456789abcdef0123456789abcdef/execroot/_main/bazel-out/k8-fastbuild/bin/binary.runfiles/_main/_binary_stage2_bootstrap.py", line 537, in
main()
~~~~^^
File "/home//.cache/bazel/_bazel_/0123456789abcdef0123456789abcdef/execroot/_main/bazel-out/k8-fastbuild/bin/binary.runfiles/_main/_binary_stage2_bootstrap.py", line 531, in main
_run_py_path(main_filename, args=sys.argv[1:])
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home//.cache/bazel/_bazel_/0123456789abcdef0123456789abcdef/execroot/_main/bazel-out/k8-fastbuild/bin/binary.runfiles/_main/_binary_stage2_bootstrap.py", line 319, in _run_py_path
runpy.run_path(main_filename, run_name="__main__")
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "", line 287, in run_path
File "", line 98, in _run_module_code
File "", line 88, in _run_code
File "/home//.cache/bazel/_bazel_/0123456789abcdef0123456789abcdef/execroot/_main/bazel-out/k8-fastbuild/bin/binary.runfiles/_main/binary.py", line 4, in
rlocation_wrapper()
~~~~~~~~~~~~~~~~~^^
File "/home///library/__init__.py", line 6, in rlocation_wrapper
print(runfiles_obj.Rlocation("library/__init__"))
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
File "/home//.cache/bazel/_bazel_/0123456789abcdef0123456789abcdef/execroot/_main/bazel-out/k8-fastbuild/bin/binary.runfiles/rules_python+/python/runfiles/runfiles.py", line 306, in Rlocation
source_repo = self.CurrentRepository(frame=2)
File "/home//.cache/bazel/_bazel_/0123456789abcdef0123456789abcdef/execroot/_main/bazel-out/k8-fastbuild/bin/binary.runfiles/rules_python+/python/runfiles/runfiles.py", line 404, in CurrentRepository
raise ValueError(
...<3 lines>...
)
ValueError: /home///library/__init__.py does not lie under the runfiles root /home//.cache/bazel/_bazel_/0123456789abcdef0123456789abcdef/execroot/_main/bazel-out/k8-fastbuild/bin/binary.runfiles
```

## 🌍 Your Environment

**Operating System:**

```
Ubuntu 24.04.4 LTS
```

**Output of `bazelisk version`:**

```
bazel 9.1.0
```

**Rules_python version:**

```
1.9.0
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.