Files
trailofbits__skills/plugins/modern-python/hooks/shims/python-shim.bats
William Tan 3b316e6ac7 fix(modern-python): suggest exact uv run python so shim advice works outside projects (#196)
* fix(modern-python): suggest exact `uv run python` so the advice works outside projects

The python/python3 shim suggested `uv run $cmd ...`, echoing back whichever
name was invoked. For `python3` that advice is self-defeating on machines
with no uv-managed interpreters: uv resolves the `python3` command through
an ordinary PATH lookup, which hits the shim again and fails with the same
suggestion. uv special-cases the exact command name `python` (uv >= 0.4.0)
and executes its resolved interpreter directly, so always suggesting
`uv run python ...` works everywhere.

Reproduced on stock Debian + uv 0.11.27 (apt python3, zero managed
pythons, no project): `uv run python3 script.py` fails via the shim while
`uv run python script.py` succeeds, across script/-c/-m/REPL forms.

Reported in #195.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(modern-python): satisfy shellcheck SC2016 in new bats assertions

Escaped backticks in double quotes instead of literal backticks in
single quotes, which shellcheck flags as a possible unintended
non-expansion.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(modern-python): requote shim suggestions and carry all arguments through

Review findings on #196: the -m branch interpolated only the module name,
so `python -m http.server 8000` suggested a command missing the port, and
`${*}` flattened arguments without quoting, so `python -c 'print(1+1)'`
suggested a command that is a bash syntax error if run verbatim (plus a
trailing space inside the backticks for bare invocations). Both branches
now build the suggestion from %q-requoted arguments, with regression tests
for each case.

Also consolidates the exact-`python` rationale into a single canonical
copy in the shim's header comment; README, setup-shims.sh, and the bats
file now point there instead of paraphrasing it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 15:16:05 -04:00

92 lines
2.7 KiB
Bash

#!/usr/bin/env bats
# Tests for python/python3 PATH shim
SHIM="${BATS_TEST_DIRNAME}/python"
@test "exits non-zero for bare python" {
run "$SHIM"
[[ $status -ne 0 ]]
[[ "$output" == *"uv run python"* ]]
}
@test "exits non-zero for python script.py" {
run "$SHIM" script.py
[[ $status -ne 0 ]]
[[ "$output" == *"uv run python script.py"* ]]
}
@test "exits non-zero for python -c" {
run "$SHIM" -c 'print(1)'
[[ $status -ne 0 ]]
[[ "$output" == *"uv run python"* ]]
}
@test "exits non-zero for python -m pytest" {
run "$SHIM" -m pytest
[[ $status -ne 0 ]]
[[ "$output" == *"uv run python -m pytest"* ]]
}
@test "exits non-zero for python -m pip install" {
run "$SHIM" -m pip install requests
[[ $status -ne 0 ]]
[[ "$output" == *"uv add"* ]]
[[ "$output" == *"uv remove"* ]]
}
@test "suggests uv run python -m <module> for arbitrary modules" {
run "$SHIM" -m http.server
[[ $status -ne 0 ]]
[[ "$output" == *"uv run python -m http.server"* ]]
}
@test "works when invoked as python3 via symlink" {
run "${BATS_TEST_DIRNAME}/python3"
[[ $status -ne 0 ]]
[[ "$output" == *'instead of `python3'* ]]
}
# The suggestion must use the exact name `python`, never `python3`; see
# the header comment in ./python for the full rationale.
@test "suggests exact 'uv run python', not python3, when invoked as python3" {
run "${BATS_TEST_DIRNAME}/python3" script.py
[[ $status -ne 0 ]]
[[ "$output" == *"Use \`uv run python script.py\`"* ]]
[[ "$output" != *"uv run python3"* ]]
}
@test "suggests exact 'uv run python -m', not python3, for modules" {
run "${BATS_TEST_DIRNAME}/python3" -m http.server
[[ $status -ne 0 ]]
[[ "$output" == *"Use \`uv run python -m http.server\`"* ]]
[[ "$output" != *"uv run python3"* ]]
}
@test "-m suggestion preserves arguments after the module" {
run "${BATS_TEST_DIRNAME}/python3" -m http.server 8000
[[ $status -ne 0 ]]
[[ "$output" == *"Use \`uv run python -m http.server 8000\` instead of \`python3 -m http.server 8000\`"* ]]
}
# %q output can differ across bash versions, so build the expectation with
# the same requoting the shim uses, after checking it actually escapes.
@test "suggestion requotes -c code so it stays copy-paste runnable" {
run "$SHIM" -c 'print(1+1)'
[[ $status -ne 0 ]]
quoted="$(printf '%q' 'print(1+1)')"
[[ "$quoted" != 'print(1+1)' ]]
[[ "$output" == *"Use \`uv run python -c $quoted\`"* ]]
}
@test "bare invocation suggests uv run python without trailing space" {
run "$SHIM"
[[ $status -ne 0 ]]
[[ "$output" == *"Use \`uv run python\` instead of \`python\`"* ]]
}
@test "python3 -m pip suggests uv add" {
run "${BATS_TEST_DIRNAME}/python3" -m pip install foo
[[ $status -ne 0 ]]
[[ "$output" == *"uv add"* ]]
}