Skip to content

fix(py_venv): preserve PBS base for nested venvs#1201

Open
tamird wants to merge 1 commit into
aspect-build:mainfrom
tamird:fix-pbs-venv-cwd-prefix-v1
Open

fix(py_venv): preserve PBS base for nested venvs#1201
tamird wants to merge 1 commit into
aspect-build:mainfrom
tamird:fix-pbs-venv-cwd-prefix-v1

Conversation

@tamird

@tamird tamird commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

CPython 3.11 and 3.12 interpret a relative pyvenv.cfg home from the process working directory. rules_py 2 writes a runfiles-relative value. When a py_binary runs as a Bazel action tool, that directory is the action sandbox, so prefix discovery can fall back to the PBS build-time /install prefix before Python can import encodings.

py_venv owns both the generated pyvenv.cfg and the relocatable bin/python link. For non-Windows in-build CPython 3.11 and 3.12 runtimes that declare supports_build_time_venv, write home with an empty value. getpath sees the key and resolves bin/python to the real PBS base executable, while the empty value does not force cwd-relative prefix discovery. That keeps outer startup relocatable and lets stdlib-created child venvs inherit PBS rather than the outer venv bin directory. System interpreters, unsupported runtimes, Windows, and other Python versions retain their current home.

The e2e matrix runs PBS 3.9 through 3.13 from an unrelated action cwd. It exercises the launcher, child interpreters with and without site initialization, the exposed venv, and a nested stdlib venv. The nested child starts from that unrelated cwd, imports encodings, and rejects /install as its base prefix. Two checked-in pyvenv.cfg snapshots make the generated metadata delta reviewable: 3.11 keeps an empty home line, while 3.13 retains a normalized nonempty home line.

Fixes issue 1048.

@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown

py_binary startup benchmark

Version Mean (ms) Median (ms) ± stddev vs BCR vs main Build (s)
BCR 1.11.5 (baseline) 170.767 170.726 ±0.645 80.55
HEAD main 55.499 54.909 ±1.990 -67.5% 9.87
This PR 55.733 54.968 ±2.830 -67.4% +0.4% 7.03

Measured with hyperfine --warmup 5 --runs 50 on Linux
Gate: PR vs HEAD main (threshold: 10%). BCR is shown only as a historical baseline.
Build time: cold bazel build //:bench with isolated output base, no disk cache.

sys.path quality

Version sys.path entries distinct site-packages roots duplicate realpaths
BCR 1.11.5 (baseline) 6 1 0
HEAD main 7 2 0
This PR 7 2 0

sys.path quality measured by bench_syspath inside the assembled venv. Duplicate realpaths indicate symlink redundancy; many distinct site-packages roots suggest an inefficient venv layout.

✅ No regression detected (PR is +0.4% vs HEAD main)

Comment thread e2e/cases/pbs-symlink-prefix-1048/test.sh Outdated
Comment thread e2e/cases/pbs-symlink-prefix-1048/action_probe.bzl Outdated
@tamird tamird force-pushed the fix-pbs-venv-cwd-prefix-v1 branch 2 times, most recently from c8db558 to 18266b8 Compare June 26, 2026 11:45
@tamird tamird marked this pull request as draft June 26, 2026 15:25
@tamird

tamird commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

I found a contract gap in my own review, so I moved this back to draft. Omitting home is enough for current CPython 3.11/3.12 startup, but it is outside the PEP 405 venv contract: the PEP defines home as the venv marker and says that without it sys.prefix == sys.base_prefix (PEP 405). A strict metadata consumer such as Ty rejects this shape, so the current test proves only the current CPython implementation, not the public py_venv contract. The latest test rewrite also removed test.sh, which was the explicit rules_python source-wheel producer check matching #1048. I am checking whether rules_py should define relocatable = true as an intentional extension and test it as such, or keep a parseable home through a different launcher/runtime design. Until that ownership boundary is explicit and the producer coverage is back, this should not merge.

@tamird

tamird commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Correction to my previous note: I overstated the test.sh point. The root CI already runs aspect test -- //..., which includes //:sdist_fallback_with_anyarch_wheel_build_test; deleting the nested script did not remove that producer coverage. The open issue is the metadata contract: no-home is a CPython-specific relocatable extension, while PEP 405 and strict consumers treat it as outside a standard venv.

