Self-contained Python scripts with uv
21 points by Brekkjern
21 points by Brekkjern
Depending on your audience, doing the same thing with pipx might be better. It supports the same pattern (although their docs don't explain the shebang). However, there are two main differences:
pipx will not download Python versions like uv does, so you need to be careful with Python version compatibility and what your users run.pipx is more widely packaged right now, so instead of telling your users to download the uv binary, depending on which platforms they are on, they could install a package.(I expect uv to be widely packaged soon, though.)
It's also worth noting that other languages have similar features.
Finally, does anyone have experiences in bundling Python interpreters in huge self-executable scripts? I had great hopes in PyOxidizer, which has a common lineage with uv in the Python binary packages they use, but last time I looked at it, it was a pain to set up.
pipx also completely breaks if you change Python versions, so there's that.
I have some stuff installed with pipx and the shebang ends up symlinking to /usr/bin/python3. So yes, that's Python 3.11 on this machine, so if my distro updates to 3.12, I would expect things to fail. But I would expect pipx reinstall-all would be sufficient in most cases.
uv likely can be better in many situations because it can manage Python versions, yes.
I'm looking forward to uv being distributed as widely as pipx is. For me, being able to apt install pipx is a nice advantage, but I'm moving many of my personal stuff to uv.
This has been tremendously useful for me.
There are some usability issues around switching from a script to the full runtime, but those are solved by deciding if you are writing a script or part of the whole program. And making sure, if it's a script, to get all the dependencies you need listed there.
uv is now my favorite tooling for Python.
This works because the -S flag tells the system to split everything after it into separate arguments before passing it to the system's env.
Where can I find documentation for this?
There are weird limitations and portability gotchas with #! lines. Basically all you can rely on is one argument after the command name. If you put more than one, they might be treated as a single argument with internal spaces, or might be split on spaces into multiple arguments. Don’t expect quoting or anything fancy to work as you might expect in a shell command line.
Some versions of the env utility have a -S option which re-splits an argument that (presumably) came from a #! line, so that it can be used as a command with arguments. The article’s explanation is muddled: it is env doing the splitting, not “the system”, and not before passing to env.
For much more about #! see https://www.in-ulm.de/~mascheck/various/shebang/
I really like the idea that I could write a one-off python script but also not have to add that specific script's dependencies to the rest of the project. I think this is really cool!
You can always use optional dependencies/dependency groups.
It can be practical to ensure that all dependencies are more or less coordinated.