Skip to content

fix(shim): discover install-time shims from disk, not static provider#270

Merged
CalvinAllen merged 1 commit into
mainfrom
fix/python/install-shim-discovery
May 14, 2026
Merged

fix(shim): discover install-time shims from disk, not static provider#270
CalvinAllen merged 1 commit into
mainfrom
fix/python/install-shim-discovery

Conversation

@CalvinAllen
Copy link
Copy Markdown
Contributor

Summary

  • Install previously copied shim files and shim-map cache entries from the provider's static Shims() declaration regardless of whether the matching executables existed on disk. On Windows that produced phantom python3 and pip shims for python-build-standalone — which ships only python.exe / pythonw.exe in the root and an empty Scripts/.empty placeholder — leaving users with shims that errored at invocation time with "secondary executable not found: pip" even though install reported success.
  • reshim already handled this correctly by registering only executables it discovered on disk, so install and reshim disagreed about which shims existed. After a fresh install of Python 3.14.2 on Windows, running dtvem reshim would drop the phantom entries and dtvem doctor would flag the cache as out of sync.
  • Factor the per-version disk scan out of RehashWithCallback into a new exported helper, shim.DiscoverShimsForVersion. Route node, python, and ruby provider createShims() through it so install registers exactly the executables that exist in bin/, root/, and Scripts/. After this change the post-install state matches the post-reshim state by construction.
  • pythonw is now picked up on Windows; pip / pip3 / pip3.X appear when ensurepip succeeds and are silently omitted when it fails (no more shims promising commands that don't exist).
  • No new error paths: if the install dir contains no executables createShims returns an explicit error, surfacing what would previously have been a silent "install succeeded but nothing was shimmed" outcome.

Resolves #269

What didn't change

  • Provider.Shims() is still used by mapShimToRuntime as a fallback when the cache lookup misses (e.g., first invocation of pip before the cache is populated). The static list remains useful as a declaration of expected shims for prefix-matching; it's just no longer the source of truth at install time.
  • The user-visible install spinner sequence is unchanged. installPipIfNeeded still runs python -m ensurepip --default-pip --upgrade and reports "pip configured successfully" / "Failed to configure pip" the same way. The only difference is that on failure, no broken pip / pip3 shims are left behind.

Test plan

  • ./rnr check — gofmt clean, golangci-lint reports 0 issues, full test suite passes on Windows
  • 6 new unit tests in internal/shim/manager_test.go:
    • empty dir → empty result
    • missing dir → empty result (no panic / no error)
    • Unix bin/ contents discovered
    • Windows python-build-standalone layout before ensurepip → [python, pythonw] only; .empty placeholder ignored
    • Windows python-build-standalone layout after ensurepip → [pip, pip3, pip3.14, python, pythonw]
    • duplicate names across root/ and Scripts/ deduped
  • CI passes on Windows / macOS / Linux

… list

Install previously created shim files and shim-map cache entries from the
provider's static Shims() declaration, regardless of whether those
executables actually existed on disk for the version being installed. On
Windows that created phantom python3 and pip shims for python-build-
standalone — which ships only python.exe / pythonw.exe in the root and
an empty Scripts/ placeholder — leaving users with shims that errored at
invocation time with "secondary executable not found." Reshim's scan
already handled this correctly by registering only executables it found
on disk, so install and reshim disagreed about which shims existed.

This change factors the per-version disk scan out of RehashWithCallback
into DiscoverShimsForVersion and routes the node, python, and ruby
provider createShims() through it. Install now registers exactly the
executables that exist in bin/, root/, and Scripts/ — picking up
pythonw on Windows, pip / pip3 / pip3.X after ensurepip succeeds, and
nothing extra when it fails.
@CalvinAllen CalvinAllen changed the title fix(shim): discover install-time shims from disk, not static provider list fix(shim): discover install-time shims from disk, not static provider May 14, 2026
@CalvinAllen CalvinAllen merged commit 9add90e into main May 14, 2026
11 of 12 checks passed
@CalvinAllen CalvinAllen deleted the fix/python/install-shim-discovery branch May 14, 2026 14:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Pip, pip3, & python3 shims not creating

1 participant