Skip to main content

multistage-build

A generic PEP-517 build backend which allows additional processing to be applied to the resulting metadata, wheel and/or editable wheel.

Motivating Example

Sometimes it is desirable to run a post-processing step on a built wheel. For example, we may wish to inject some additional metadata into the wheel. To do this, we should write a function which accepts the wheel path as its only argument, for example:

def my_wheel_post_processing_func(wheel_path):
    print(f'The wheel to be processed is at {wheel_path}')

This function can then be declared as post-processing step of the PEP-517 build_wheel function:

[build-system]
requires = [
    'multistage-build',
    'setuptools',
]
build-backend = "multistage_build:backend"

[tool.multistage-build]
build-backend = "setuptools.build_meta"
post-build-wheel = [
    {hook-function="my_mod:my_wheel_post_processing_func", hook-path="."},
]

[project]
name = "some-project"
version = "0.1.0"
...

We could also publish this functionality to the package repository, and consume it by declaring it as a build requirement:

[build-system]
requires = [
    'multistage-build',
    'my_mod',
    'setuptools',
]
build-backend = "multistage_build:backend"

[tool.multistage-build]
build-backend = "setuptools.build_meta"
post-build-wheel = [
    "my_mod:my_wheel_post_processing_func",
]

[project]
name = "some-project"
version = "0.1.0"
...

Plugin based hooks

For tools wishing to expose a standard behaviour, without requiring the user to declare each of the hooks manually, it is possible to declare potential hooks as entrypoints.

An example of a project which automatically registers build-time hooks using entry points:

[project.entry-points.multistage_build]
post-prepare-metadata-for-build-wheel = "my_mod:prepare_metadata_for_build_wheel_fn"
post-build-sdist = "my_mod:build_editable_fn"
post-build-wheel = "my_mod:build_editable_fn"
post-build-editable = "my_mod:build_wheel_fn"

These hooks will get called for any user of the multistage_build backend, even if the project declaring these entrypoints doesn't itself use multistage-build. It allows one to build a library of hooks, and to have consumers add them by adding extra build dependencies (and declaring a multistage-build backend).

As is normal for entry-points, the name of the function is unimportant. It is possible to declare multiple entry-points per hook. A nice pattern would be to only run some behaviour if the hook is configured in the pyproject.toml (which is in the CWD when the hook is running); though this isn't obligatory (esp. when no configuration is needed - in that case, the existence of the project in the build environment is enough of a signal for the hook to be run).

Hook points

For each PEP-517 / PEP-660 hook that multistage-build wraps, there is a pre-* and a post-* extension point. Pre-hooks run before the wrapped backend is invoked; post-hooks run after it returns. Use pre-* when you need to mutate inputs (e.g. rewrite pyproject.toml) before the underlying backend reads them. Use post-* when you want to operate on the produced artefact.

Hook When it fires Arguments
pre-build-wheel Before build_wheel (wheel_directory, config_settings)
post-build-wheel After build_wheel (wheel_path,)
pre-build-editable Before build_editable (wheel_directory, config_settings)
post-build-editable After build_editable (wheel_path,)
pre-build-sdist Before build_sdist (sdist_directory, config_settings)
post-build-sdist After build_sdist (sdist_path,)
pre-prepare-metadata-for-build-wheel Before prepare_metadata_for_build_wheel (metadata_directory, config_settings)
post-prepare-metadata-for-build-wheel After prepare_metadata_for_build_wheel (dist_info_path,)
pre-prepare-metadata-for-build-editable Before prepare_metadata_for_build_editable (metadata_directory, config_settings)
post-prepare-metadata-for-build-editable After prepare_metadata_for_build_editable (dist_info_path,)

config_settings is the dict (or None) passed by the PEP-517 frontend. The *_directory arguments are the directories where the artefact will be written; they may not yet exist, and certainly do not yet contain the artefact.

Each hook can be declared either inline in pyproject.toml under [tool.multistage-build], or via the multistage_build entry-point group on an installed package. The pre-* hooks follow the same patterns as the post-* hooks documented above, under the matching name.

Status of work

The current functionality includes:

  • Pre- and post- hooks for build-wheel, build-editable, build-sdist, prepare-metadata-for-build-wheel, and prepare-metadata-for-build-editable.
  • Ability to have local definitions included, using the same mechanism as in-source builds from PEP-517.

There are a few known features not yet implemented:

  • Ability to override multiple hooks with a single declaration (e.g. editable and build hooks). Perhaps allow entrypoint definitions so that you get it simply by having the dependency installed?

Release files for multistage-build 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for multistage-build 0.3.0
File Size Uploaded
multistage_build-0.3.0.tar.gz 16.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for multistage-build 0.3.0
File Interpreter ABI Platform
multistage_build-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 26.9 kB

Release files / multistage_build-0.3.0.tar.gz

Download URL multistage_build-0.3.0.tar.gz
Size 16.9 kB
Tags Source
SHA-256 checksum
How to use checksums
b8bc026b644baad06ac150eeb36c04e14f2550b37e5f3ec265270300f0121480
BLAKE2b-256 checksum
How to use checksums
9549a134fdf0ac7122f70b70db33dbc94d5a74f70cbe500a929486355517dc25
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 18, 2026.

Transparency log

Release files / multistage_build-0.3.0-py3-none-any.whl

Download URL multistage_build-0.3.0-py3-none-any.whl
Size 10.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
72869476c568235383721e902022f993a8e0a448f6a9cfb12a0535b514402838
BLAKE2b-256 checksum
How to use checksums
7ada5129f77734f550ef7209b8f8eae13a3d4dc1812f7be85dca0e63d821db21
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 18, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page