Paul's Programming Notes     Archive     Feed     Github

Python - Inline Script Dependencies With PEP 723

Distributing one-off Python scripts has gotten a lot better recently. PEP 723 added a standard way to declare dependencies and a minimum Python version inside a single .py file, and uv makes running them painless. I used this to share a script with the team and it just worked across everyone’s machines.

Before this, you’d end up writing some wrapper shell script that creates a virtualenv, makes sure the right Python version is being used, installs the dependencies, and tries to keep everything in sync. Brew-installed Python was especially bad for this because brew upgrade can silently swap your Python version and break every virtualenv pointing at it. Even version managers like asdf or pyenv don’t really help because the recipient still needs the right version installed through their manager. A lot of ceremony for a single file.

PEP 723 lets you declare all of that inline:

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

import requests

resp = requests.get("https://example.com/api/health", timeout=10)
print(resp.json())

The # /// script block is TOML. You don’t have to write it by hand either, uv add --script example.py 'requests' will add it for you.

The recipient just needs uv installed:

uv run check_status.py

uv reads the inline metadata and installs the dependencies in an isolated environment. If the required Python version isn’t on their machine, uv downloads it automatically. No virtualenv, no version manager, no wrapper script.

You can also lock dependencies with uv lock --script example.py for reproducible runs. For bigger tools that span multiple files, uv tool install is the next step up and can install from a private PyPI index.