How python -m build Isolates Environments
The standard Python build tool
(python -m build) ensures reproducible and clean package
generation by compiling distributions inside a temporary, isolated
virtual environment. By adhering to modern packaging standards defined
in PEP 517 and PEP 518, build creates a dedicated workspace
containing only explicitly declared build dependencies, preventing
packages installed in the global or local environment from interfering
with the build process.
The Problem with Unisolated Builds
Historically, generating Python distributions
(python setup.py sdist bdist_wheel) relied entirely on
whatever packages happened to be present in the active Python
environment. This approach created common issues:
- Hidden Dependencies: A build might succeed locally because an undeclared tool was installed on the developer's machine, but fail in CI/CD pipelines.
- Version Conflicts: An outdated package in the ambient environment could break the build backend.
- Environment Contamination: Running setup scripts could execute arbitrary code and modify the host environment.
The Step-by-Step Isolation Process
When you run python -m build, the tool follows a
standardized sequence to construct wheels and source distributions
(sdists) cleanly:
1. Inspecting
pyproject.toml
The tool reads the project configuration file to locate the
[build-system] table. It extracts two critical pieces of
metadata:
requires: A list of packages required to build the distribution (e.g.,setuptools>=61.0,wheel,flit_core, orhatchling).build-backend: The entry point that will perform the packaging (e.g.,setuptools.build_meta).
2. Creating a Temporary Environment
Using an isolated environment provider (such as the venv
module or the third-party virtualenv package),
build provisions a fresh, transient directory structure.
This temporary directory is detached from the host Python's
site-packages.
3. Installing Build Requirements
Inside the newly provisioned environment, build runs an
installer (typically pip) to fetch and install only the
packages declared in the requires field. It can also query
the build backend for dynamic requirements via the
get_requires_for_build_wheel or
get_requires_for_build_sdist PEP 517 hooks and install
those as well.
4. Executing Build Hooks via Subprocess
Instead of executing code directly inside the parent process,
build runs the backend within a subprocess tied directly to
the temporary environment's Python executable. This ensures:
sys.pathcontains only the standard library and the isolated environment's dependencies.- Build artifacts are produced under strict isolation.
- Host environment variables and packages cannot accidentally alter the output.
5. Artifact Extraction and Teardown
Once the backend successfully outputs the .tar.gz
(sdist) and .whl (wheel) into the specified output
directory (defaulting to dist/), build
dismantles and deletes the temporary environment completely.
Disabling Isolation
Isolation is the default behavior, but developers can bypass it using
the --no-isolation (or -n) flag:
python -m build --no-isolationWhen this flag is active, build skips the creation of
the temporary virtual environment and executes the build hooks directly
within the current Python interpreter. This is primarily useful in
managed environments like Linux package distribution systems, offline
build environments, or situations where build dependencies have already
been pre-installed intentionally.