Skip to content

Dependency Contract

The six root requirements inputs and the two packaged Xpra inputs own every exact direct Python dependency. Each is paired with a same-stem requirements*.txt lock generated by pip-compile with hashes; locks must never be edited manually. Every tool input includes requirements.in exactly once, so all runtime-derived environments resolve the same published runtime pin.

Audience Direct input Generated lock Purpose
runtime requirements.in requirements.txt published ssh-wrapper runtime
quality requirements-quality.in requirements-quality.txt Ruff, mypy, Bandit, audit, licenses
test requirements-test.in requirements-test.txt pytest and coverage
package requirements-package.in requirements-package.txt wheel/sdist construction
standalone requirements-standalone.in requirements-standalone.txt native PyInstaller build
docs requirements-docs.in requirements-docs.txt strict MkDocs rendering
Xpra client requirements-xpra.in requirements-xpra.txt isolated matching PyOpenGL additions
Xpra builder requirements-xpra-build.in requirements-xpra-build.txt temporary accelerator source-build tools

pyproject.toml declares runtime dependencies as dynamic setuptools metadata read from requirements.in. It contains no second copy of those versions and no internal quality, test, package, standalone, or documentation extras. Its build-system setuptools range expresses a backend capability; the exact setuptools used by project commands is pinned in requirements-package.in.

ssh-wrapper is the sole runtime dependency; its version is maintained only in requirements.in. The standard-library helper tools/runtime_dependency.py reads the current input for all six Make environments, clean-install and standalone smoke, and live dependency identity checks. Make verifies it both before reusing an environment and after installing one, so a stale lock cannot produce a successful preparation with a different runtime version. The lock validator compares the generated graphs against the same input. Tests change a fixture input to prove that a new pin needs no copied version constants or documentation edits. Every audience that needs it resolves the reviewed PyPI wheel through generated hashes. This repository does not vendor it, build it from another checkout, or add an import path to an uninstalled source tree.

The Xpra input is independent of the Elsewindow runtime. Its PyOpenGL pair must stay on the same upstream version and is packaged with wheel, sdist and native executables. make runtime-venv prepares this separate environment as well; --prepare-xpra provides the installed and standalone setup route. Dependabot includes both the repository root and elsewindow/ manifest directories. The separate build lock supplies Cython, NumPy headers, and setuptools during preparation only; these packages are removed from the prepared Xpra venv. When an accelerator wheel is unavailable, notably on Linux arm64, its verified source archive is built without unpinned build-isolation downloads. The host must provide a C compiler and system Python headers for that route.

Run make lock only after an intentional direct dependency change in a requirements*.in file and make refresh-dependencies for a reviewed whole-graph upgrade. Both use the online resolver container. Never edit a lock manually. Environment targets install with --require-hashes, binary-only policy, and pip check. The sole source-build exception is the Xpra accelerator under the separate locked builder.

make freeze-check is an explicit online gate that recompiles every audience against its current constraints. make lock-validate checks exact ownership, pins, hashes, and wrapper provenance. make dependency-snapshot produces all eight GitHub dependency manifests deterministically.

Dependabot treats every .in file as a native pip-compile manifest, updates its matching .txt lock, and groups all ordinary Python changes into one pull request. pyproject.toml is excluded from its pip manifests so a plain requirements updater cannot take ownership of generated locks. The coordinated ssh-wrapper runtime contract remains excluded from automatic version changes. Both local resolver stages pin the pip==26.1.1 and pip-tools==7.5.3 pair used by Dependabot when this contract was established; a future resolver migration must update both stages together and reproduce all eight locks. GitHub Actions updates remain grouped into one other pull request, so one scheduled run opens at most one update per ecosystem.

make audit checks every lock and accepts only exact findings in dependency-audit-exceptions.json; an unused exception fails as stale. make licenses inventories the complete standalone build environment, a conservative superset of bundled Python packages; make outdated is an explicit online review aid. Maintainer locks are not a public installation interface: users install the published distribution normally.