Created
April 14, 2025 15:34
-
-
Save cfstras/5c94e39b057d383f61c73779f3e7e9e2 to your computer and use it in GitHub Desktop.
Revisions
-
cfstras renamed this gist
Apr 14, 2025 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
cfstras renamed this gist
Apr 14, 2025 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
cfstras revised this gist
Apr 14, 2025 . No changes.There are no files selected for viewing
-
cfstras revised this gist
Apr 14, 2025 . 2 changed files with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes.File renamed without changes. -
cfstras revised this gist
Apr 14, 2025 . 2 changed files with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes.File renamed without changes. -
cfstras created this gist
Apr 14, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,41 @@ # Universal Python UV Shebang You've probably seen the `#!/usr/bin/env -S uv run` pattern popularized by [Simon Willison](https://simonwillison.net/2024/Aug/21/usrbinenv-uv-run/). One issue I've had with it: When "upgrading" scripts to get their own pyproject.toml, I can't run them from a different directory anymore! E.g. this works: ```bash ./my_script.py ``` This doesn't: ```bash some_dir/my_script.sh ``` This special, but longer, shebang header allows us to do that. ## How? It works like this: 1. The first line is a shebang executing the file as a regular old POSIX script with /bin/sh. 1. A comment follows - this is ignored by sh (and also python) 1. Here comes the magic: We start a python block comment. - in Bash land, we just gave an empty string (`""`), followed by the start of a string (`"`). - to make bash happy, we finish off with `:"` - turning that "start of a string" into "please execute `:`" - which is an alias for "true"`, or a no-op command returning 0 1. Now, we just tell bash to run `uv`, but with `--project $(dirname $0)`, so that UV knows where to search for a pyproject file. 1. We use `exec` to replace the running `sh`, so that signals and return codes are followed 1. We use `set -eu` to error out if any errors occur before uv takes over - unset variables - `uv` not being installed, etc. ## Limitations Tested on - macOS - Debian (Bookworm) Probably doesn't work on Windows, unless you're using WSL or Git-Bash. This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,13 @@ #!/usr/bin/env sh # Special shebang: almost the same as just `uv run`, but always use the script directory to search for pyproject.toml. # The following lines are ignored by python, and executed by bash # Use `set -x` if you want to see what's happening """:" set -eu exec uv run --project=$(dirname "$0") "$0" "$@" """ ### if __name__ == "__main__": print("Hello, world!")