pip 10 declares build dependencies before running setup.py
pip 10 implements PEP 518 and prepares a separate environment for declared build requirements. The change addresses the circular problem of executing setup.py to discover what it needs.
A source package can need an installed library before its build script can even explain how to build it. If the requirements live inside that script, an installer must execute code before it knows whether the prerequisites for executing the code exist. Python packaging has accommodated that circular dependency through conventions and additional installation machinery. pip 10 gives projects a declarative place to state the initial requirements.
The pip changelog dates version 10.0.0 to April 14. Its release-tagged copy records support for build dependencies in pyproject.toml, as specified by PEP 518. Packages declaring build dependencies can have those dependencies installed in an isolated build environment before pip builds a wheel. The final release also includes a PEP 518 support fix following the beta releases.
I find Python's packaging systems disproportionately difficult relative to the language itself. This change addresses a specific cause of that difficulty. A source package can state what its build requires in a form an installer can read before invoking the build script. That makes an otherwise implicit prerequisite available to automation.
Why setup_requires could not settle the problem
PEP 518 explains the historical dependency on executable setup.py files. With distutils in the standard library, the build machinery came with Python. Once projects adopted setuptools and other build-time components, the interpreter alone no longer established that the script could run.
Setuptools provides setup_requires, but the proposal identifies several limitations. An installer other than setuptools cannot obtain that information without executing the script. Setuptools itself discovers the requirements during setup(), which can be too late for imports earlier in the file. A build requirement on setuptools is also awkward when setuptools must already be available to interpret the requirement.
That timing problem is easy to see in an illustrative build script. If a top-level import depends on a package that has not been installed, control never reaches the setup() call holding the dependency declaration. Moving the declaration into an argument does not move it ahead of the import. Authors can delay imports or require users to prepare their environments, but those arrangements push build knowledge into procedural code or separate instructions.
The proposal also describes competing dependency-management activity. A pip operation can cause setuptools to download requirements through its own mechanisms. Users may then need to configure both systems, including their repository settings. The problem includes ownership of the installation process as well as the location of the dependency list.
PEP 518 separates the initial dependency information from executable build code. Its scope is the minimum environment needed for the build system to begin execution. That is a constrained claim, which makes the change easier to assess. The file describes prerequisites; it does not make every part of a source build declarative.
The new file describes the build environment
A conventional setuptools project can add a pyproject.toml containing a build-system table. For pip 10's wheel-building path, an explicit declaration can include both setuptools and wheel.
[build-system]
requires = ["setuptools", "wheel"]
The list contains requirement strings. PEP 518 specifies PEP 508 dependency notation, so this is dependency data with a defined interpretation. It is not a shell command and does not require executing the project's setup.py to read the names.
The distinction between build requirements and application requirements is essential. These entries make the build machinery available. They do not declare all packages that users need when they import the installed application. Putting a library here answers a question about constructing the distribution. It does not, by itself, answer whether that library belongs in the installed application's dependency metadata.
The pip 10 requirement implementation shows the file handling directly. get_pep_518_info() reads pyproject.toml, obtains the build-system table and retrieves requires. When the file exists but lacks a build requirement declaration, this implementation supplies setuptools and wheel as defaults. It also returns a flag indicating the file's presence and the need for build isolation.
That detail matters for projects adopting the file for another tool. PEP 518 permits tool configuration under namespaced tables such as tool.<name>. The file can therefore exist without a build-system table. In pip 10, its presence still participates in the build-environment decision. A maintainer needs to understand the installer's behaviour alongside the configuration schema.
The example deliberately keeps the declaration small. A version constraint belongs here when the build actually requires it. An unconstrained name leaves the selected version dependent on package discovery at build time. A minimum version expresses a prerequisite, but does not describe one fully fixed set of build inputs. Those are different promises about the resulting process.
Isolation changes where build tools are installed
The build environment implementation in pip 10 creates a temporary build directory. It places that environment's script directory at the front of PATH, adjusts PYTHONPATH to include its library directories, and sets PYTHONNOUSERSITE to disable the user site. On exit it restores the saved environment variables and ordinarily removes the temporary directory.
Those mechanics explain the intended separation. Tools needed to construct a package have a build location that is distinct from the target application's ordinary installation. A project can request its build requirements without requiring the user to leave those packages installed as application dependencies simply to complete the build.
The implementation also gives the word isolation a precise limit. It prepends build library locations to an existing PYTHONPATH when one is present. Its code manages process environment variables and installation directories. It does not create an operating-system security boundary around arbitrary build code. Reading a dependency declaration before execution solves a dependency-ordering problem, while executing a build remains execution of the project's code.
That distinction is particularly relevant when evaluating the change's reliability claims. Explicit prerequisites can reduce dependence on whatever build tools happen to be installed already. They do not establish that every influence on a build has been removed. The source tree, compiler and other external inputs still have their own roles in any particular package's build process.
I regard the explicit declaration as useful even with those limits. It makes a failed build easier to discuss because the intended initial Python dependencies have a location in the project. The maintainer and installer can refer to the same data instead of inferring prerequisites from an import failure or an undocumented preparation step.
setup.py remains part of this release's interface
The pip 10 installation reference still describes a setup.py build interface. It documents commands for metadata generation and installation, along with bdist_wheel for wheel construction. Editable installation uses setup.py develop --no-deps. The presence of pyproject.toml in this release does not establish a completely different invocation protocol for arbitrary build tools.
This keeps the event's scope clear. PEP 518 specifies how to obtain the minimum build dependencies. The installer can prepare those dependencies and then use its supported build commands. A project cannot assume that naming any package in requires tells pip how to invoke that package as a build system.
The installation reference also says installing a wheel does not invoke the build system. That distinction explains why users can encounter different prerequisites depending on the distribution artifact available to them. A source build needs preparation that an already-built wheel does not. Declaring build dependencies addresses the source path without changing the meaning of runtime dependency metadata. A build failure and an application import failure consequently need different dependency investigations, even when both occur during what the user considers one installation operation.
pip 10 separately changes installation from local directories and version-control locations to build a wheel for installation, as its release notes describe. Wheels from those sources are not cached. The release therefore makes wheel construction relevant to more local development operations while introducing a way to prepare declared build requirements.
For a package author, the concrete result is that the repository can now describe the Python tools needed before its existing build script runs. The declaration travels with the source and pip interprets it before building the wheel. That closes the initial dependency-discovery gap without requiring the project to encode its prerequisites in a script that cannot yet execute.