Dependency resolution

pyappdist pins dependencies from your project’s lockfile so the distribution matches the versions you tested. It exports the lock with your package manager — to a PEP 751 pylock.toml for uv, or a requirements.txt for the other managers — then turns those pins into wheels with the target runtime’s own python.exe.

Why the lockfile

Resolving from PyPI at build time could drift from what you developed and tested against. Exporting from the lockfile guarantees the shipped versions are exactly the locked ones.

Why the target interpreter

The exported requirements include environment markers and are turned into wheels by the target’s python.exe via pip wheel -r. Evaluating markers on the target keeps them natively correct — for example pandas’ tzdata; sys_platform == "win32" is included for a Windows target even when you build from Linux. Dependencies with only an sdist are built into wheels at this step, so the wheelhouse ends up containing wheels only and the later offline install never needs a compiler.

Manager detection

If [tool.pyappdist].manager is not set, pyappdist detects the manager by lockfile, in this order:

uv — lockfile uv.lock:

uv export --frozen --no-dev --no-emit-project --format pylock.toml

uv exports a PEP 751 pylock.toml instead of a requirements.txt; see Per-package indexes below for why.

poetry — lockfile poetry.lock:

poetry export -f requirements.txt --without dev

pipenv — lockfile Pipfile.lock:

pipenv requirements --hash

PDM — lockfile pdm.lock:

pdm export -f requirements --prod

All exports are production dependencies only (development dependencies are excluded, so pyappdist itself and other dev tooling are never bundled) and include hashes.

Per-package indexes (uv only)

A lock can pin individual packages to an alternative index. The typical case is a GPU (CUDA) build of PyTorch from the PyTorch wheel index, configured with [tool.uv.sources] and an explicit = true [[tool.uv.index]]:

[tool.uv.sources]
torch = [
    { index = "pytorch-cu130", marker = "sys_platform == 'win32' or sys_platform == 'linux'" },
]

[[tool.uv.index]]
name = "pytorch-cu130"
url = "https://download.pytorch.org/whl/cu130"
explicit = true

pip’s --index-url / --extra-index-url are global options, so a requirements.txt cannot express this kind of per-package routing. The PEP 751 pylock.toml that uv exports records each package’s exact artifact URLs and hashes instead, and pip fetches those URLs directly without consulting any index — the per-package pin survives into the build exactly as locked.

For GPU builds of PyTorch (or any project pinning packages to a dedicated index) we therefore recommend managing the project with uv, configured as described in the uv documentation: Using uv with PyTorch. The pytorchdemo sample (Samples) is a working configuration. With the other managers the exported requirements.txt flattens index configuration into global options, which cannot pin an index per package.

Note

pip’s pylock.toml support is recent (and marked experimental by pip), so the bundled runtime needs a reasonably new pip. pyappdist guarantees this itself: after extracting the runtime it upgrades the bundled pip in place whenever it is older than pip 26.1, so pylock support is present even when the python-build-standalone build ships an older pip.

Including optional-dependency extras

By default only the production (non-dev) dependencies are exported. To also bundle one or more [project.optional-dependencies] extras, list them per target with extras:

[[tool.pyappdist.targets]]
name = "win"
platform = "windows-x86_64"
format = "msi"
extras = ["gui", "pdf"]

Each name is passed through to the manager’s own extra selector, alongside the production dependencies. extras is ignored (with a warning) in requirements.txt mode, since that file is used verbatim.

Overriding the manager

Set [tool.pyappdist].manager explicitly to bypass detection:

[tool.pyappdist]
manager = "poetry"

requirements.txt mode

Set manager = "requirements.txt" to skip exporting and use a requirements.txt you maintain at the project root:

[tool.pyappdist]
manager = "requirements.txt"

Fallback behavior

If no lockfile is found and manager is unset, pyappdist prints a warning and falls back to requirements.txt mode. If that file is also absent, the build fails with an error.

The manager tool must be installed at build time. As a developer you already use it to manage the project, so this is normally already satisfied.