Repository navigation
Expand file tree
/
Copy pathpython
More file actions
executable file
·102 lines (96 loc) · 3.44 KB
/
Copy pathpython
File metadata and controls
executable file
·102 lines (96 loc) · 3.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#!/usr/bin/env bash
set -euo pipefail
# PATH shim for python/python3 — intercepts the invocations `uv run` replaces and
# passes the rest through to the real interpreter. Works for both names via $0.
#
# Parameter expansion rather than basename/dirname on purpose: this shim has to work
# when PATH holds nothing but its own directory, which is exactly the case where it
# must report that no real interpreter was found. Shelling out to coreutils there
# fails first, with a confusing error about basename.
cmd="${0##*/}"
# What is intercepted, and what is not (#207):
#
# `python` and `python script.py` are what `uv run` exists to replace — they resolve a
# script against a project's dependencies, and running them bare gets the system
# interpreter with none of them.
#
# `-c`, `-m` and `-` are not that. They read a program from the command line, a module
# already on the path, or stdin, and none of them resolves a script's dependencies.
# `uv run python3 -` is also not a drop-in replacement inside a pipeline, so redirecting
# it there broke real scripts — zeroize-audit's smoke test among them.
#
# `-m pip` stays intercepted: that IS package management, and it is the foot-gun.
# Hand off to the real interpreter, skipping this shim's directory in PATH.
exec_real() {
local shim_dir path_entries dir resolved
shim_dir="$(cd "${0%/*}" && pwd)"
IFS=: read -ra path_entries <<<"${PATH:-}"
for dir in "${path_entries[@]}"; do
resolved="$(cd "$dir" 2>/dev/null && pwd)" || continue
[[ "$resolved" == "$shim_dir" ]] && continue
if [[ -x "$dir/$cmd" ]]; then
exec "$dir/$cmd" "$@"
fi
done
echo "ERROR: real $cmd binary not found on PATH" >&2
exit 127
}
# Canonical rationale for the suggestion's shape (the README,
# setup-shims.sh, and python-shim.bats point here):
#
# Suggestions always use the exact name `python`, never `python3`: uv
# special-cases the `python` command (uv >= 0.4.0) and executes its resolved
# interpreter directly instead of a PATH lookup, so the suggested command
# works even outside a project, where `uv run python3` would resolve back
# to this shim.
#
# Arguments are requoted with %q so the suggestion stays runnable when they
# contain spaces or shell metacharacters.
args=""
if (($#)); then
args="$(printf ' %q' "$@")"
fi
# Find the mode selector, stepping over any interpreter flags in front of it. Reading
# only $1 would make the decision depend on argument order: `python -u -c 'code'` means
# exactly what `python -c 'code'` means, and refusing one while allowing the other is an
# accident, not a rule. `-W`, `-X` and `--check-hash-based-pycs` take a separate value,
# so they consume two slots; everything else beginning with `-` consumes one.
mode=""
argv=("$@")
i=0
while ((i < ${#argv[@]})); do
case "${argv[i]}" in
-c | -m | -)
mode="${argv[i]}"
break
;;
-W | -X | --check-hash-based-pycs)
((i += 2))
;;
-*)
((i += 1))
;;
*)
# A script path. This is the case `uv run` exists to replace.
break
;;
esac
done
case "$mode" in
-m)
if [[ "${argv[i + 1]:-}" == "pip" ]]; then
echo "ERROR: \`$cmd -m pip\` is not supported. Use:" >&2
echo " uv add <package> # add a dependency" >&2
echo " uv remove <package> # remove a dependency" >&2
exit 1
fi
exec_real "$@"
;;
-c | -)
exec_real "$@"
;;
*)
echo "ERROR: Use \`uv run python$args\` instead of \`$cmd$args\`" >&2
exit 1
;;
esac