|
|
|
|
|
by networked
448 days ago
|
|
My general solution to project management problems with PEP 723 scripts is to develop the script as a regular Python application that has `pyproject.toml`.
It lets you use all of your normal tooling.
While I don't use an LSP-based editor, it makes things easy with Ruff and Pyright.
I run my standard Poe the Poet (https://poethepoet.natn.io/) tasks for formatting, linting, and type checking as in any other project. One drawback of this workflow is that by default, you duplicate the dependencies: you have them both in the PEP 723 script itself and `pyproject.toml`.
I just switched a small server application from shiv (https://github.com/linkedin/shiv) to inline script metadata after a binary dependency broke the zipapp.
I experimented with having `pyproject.toml` as the single source of truth for metadata in this project.
I wrote the following code to embed the metadata in the script before it was deployed on the server.
In a project that didn't already have a build and deploy step, you'd probably want to modify the PEP 723 script in place. #! /usr/bin/env python3
# License: https://dbohdan.mit-license.org/@2025/license.txt
import re
import tomllib
from pathlib import Path
from string import Template
import tomli_w
DEPENDENCIES = "dependencies"
PROJECT = "project"
REQUIRES_PYTHON = "requires-python"
DST = Path("bundle.py")
PYPROJECT = Path("pyproject.toml")
SRC = Path("main.py")
BUNDLE = Template(
"""
#! /usr/bin/env -S uv run --quiet --script
# /// script
$toml
# ///
$code
""".strip()
)
def main() -> None:
with PYPROJECT.open("rb") as f:
pyproject = tomllib.load(f)
toml = tomli_w.dumps(
{
DEPENDENCIES: pyproject[PROJECT][DEPENDENCIES],
REQUIRES_PYTHON: pyproject[PROJECT][REQUIRES_PYTHON],
},
indent=2,
)
code = SRC.read_text()
code = re.sub(r"^#![^\n]+\n", "", code)
bundle = BUNDLE.substitute(
toml="\n".join(f"# {line}" for line in toml.splitlines()),
code=code,
)
DST.write_text(bundle)
if __name__ == "__main__":
main()
|
|