Skip to content

fix(hyperframes-media): resolve python3 -> python/py on Windows#1922

Draft
miguel-heygen wants to merge 1 commit into
mainfrom
fix/python3-win32-command-resolution
Draft

fix(hyperframes-media): resolve python3 -> python/py on Windows#1922
miguel-heygen wants to merge 1 commit into
mainfrom
fix/python3-win32-command-resolution

Conversation

@miguel-heygen

Copy link
Copy Markdown
Collaborator

Root cause

The audio engine shells out to python3 for ElevenLabs TTS (tts.mjs) and the local Lyria/MusicGen BGM paths (bgm.mjs). python3 is the right name on macOS/Linux, but a standard python.org install on Windows only creates python.exe plus the py launcher — there is no python3.exe (only the Microsoft Store build adds one). So every spawn("python3", …) / spawnSync("python3", …) ENOENTs on a normal Windows Python setup, silently disabling all Python-backed audio features (ElevenLabs voices, MusicGen/Lyria BGM generation).

Two reports of this: one user copied python.exe to python3.exe as a shim to work around it; another had to target a python3 stub specifically.

Fix

A shared lib/python.mjs resolver probes the platform's candidates in order and returns the argv prefix that actually launches Python 3 — resolved once per process:

  • win32: ["python3"]["python"]["py", "-3"] (the py launcher needs -3 to select Python 3, hence a prefix, not a bare name)
  • elsewhere: ["python3"]["python"]

All direct python3 spawn sites route through it:

  • tts.mjs: the ElevenLabs import probe (elevenlabsAvailable) and the ElevenLabs synth spawn.
  • bgm.mjs: the pyOk dependency probe, the Lyria recipe spawn, and the detached MusicGen script spawn.

On macOS/Linux python3 still wins first, so behavior there is unchanged. If nothing probes OK the resolver falls back to python3, so the eventual spawn fails loudly exactly as it did before this change — never worse.

Scope / not addressed here

  • Only the direct python3 invocations. bgm.mjs's pipInstall() still shells bare pip — switching that to <python> -m pip is the separate concern of the open draft PR fix(hyperframes-media): install MusicGen deps via python3 -m pip, not bare pip #1894; flagged here so the two don't collide.
  • The same feedback report also noted a Windows whisper.cpp-vs-openai-whisper flag-detection crash and an npm_execpath/npx spawn issue — distinct root causes, not touched here.

Test plan

  • New python.test.mjs (node:test) covers every platform/probe branch with an injected probe (no real interpreter spawned): non-win32 picks python3; win32 prefers python3, falls back to python, then to py -3; the launcher is probed as py -3 --version; nothing-runs falls back to the canonical python3; and pythonInvocation keeps the launcher's -3 ahead of caller args. — 7/7 passing.
  • Existing tts.spawn.test.mjs still passes (6/6, no regression).
  • node --check on all three modules; bunx oxlint / bunx oxfmt --check clean; full bun run build clean.

The audio engine shells out to `python3` for ElevenLabs TTS
(tts.mjs) and the local Lyria/MusicGen BGM paths (bgm.mjs). `python3`
is correct on macOS/Linux, but a standard python.org install on
Windows only creates `python.exe` plus the `py` launcher -- there is
no `python3.exe` (only the Microsoft Store build adds one). So every
`spawn("python3", ...)`/`spawnSync("python3", ...)` ENOENTs on a normal
Windows Python setup, silently disabling all Python-backed audio
features until the user hand-creates a `python3.exe` shim (reported: a
user copied python.exe to python3.exe to work around it, and separately
another had to target a python3 stub specifically).

Fix: a shared lib/python.mjs resolver probes the platform's candidates
in order and returns the argv prefix that actually launches Python 3 --
`["python3"]` / `["python"]` / `["py", "-3"]` on win32, `["python3"]`
then `["python"]` elsewhere -- resolved once per process. All direct
`python3` spawn sites in tts.mjs (elevenlabs probe + synth) and bgm.mjs
(pyOk probe, Lyria recipe, MusicGen script) now route through it. On
macOS/Linux `python3` still wins first, so behavior there is unchanged;
if nothing probes OK the resolver falls back to `python3` so the spawn
fails loudly exactly as before, never worse.

Scope: only the direct python3 invocations. bgm.mjs's pipInstall()
still shells `pip` -- switching that to `<python> -m pip` is the
separate concern of the open PR #1894 (draft); noting the overlap so
the two don't collide. Windows-specific whisper.cpp-vs-openai-whisper
detection and the npm_execpath/npx spawn issue from the same report are
distinct root causes, not addressed here.

Test: python.test.mjs (node:test) covers every platform/probe branch
with an injected probe -- no real interpreter spawned: non-win32 picks
python3; win32 prefers python3, falls back to python, then to `py -3`;
the py launcher is probed as `py -3 --version`; nothing-runs falls back
to the canonical python3; and pythonInvocation keeps the launcher's -3
ahead of caller args. Existing tts.spawn.test.mjs still passes (6/6).
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