pbs-installer
Downloads and installs indygreg's standalone CPython and PyPy builds from a Python API or CLI.
Repository Health
Technical Analysis
pbs-installer is a small, focused installer for the python-build-standalone project’s prebuilt, portable CPython and PyPy binaries. Rather than compiling Python from source or relying on a system package manager, it resolves a requested version string (e.g. 3.10, 3.10.4, pypy@3.10) against a large generated table of known releases, finds the matching archive for the current (or an overridden) architecture and platform, downloads it with checksum verification, and unpacks it to a destination directory.
The project ships two ways to use it: as an importable library (install, download, get_download_link, install_file) for tools that need to provision Python interpreters programmatically, and as a pbs-install CLI for ad-hoc use via pipx run pbs-installer. The version table in _versions.py is regenerated automatically by a scheduled GitHub Action that scrapes the upstream python-build-standalone releases, so the package stays in sync with new Python builds without manual maintenance.
What You Get
- A
get_download_link()function that resolves a version request (major, major.minor, or full major.minor.micro, optionally with apypy@prefix ortfree-threaded suffix) to the matching release URL and checksum - A
download()helper that streams the archive to disk with SHA-256 checksum verification and warns if no checksum is available - An
install_file()/install()pair that unpacks.tar.zst,.tar.gz, or.ziparchives into a destination directory, stripping the top-level path component - A
pbs-installCLI (installable viapipx) with--arch,--platform,--version-dir,--build-dir, and--listflags for interactive or scripted use - An auto-updated
PYTHON_VERSIONStable refreshed on a schedule by a GitHub Action, so new upstream releases become installable without waiting on a manual package release
Common Use Cases
- Packaging tools (e.g. Python version managers or project tooling) that need to provision an isolated, self-contained Python interpreter without requiring the user to have a compiler or system Python installed
- CI pipelines that need to download a specific pinned Python version quickly, using
pipx run pbs-installerwithout a persistent install - Cross-platform build scripts that need one API to fetch the correct CPython/PyPy build for the current architecture and OS, including musl/glibc and free-threaded variants
- Sandboxed or ephemeral environments (containers, CI runners) where installing Python from a portable archive is faster and more reproducible than compiling from source
Under The Hood
Architecture
pbs-installer is organized as a small, flat module set under src/pbs_installer/: _utils.py holds platform/architecture detection and archive-extraction helpers, _install.py implements the core get_download_link -> download -> install_file pipeline used by both the library API and the CLI, and _versions.py is a large, machine-generated lookup table mapping PythonVersion tuples to per-(platform, arch, install-only) download URLs and checksums. __main__.py is a thin argparse wrapper around _install.install(). The design cleanly separates version resolution (pure data lookup) from I/O (network download, filesystem extraction), and defers imports of httpx and the extras-only extraction helpers until they’re actually needed, so the base package has minimal required dependencies. Nothing about the core abstraction (request a version, get a URL, download, unpack) would need to change if a new archive format or platform were added — that variability is isolated in _utils.py and the generated version table.
Tech Stack
The package targets Python 3.9+, uses pdm-backend with SCM-based versioning (no manually bumped version string; releases are tagged directly), and organizes optional functionality behind PEP 508 extras: httpx for the download extra and backports.zstd (needed on Python <3.14 to read .tar.zst archives) for the install extra. The CLI entry point is registered via project.scripts as pbs-install. Documentation is built with mkdocs + mkdocs-material + mkdocstrings and published to Read the Docs. mypy --strict and ruff (with import sorting) are configured as the type-checking and linting tools.
Code Quality
There are no test files anywhere in the repository beyond an empty tests/__init__.py — no unit or integration tests exist for the version-matching logic, the download/checksum path, or the archive-extraction helpers, despite mypy --strict being configured for static type coverage. Error handling is explicit but minimal: download() raises on checksum mismatch and HTTP errors via resp.raise_for_status(), _utils.PythonVersion.matches() raises ValueError on malformed version strings, and install_file()/download() raise clear RuntimeErrors when optional extras aren’t installed. Naming is consistent (leading-underscore private modules, verb-named public functions) and the codebase is fully type-annotated with from __future__ import annotations, but the complete absence of automated tests is a real gap for a package other tools depend on to provision interpreters.
API Design
The public surface is small and deliberately minimal — four functions (install, download, get_download_link, install_file) plus the PythonVersion NamedTuple — each documented with Google-style docstrings including runnable examples, and each accepting the same version-request string format across both the library and CLI. Extras (download, install, all) are clearly separated so consumers only pull in httpx or backports.zstd when they need download or extraction behavior, keeping the zero-dependency core usable for version-lookup-only consumers. The tradeoff is that calling install() requires understanding which extras are needed to avoid a RuntimeError at call time rather than an import-time failure.