# uv - Python Package Manager ## Determining Which Python Interpreter is Used ### Quick checks **Find which Python uv will use:** ```bash uv python find ``` Prints the exact interpreter path `uv` would use (considering `.python-version`, `.venv`, etc.). **See what uv run actually used:** ```bash uv run python -c "import sys; print(sys.executable); print(sys.prefix)" ``` - `sys.executable` → Python binary being used - `sys.prefix` → venv location **Force a specific interpreter:** ```bash uv run --no-project -p /path/to/python python --version ``` `-p/--python` lets you specify an interpreter; `--no-project` ignores project constraints. ### How uv selects Python uv discovers interpreters in this order: 1. Directly provided path (`-p/--python`) 2. Spawning interpreter (when using `python -m uv`) 3. Activated venv (`VIRTUAL_ENV`) 4. Venv in current directory (`./.venv`) 5. Interpreter on `PATH` ### Environment variables - `VIRTUAL_ENV` → if set, uv will use that environment - `uv pip install --python /path/to/python` → target specific environment - `uv pip install --system` → use system Python - In projects, uv automatically finds and uses `./.venv` ## Running with Ad-hoc Dependencies (`--with`) `--with` injects packages into the run environment without adding them to a project. **Single dependency:** ```bash uv run --with rich example.py ``` **Version constraints:** ```bash uv run --with 'rich>12,<13' example.py ``` **Multiple dependencies (repeat the flag):** ```bash uv run --with requests --with rich example.py ``` Inside a project, `--with` packages supplement the project's existing dependencies. Use `--no-project` to skip project deps entirely: ```bash uv run --no-project --with requests script.py ``` ### Quick one-liners with `python -c` Combine `--with` and `python -c` for throwaway snippets that need a package: ```bash uv run --with httpx python -c "import httpx; print(httpx.get('https://example.com').status_code)" ``` ```bash uv run --with rich python -c "from rich import print; print('[bold green]hello[/bold green]')" ``` Multiple deps work too: ```bash uv run --with requests --with beautifulsoup4 python -c " import requests, bs4 html = requests.get('https://example.com').text print(bs4.BeautifulSoup(html, 'html.parser').title.string) " ``` ### With tools (`uvx` / `uv tool run`) Same flag works for CLI tools — handy for plugins: ```bash uvx --with mkdocs-material mkdocs serve ``` Permanent tool install with extras: ```bash uv tool install mkdocs --with mkdocs-material ``` ## Keeping Tools Up to Date ```bash uv tool list # see installed tools and versions uv tool upgrade --all # upgrade all tools installed via uv tool install uv tool upgrade ty # upgrade a specific tool ``` ## Inline Script Dependencies (`--script` / PEP 723) Single-file scripts can declare their own dependencies via PEP 723 metadata, so anyone can run them with just `uv run`. ### Creating a script with metadata ```bash uv init --script example.py --python 3.12 ``` ### Adding dependencies to a script ```bash uv add --script example.py 'requests<3' 'rich' ``` This produces an inline metadata block at the top of the file: ```python # /// script # requires-python = ">=3.12" # dependencies = [ # "requests<3", # "rich", # ] # /// import requests from rich import print ... ``` ### Running it ```bash uv run example.py ``` uv reads the metadata, installs the deps into an ephemeral environment, and runs the script. No virtualenv setup needed. ### Making scripts directly executable Add a shebang so the script can run standalone: ```python #!/usr/bin/env -S uv run --script # /// script # dependencies = ["requests"] # /// import requests ... ``` Then: ```bash chmod +x example.py ./example.py ``` ### Locking a script ```bash uv lock --script example.py ``` Creates `example.py.lock` alongside the script, pinning exact versions (with hashes) of all dependencies and their transitive deps. Each script gets its own independent lockfile, so multiple scripts in the same folder lock separately: ```text my-folder/ ├── example.py ├── example.py.lock # pins requests + deps ├── other.py └── other.py.lock # pins rich + deps ``` When `uv run example.py` finds a lockfile, it uses those pinned versions. If the lockfile is missing or the inline metadata has changed, uv resolves fresh. > **Note:** When inline metadata is present, project dependencies are ignored — `--no-project` is not needed.