Skip to content

fix(deps): exclude nltk 3.10.1, which breaks venvs living inside the working directory (v1) - #6607

Merged
wuliang229 merged 1 commit into
v1from
port-nltk-exclusion-v1
Aug 6, 2026
Merged

fix(deps): exclude nltk 3.10.1, which breaks venvs living inside the working directory (v1)#6607
wuliang229 merged 1 commit into
v1from
port-nltk-exclusion-v1

Conversation

@wuliang229

Copy link
Copy Markdown
Collaborator

Link to Issue or Description of Change

Ports 1a0c3bd from main to v1. Original PR on main: #6576. Upstream: nltk/nltk#3730, reverted by nltk/nltk#3732.

Applied by hand rather than cherry-picked — the extras lists have diverged between the branches (main has google-cloud-texttospeech, mcp, lxml in places v1 does not), so the cherry-pick would not apply cleanly. The same three extras reach nltk on v1.

Problem:

nltk 3.10.1 added an import-time security hook (nltk/inisec.py) that breaks any ADK code path reaching nltk, in two independent ways:

  1. It installs a meta-path finder that raises ImportError for any module whose file resolves under the CWD while an nltk frame is on the stack. The standard layout puts the virtualenv inside the project (.venv/), so every site-packages module nltk imports looks like a CWD hijack, and a plain import nltk dies on import regex.
  2. It calls os.environ.setdefault("PYTHONSAFEPATH", "1"), which leaks into every subprocess started afterwards. PYTHONSAFEPATH stops CPython from prepending the script/CWD entry to sys.path, and that prepend is what causes the eagerly created google namespace package (from google-cloud-aiplatform's legacy *-nspkg.pth) to recompute its __path__ and pick up src/google. Without it, import google.adk fails with ModuleNotFoundError in child interpreters. This fires even when the nltk import itself fails, because the hook installs before the failure — catching the ImportError does not undo it.

Solution:

Exclude the single bad release from the three extras that reach nltk:

Extra Path to nltk
eval rouge-score -> nltk
extensions llama-index-{embeddings-google-genai,readers-file} -> llama-index-core -> nltk
test both of the above

!= rather than an upper bound, so a fixed release is picked up automatically.

Note on current urgency

This is parity and defense-in-depth, not an active CI fix. nltk 3.10.2 shipped the upstream revert on 2026-08-05, after the original commit landed on main, so a fresh resolve already selects a good version:

$ python -c "import zipfile,io,json,urllib.request; ..."   # nltk-3.10.2-py3-none-any.whl
inisec present: False
PYTHONSAFEPATH in __init__: False

3.10.1 is not yanked, however, so it stays reachable via stale lockfiles, lowest-version resolution, and pinned or mirrored indexes. Landing this keeps v1 in parity with main at zero cost — the != form does not block 3.10.2.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

No test added — this mirrors the commit as it landed on main, which is pyproject.toml-only. (The guard test proposed in #6576 was dropped before that commit landed, and tests/unittests/test_release_dependencies.py does not exist on v1.)

Verification performed:

  • pyproject-fmt v2.5.0 — the rev pinned in this branch's .pre-commit-config.yaml — reports no change, so comment alignment is correct.
  • Resolver check on rouge-score>=0.1.2 with and without the constraint: both now resolve to nltk==3.10.2, confirming the exclusion does not pin the branch to an old nltk.
  • Diff is 3 added lines, no other changes; uv.lock deliberately untouched, matching the main commit.

…working directory (v1)

Ports 1a0c3bd from main to v1. Applied by
hand rather than cherry-picked, because the extras lists have diverged
between the branches; the same three extras reach nltk on v1.

nltk 3.10.1 added an import-time security hook (nltk/inisec.py) that breaks any
ADK code path reaching nltk, in two independent ways:

1. It installs a meta-path finder that raises ImportError for any module whose
   file resolves under the current working directory while an nltk frame is on
   the stack. The standard layout puts the virtualenv inside the project
   (.venv/), so every site-packages module nltk imports looks like a CWD hijack
   and a plain `import nltk` dies on `import regex`.

2. It calls os.environ.setdefault("PYTHONSAFEPATH", "1"), which leaks into every
   subprocess started afterwards. PYTHONSAFEPATH stops CPython from prepending
   the script/CWD entry to sys.path, and that prepend is what causes the eagerly
   created `google` namespace package (from google-cloud-aiplatform's legacy
   *-nspkg.pth) to recompute its __path__ and pick up src/google. Without it,
   `import google.adk` fails with ModuleNotFoundError in child interpreters.
   Note this happens even when the nltk import itself fails, because the hook
   installs before the failure, so catching the ImportError does not undo it.

Three extras reach nltk, and all three are constrained here:

  * eval       -> rouge-score -> nltk.
  * extensions -> llama-index-{embeddings-google-genai,readers-file} ->
                  llama-index-core -> nltk.
  * test       -> both of the above.

nltk removed the hook in 3.10.2, released after the original commit landed on
main, so a fresh resolve already picks up a good version. 3.10.1 is not yanked,
though, so it stays reachable via stale lockfiles, lowest-version resolution and
pinned or mirrored indexes. The `!=` form excludes only the bad release and
keeps v1 in parity with main.
@wuliang229
wuliang229 marked this pull request as ready for review August 6, 2026 01:03
@wuliang229
wuliang229 merged commit f25bb90 into v1 Aug 6, 2026
15 checks passed
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.

1 participant