A CLI wrapper that auto-installs PEP 723 inline script dependencies before executing linters and other tools.
Python scripts with PEP 723 inline metadata declare their dependencies directly in the file:
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "requests>=2.31.0",
# "rich>=13.0.0",
# ]
# ///
import requests
from rich import print
# ...But when you run type checkers or linters on these scripts, they fail because the dependencies aren't installed:
$ mypy script.py
script.py:8: error: Cannot find implementation or library stub for module named "requests"
script.py:9: error: Cannot find implementation or library stub for module named "rich"pep723-loader wraps your linter and automatically installs the inline dependencies first:
$ pep723-loader mypy script.py
# Dependencies installed, then mypy runs successfullypip install pep723-loaderOr with uv:
uv tool install pep723-loader# Wrap any linter or tool
pep723-loader mypy script.py
pep723-loader basedpyright script.py
pep723-loader ruff check script.py
pep723-loader bandit script.py
# Pass any arguments through to the wrapped command
pep723-loader mypy --strict --warn-unreachable script.py
# Works with directories too
pep723-loader mypy scripts/There are two ways to use pep723-loader with pre-commit:
First, add the tools to your project's dev dependencies:
uv add --dev pep723-loader mypyThen configure the hook:
- repo: local
hooks:
- id: mypy
name: mypy
entry: pep723-loader mypy
language: system
types: [python]
pass_filenames: trueThis approach keeps tools out of your project's dependencies - uv provides them on-demand:
- repo: local
hooks:
- id: mypy
name: mypy
entry: uv run -q --no-sync --with pep723-loader --with mypy pep723-loader mypy
language: system
types: [python]
pass_filenames: true
- id: basedpyright
name: basedpyright
entry: uv run -q --no-sync --with pep723-loader --with basedpyright pep723-loader basedpyright
language: system
types: [python]
pass_filenames: trueWhat do these flags do?
| Flag | Purpose |
|---|---|
-q |
Quiet mode - suppresses uv's output so only linter output is shown |
--no-sync |
Skip syncing the project's dependencies - faster, we only need the tools |
--with <pkg> |
Temporarily add a package for this invocation |
The --with packages are ephemeral - they're not installed into your project's virtualenv. However, they're cached by uv, so after the first run there's no download overhead.
- Scans Python files passed as arguments for PEP 723
# /// scriptmetadata blocks - Extracts dependencies using
uv export --script - Installs dependencies via
uv pip install - Executes the wrapped command with all original arguments
- Propagates the wrapped command's exit code
- Python 3.10+
- uv (used for dependency extraction and installation)
- pep723-uv-interpreter - VS Code extension that automatically sets the Python interpreter for PEP 723 scripts, enabling auto-completion and intellisense in your editor.
These tools are complementary: pep723-uv-interpreter solves the IDE experience, while pep723-loader solves CI/pre-commit linting.
Apache License 2.0