fix(powershell): probe python3 before selecting it in Get-Python3Command - #4151
jawwad-ali wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The probe ignores nonzero exits, and the new .cmd-based tests fail on POSIX systems with PowerShell.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds runtime validation when selecting Python 3 for PowerShell scripts.
Changes:
- Centralizes interpreter probing across
python3,python, andpy -3. - Adds Store-alias fallback tests.
File summaries
| File | Description |
|---|---|
scripts/powershell/common.ps1 |
Adds and applies the Python probe. |
tests/test_resolve_template_python_parity.py |
Tests unusable interpreter fallbacks. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Nice work, and thanks for disclosing the AI assistance. Copilot's review flagged two things worth addressing before I merge: the probe should check the exit code (not just the |
|
Thanks for your contributions here, @jawwad-ali — a quick note on review prioritization. You currently have 6 open pull requests, above the three-open-PR guideline in CONTRIBUTING. This isn't a freeze — your open PRs stay in the queue and can still be reviewed and merged. But beyond three, additional submissions may be placed behind other contributors' work, so the most effective path is to consolidate where you can, or tell us the few you'd most like prioritized, and I'll focus on those first. I'm adding the (Drafted with AI assistance — GitHub Copilot.) |
|
Thanks @jawwad-ali— the probe now captures The POSIX shim change still has a problem: the driver replaces Please make the POSIX shims runnable under that restricted PATH—for example, use an absolute shell interpreter—while keeping real Python installations excluded from the test. Then verify the success and fallback cases on POSIX PowerShell and request re-review. Drafted for @mnriem by GitHub Copilot (model: GPT-6 Astra). |
`Get-Python3Command` returned `python3` on mere `Get-Command` presence, with no execution probe -- unlike its own `python` and `py -3` branches. On Windows `python3` almost always resolves to the Microsoft Store App Execution Alias stub, which `Get-Command` finds but which fails at runtime, so callers invoked a dead interpreter instead of falling through to a working one. The Bash twin (`_python3_command`) already probes all three candidates. The existing `python` / `py -3` probes had a second problem with the same root: `& python --version 2>&1` under the `$ErrorActionPreference = 'Stop'` that every caller sets raises a terminating NativeCommandError when the probed exe writes to stderr, rather than simply failing the match. `Test-Python3Command` now probes each fallback candidate without throwing, and requires a zero exit status as well as a "Python 3" banner -- the Bash twin gates purely on exit status, so a wrapper that echoes a version and then fails must not be selected. The `SPECKIT_PYTHON_EXECUTABLE` override block that main added above these branches is left unchanged. Tests shim fake interpreters onto PATH in both forms -- an executable script always, plus a `.cmd` on Windows -- because `HAS_POWERSHELL` is also true for `pwsh` on Linux and macOS. The scripts use an absolute `#!/bin/sh`: the driver replaces PATH with the shim directory alone, so `#!/usr/bin/env sh` cannot find `sh` and every shim exits 127, which is why these tests failed on macOS CI while passing on Windows. The driver also strips the SPECKIT_PYTHON override variables, which would otherwise bypass the shims entirely. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
843f825 to
5554b20
Compare
|
@mnriem — fixed, and rebased onto current The test failure was real, and it was mine. The three Root cause: the test driver replaces Shims now use an absolute Rebase: Gates on the rebased branch: 4 selection tests fail with |
The probe driver embeds `shim_dir` and the `common.ps1` path into single-quoted PowerShell literals and was written as ASCII, so: - a non-ASCII path (username, temp dir or checkout containing e.g. `é`) raised UnicodeEncodeError before PowerShell started, and - a path containing `'` (e.g. a `C:\Users\O'Brien` profile) terminated the literal early and failed with a PowerShell parse error. Double `'` the way the sibling parity tests already do, and write the driver as UTF-8 with a BOM so Windows PowerShell 5.1 does not read it in the ANSI code page. Reproduced both with `--basetemp` under such paths: 4 failed before, 4 passed after (also with both characters in one path). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Problem
Get-Python3Command's first branch returns@('python3')on mereGet-Commandpresence, with no execution probe — while its own second and third branches do probe:Its own docstring promises "a usable Python 3 executable".
On Windows,
python3almost always resolves to the Microsoft Store App Execution Alias stub, whichGet-Commandfinds but which fails at runtime:Note the existing probe already rejects it correctly — the first branch just never runs one.
Precedent in this repo
scripts/bash/common.shdocuments this exact hazard by name and defends against it:Its
_python3_commandprobes all three candidates. The PowerShell twin probes only the last two.Second half of the same root cause
The existing probes use
& python --version 2>&1. In Windows PowerShell, redirecting a native command's stderr into the success stream wraps each line in anErrorRecord— so under the$ErrorActionPreference = 'Stop'that every caller sets, the probe raises a terminatingNativeCommandErrorrather than simply failing the match. Reaching branch 2 therefore crashes outright whenpythonis also a Store alias (the Windows 11 default). One function, one fix.Reproduction — shimmed interpreters on PATH, against
upstream/mainCallers (
Resolve-TemplateContent→setup-plan.ps1,create-new-feature.ps1) then invoke the dead stub, whose stderr becomes a terminating error under'Stop', aborting the script instead of falling through to a working interpreter.With the fix:
Fix
Extract the probe into
Test-Python3Commandand apply it to all three branches. The probe saves and restores$ErrorActionPreferencearound the invocation so a candidate writing to stderr fails the match instead of throwing.Match semantics are unchanged — still
-match 'Python 3', exactly as branches 2 and 3 already did.Verification
common.ps1reverted toupstream/main→ 3 passed with the fix.PATH, so they do not depend on the runner actually having a Store alias. Gated onHAS_POWERSHELL.test_setup_tasks_ps_core_template_resolved— which is pre-existing on cleanmain, fails identically with and without this change, and has an unrelated cause (JSONDecodeError: Invalid control characterin emitted stdout). I am not claiming to fix it.common.ps1remains ASCII-only (verified byte-wise: 0 non-ASCII bytes), per this repo's.ps1encoding rule andtests/test_ps1_encoding.py, which passes.uvx ruff@0.15.0 check src tests→ cleanNo breaking change. A genuinely working
python3still passes the probe and is still selected first; only candidates that cannot actually run are now skipped — which is what the function already promised.Written with assistance from Claude Code. Bug found, reproduced, and verified by me on current
main.