PEP 723 and ditching .sh for .py

Because PEP 723 introduces inline metadata in Python scripts, I can now write portable python scripts that can be run with a single command. I write this at the head of every script I write:

#!/usr/bin/env -S uv run

# /// script
# requires-python = ">=3.12"
# dependencies = [
#   "requests",
# ]
# ///

Why? To avoid python -m venv venv, source venv/bin/activate, pip install -r requirements.txt, python script.py. With this, I run script.py.

How

Shebang: #!/usr/bin/env -S uv run

Because of the leading #!/usr/bin/env -S uv run (known as a shebang), your shell will interpret the leading shebang as a command to run the script with uv. Instead of uv run script.py, it will run script.py.

Shebang

  • #!: Shebang marker. Tells the system to interpret the following text as a command.
  • /usr/bin/env: Use the system's environment to find the uv command.
  • -S: Split the what follows into parts based on whitespace.
  • uv: Find this.
  • run: Pass it this subcommand.

PEP 723 Metadata

After that, a PEP 723 comment block specifies whatever I want. uv interprets the comment block as toml, installs your dependencies (out of sight), then runs the script. That's it.