@tamird

tamird commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Pushed edf92694 and rewrote the body around the explicit rules_py relocatable-metadata contract. I am keeping this draft until the refreshed matrix is green and the local Ty adapter is proven against the real targets.

@tamird tamird marked this pull request as ready for review June 26, 2026 15:55
@tamird

tamird commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Ready again: the refreshed upstream matrix is green, the contract review is clean, and the real Ty adapter targets pass with the strict parser kept outside this relocatable metadata path.

tamird commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

@xangcastle could you review this when you have a chance? It is the same py_venv ownership boundary as PR 1147, and the full matrix is green.

home = config_values.get("home")

def test_base_prefix_not_install():
assert sys.base_prefix != "/install", (

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did any of these assertions change or only move? The diff is unclear

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They changed. The old test called verify_all(), then repeated the /install and stdlib checks. The action-cwd probe keeps the #1048 checks and adds cwd/PWD, base_exec_prefix and executable existence, relocatable/home metadata, _ctypes, child -S/-BS, exposed venv, and 3.9-3.13 controls. It drops the incidental verify_all() symlink-walk and sys.path checks because this fixture now targets startup from an arbitrary action cwd rather than general venv layout.

@jbedard

jbedard commented Jun 26, 2026

Copy link
Copy Markdown
Member

Add a snapshot test that shows the diff of the generated code

@tamird

tamird commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Done.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0de7d43642

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread py/private/py_venv/venv.bzl Outdated
Comment on lines +732 to +733
if omit_venv_home:
pyvenv_home = None

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep home so 3.11/3.12 venvs activate

For non-Windows CPython 3.11/3.12 runfiles runtimes with supports_build_time_venv, this sets pyvenv_home to None, so the generated pyvenv.cfg has no home line. In CPython 3.11/3.12 the startup code only retains the detected venv prefix while processing a home key; without it, sys.prefix remains the base install, the venv site-packages/.pth files are not loaded, and any py_binary/py_venv relying on deps from the assembled venv will fail to import them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

False positive. The action probe on this head asserts sys.prefix != sys.base_prefix for 3.11 and 3.12. I also ran the exposed 3.11 venv directly: sys.prefix was the generated .action_probe_311.venv, sys.base_prefix was the PBS interpreter, and sys.path included the generated venv site-packages directory. The runtime test executes both the launcher and exposed venv from an unrelated action cwd; omitting home does not disable venv activation in current CPython.

# https://github.com/bazel-contrib/rules_python/blob/bac54949/python/private/py_runtime_info.bzl#L316-L337
omit_venv_home = (
py_toolchain.runfiles_interpreter and
not is_windows and

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the exception for windows?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Windows is excluded deliberately because this workaround relies on the POSIX relocatable bin/python symlink path, and this fixture has no Windows repro. I am leaving Windows unchanged until there is a failing Windows case rather than broadening the extension without evidence.

Comment thread py/private/py_venv/venv.bzl
@jbedard

jbedard commented Jun 26, 2026

Copy link
Copy Markdown
Member

Rebase

Comment thread py/private/interpreter/repository.bzl Outdated
Comment thread py/private/interpreter/repository.bzl Outdated
@tamird tamird force-pushed the fix-pbs-venv-cwd-prefix-v1 branch from 0de7d43 to 61a492b Compare June 26, 2026 20:19
@tamird

tamird commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Done.

@jbedard

jbedard commented Jun 26, 2026

Copy link
Copy Markdown
Member

squash, reduce unnecessary diffs

@tamird tamird force-pushed the fix-pbs-venv-cwd-prefix-v1 branch from 61a492b to 0217ea8 Compare June 26, 2026 20:36
@tamird

tamird commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Done.

@tamird tamird force-pushed the fix-pbs-venv-cwd-prefix-v1 branch from 0217ea8 to fdc79ea Compare June 26, 2026 21:24

tamird commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Correction: my earlier “Not required” reply was wrong. Exact downstream CI with the explicit line removed restored the /install encodings failure in four nested-venv tests. The gate reads the selected PyRuntimeInfo after toolchain plumbing, where the implicit default is not reliable. I restored the explicit producer-owned field in fdc79ea and updated the body.

@tamird tamird marked this pull request as draft June 26, 2026 21:28

tamird commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Second correction: the explicit field alone did not fix the exact downstream subset locally. The remaining failure is a nested stdlib venv whose home points at the outer relocatable venv bin directory, then falls back to /install. I moved this back to draft while I add that missing ownership case instead of asking you to review an incomplete fix.

@jbedard

jbedard commented Jun 26, 2026

Copy link
Copy Markdown
Member

Create an e2e test reproducing the same issue as downstream

@tamird tamird force-pushed the fix-pbs-venv-cwd-prefix-v1 branch from fdc79ea to 6c8a2a7 Compare June 26, 2026 21:56
@tamird tamird changed the title fix(py_venv): derive base prefix from symlink fix(py_venv): preserve PBS base for nested venvs Jun 26, 2026
@tamird tamird force-pushed the fix-pbs-venv-cwd-prefix-v1 branch from 6c8a2a7 to b990f23 Compare June 26, 2026 21:57

tamird commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Done. The action probe now creates a nested stdlib venv from the unrelated action cwd, starts its child interpreter, imports encodings, and rejects /install. Empty home fixes the three downstream nested-venv failures. The fourth downstream failure was our monorepo test's detached venv alias, not this metadata path; I narrowed that test back to its shell-trampoline contract. This reroll also removes the unproven implementation_name line. The exact four-test subset passes locally.

@tamird tamird marked this pull request as ready for review June 26, 2026 22:06

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b990f23915

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread py/private/py_venv/venv.bzl
@tamird tamird force-pushed the fix-pbs-venv-cwd-prefix-v1 branch from b990f23 to af6f022 Compare June 26, 2026 22:36
CPython 3.11 and 3.12 interpret a relative pyvenv.cfg home from the process working directory. rules_py 2 writes a runfiles-relative home, so an action tool can derive the PBS build-time /install prefix and fail before importing encodings.

For in-build CPython 3.11 and 3.12 runtimes that support build-time venvs, write an empty home key instead. getpath sees the key and resolves the relocatable bin/python symlink to the real PBS base executable, but the empty value does not force cwd-relative prefix discovery. This keeps outer startup relocatable and lets stdlib-created child venvs inherit PBS rather than the outer venv bin directory.

Keep system interpreters, Windows, unsupported runtimes, and other Python versions unchanged. Exercise PBS 3.9 through 3.13 from an unrelated action cwd, including child interpreters, the exposed venv, and a nested stdlib venv. Snapshot the empty 3.11 home beside the retained 3.13 home.

Fixes issue 1048.
@tamird tamird force-pushed the fix-pbs-venv-cwd-prefix-v1 branch from af6f022 to a156bec Compare June 26, 2026 22:42

tamird commented Jun 28, 2026

Copy link
Copy Markdown
Contributor Author

@jbedard Could you review the current exact remaining downstream set: #1201, #1205, #1206, and #1212? #1202 is merged. All four heads are green; #1205 is rerolled at 718f03a with the google/protobuf e2e, and #1212 is the separate dirname-free console-script fix exposed by the downstream manifest-only check.

tamird commented Jun 28, 2026

Copy link
Copy Markdown
Contributor Author

Update to the exact remaining downstream set: #1201, #1205, #1206, #1212, #1213, and #1214. #1202 is merged. #1213 is the downstream fasttext C++ runtime failure; #1214 is the OpenAPI binary-as-dep PyWheelsInfo loss. All six public heads are green.

py_runtime(
name = "system_py3_runtime",
interpreter_path = "/opt/fake-python/bin/python3",
# Braces make sure the generated home line is not formatted a second time.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this required?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the regression input for the brace-preservation fix in venv.bzl. interpreter_path is a host path string and may contain literal braces; before the change we formatted the home line once and then fed it through the outer pyvenv.cfg format, so {fake-python} was reinterpreted and either rewrote the path or failed analysis. Keeping braces here makes test_pyvenv_home fail on that bug; a plain path only covers the older home-directory behavior.

@jbedard

jbedard commented Jun 28, 2026

Copy link
Copy Markdown
Member

Review these changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants