Firstly, mise tool stubs #
I’m enjoying using mise.
I’m especially enjoying using mise’s “tool stubs”.
Here’s how it works:
- Pick a directory to plop tool stubs, and tell
miseto prepend/append it to thePATH - Take the single-file binary you want to use (along with the version)
mise generate tool-stub <path> --platform-url <url1> --platform-url <url2> ...- Now that you have an executable on
PATHwith the name of the tool, you can just./tool-name
mise will handle the downloading, checksumming, and all that jazz for you.
Under the hood the file on disk is just a “lockfile” containing the URLs, checksums, etc… for the tool.
Example uv tool stub:
#!/usr/bin/env -S mise tool-stub
version = "0.11.1"
[platforms.macos-arm64]
url = "https://github.com/astral-sh/uv/releases/download/0.11.1/uv-aarch64-apple-darwin.tar.gz"
checksum = "blake3:3827382f68acaf640bf0749b80dfde35b62c81c7b70255e2221bcefe8a5d12bb"
size = 20474937 # 19.53 MiB
[platforms.linux-arm64]
url = "https://github.com/astral-sh/uv/releases/download/0.11.1/uv-aarch64-unknown-linux-gnu.tar.gz"
checksum = "blake3:10f74d9d7de56a88ef8e5dbda47a27b7a7a915429812ebdb99f82c4afe50f1d9"
size = 22320966 # 21.29 MiB
[platforms.linux-x64]
url = "https://github.com/astral-sh/uv/releases/download/0.11.1/uv-x86_64-unknown-linux-gnu.tar.gz"
checksum = "blake3:840cd02af39074f1bc3187f3a9802f27a1ed0c1a99e768de067a4ab35bca0be8"
size = 23844436 # 22.74 MiB
Centrally, uv tool stubs #
I wished I had the same thing for Python tools.
I tried at first to get it working using just really clever she-bangs.
(This led to me filing this really embarassing issue on the uv repo)
Alas, since you need some arguments after the filename, it can’t be done just in a she-bang
(someone remind me to turn this blog post into a uv feature request).
So the next best thing is a Bash script:
#!/usr/bin/env bash
# A uv-powered tool stub executor (similar to mise tool stubs)
# Usage:
#
# 1. Make a "stub" file: `uvx-stub generate <requirement> <location>`
# 2. That file is now runnable!
if [[ "$1" == "generate" ]]; then
requirement="$2"
location="$3"
echo "#!/usr/bin/env uvx-stub" > "$location"
chmod +x "$location"
echo "$requirement" | uv pip compile --no-annotate --custom-compile-command "$(basename "$0") $*" - >> "$location"
exit 0
fi
exec uv tool run --isolated --with-requirements "$1" "$(basename "$1")" -- "${@:2}"
Slap that sucker in an executable file called uvx-stub (somewhere on PATH), and now you’re cooking!
How it works: #
- The
generatecommand takes a requirement (likefoobar >= 2.3) and a location and makes an executable file at the location- (The “executable file” is a just a she-bang and a requirements file - why not
pylock.toml? More later)
- (The “executable file” is a just a she-bang and a requirements file - why not
- When you run the file, it uses
uvx-stubto “run” it uvx-stubjust uses a long and cleveruv tool runcommand, with “the file” as the requirements
In other words, it’s a uv-powered “tool stub”.
Example file (for black):
#!/usr/bin/env uvx-stub
# This file was autogenerated by uv via the following command:
# uvx-stub generate black .config/black
black==26.5.1
click==8.4.1
mypy-extensions==1.1.0
packaging==26.2
pathspec==1.1.1
platformdirs==4.10.0
pytokens==0.4.1
Nextly #
Two things:
uvreally ought to allow apylock.tomlwith--with-requirements(or similar). (#19117)- It’d be nice if this was just a subcommand of
uv/uvx(e.g.uvx-stub <location>).