bazel-contrib / bazel-contrib/rules_python
Runfiles `Rlocation()` call without `source_repo` param fails in custom python package
- 主要言語
- Starlark
- スター
- 688
- フォーク
- 721
- 平均マージ
- 15時間 7分
- マージ済み PR(30日)
- 76
説明
# 🐞 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
```
コントリビューションガイド
調査の方向性
まず、リンク先の行にある python/runfiles/runfiles.py、特に Rlocation() と CurrentRepository() から確認し、次に PYTHONPATH を runfiles ディレクトリの外部に設定して、提供されている最小再現を実行します。カスタムパッケージが source_repo なしで Rlocation() を呼び出せ、再現で示された ValueError が発生しなくなれば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- python
- 領域
- build-system
- issue の種類
- バグ
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 活発さ
- 静か
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 58/100