Feature: Specify constraints file for the isolated build environment
What's the problem this feature will solve?
The recent hickup with setuptools 78.0.1 has shown:
- A constraints file specified with the
-coption of pip does not affect its isolated build environment - A constraints file specified with the
PIP_CONSTRAINTenv var does influence its isolated build environment
See https://github.com/pypa/setuptools/issues/4910#issuecomment-2748723219 for details.
That difference is inconsistent and the documentation also does not reveal the difference nor does it even talk about the isolated build environment: https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-c
Describe the solution you'd like
Add a command line option and corresponding env var that allows specifying a constraints file for only the isolated build environment whenever pip builds a package, e.g. when installing from a tarball.
The "uv" installer does have a UV_BUILD_CONSTRAINT env var and --build-constraint option specifically for constraints on the isolated build environment.
Alternative Solutions
- Use "uv pip install" :-)
- Continue with the different behavior mentioned above (bad)
Additional context
May be related to #8439
Code of Conduct
- [x] I agree to follow the PSF Code of Conduct.
I've been thinking the same for a little while and mentioned it just a moment ago: https://github.com/pypa/pip/issues/9081#issuecomment-2749464768
There's some design questions, and I don't know how uv pip handles this:
If a build dependency needs building is the --build-constraint flag passed to it? Or do we only support recursive build constraints via PIP_CONSTRAINT and PIP_BUILD_CONSTRAINT?
And for that matter, how is the env variable PIP_BUILD_CONSTRAINT passed down? Normally the env variable affects the current environment, but build constraints would explicitly not, does pip know when it's in an isolated build environment?
Other maintainers may feel differently, but I would be supportive of someone submitting a well tested PR for this flag, assuming these design questions are answered and tested for.
Also related: #8439
Also related is #13208 , in that it has the same underlying cause (environment variables that are supposed to correspond to command-line options, differ in terms of whether they are forwarded to the build environment).
I have thought about the design of how constraints and build constraints would interact in pip, I have a branch that implements this but I still have a fair bit of work to add tests for this design.
I think the design is easiest presented in table form.
Here is the current state:
| Requirement Level | PIP_CONSTRAINT |
--constraint |
|---|---|---|
| Install | Applied | Applied |
| Build | Applied | Not Applied |
| Build of Build (etc.) | Applied | Not Applied |
And here would be the new state:
| Requirement Level | PIP_CONSTRAINT |
PIP_BUILD_CONSTRAINT |
--constraint |
--build-constraint |
|---|---|---|---|---|
| Install | Applied | Not Applied | Applied | Not Applied |
| Build | Applied unless overridden | Applied and overrides | Not Applied | Applied and overrides |
| Build of Build (etc.) | Applied unless overridden | Applied and overrides | Not Applied | Not Applied (but overrides?) |
They key here is that PIP_BUILD_CONSTRAINT or --build-constraint would apply to the build environment overrides PIP_CONSTRAINT if it is set, on the assumption that if the user is passing one of these arguments they intend that to be the constraints for building, not PIP_CONSTRAINT.
Secondly I have modeled the current havior of PIP_CONSTRAINT / --constraint with PIP_BUILD_CONSTRAINT / --build-constraint, in that --build-constraint is not passed recursively, but due to the nature of env variables PIP_BUILD_CONSTRAINT applied to every subprocess of subprocess called. My thinking is that some users may have constraints on their direct build environment, but not on their build of their build environments, as that would be trickier to reason about, but they have an option to do so with PIP_BUILD_CONSTRAINT.
Finally there is the situation of PIP_CONSTRAINT and --build-constraint, this is a weird edge case, the user has a seperation of concerns of install and build constraints, but there is a build of a build. Should the presense of --build-constraint cause PIP_CONSTRAINT not to be applied in the build of the build? I don't know, but I just realized this is how I've currently implemented it, and it pops out of this override design natrually, so it might be a bit messy to implement it in a different way.
I am not likely to publish this PR for at least a month, so there is no rush.
There are a couple of other designs that would be simpler, but both would introduce at least minor backwards incompatibilities.
Passing --constraint and --build-constraint recursively:
| Requirement Level | PIP_CONSTRAINT / --constraint |
PIP_BUILD_CONSTRAINT / --build-constraint |
|---|---|---|
| Install | Applied | Not Applied |
| Build | Applied unless overridden | Applied and overrides |
| Build of Build (etc.) | Applied unless overridden | Applied and overrides |
Or not pass PIP_CONSTRAINT to the build environment and only allowing PIP_BUILD_CONSTRAINT to be applied recursively:
| Requirement Level | PIP_CONSTRAINT |
PIP_BUILD_CONSTRAINT |
--constraint |
--build-constraint |
|---|---|---|---|---|
| Install | Applied | Not Applied | Applied | Not Applied |
| Build | Not Applied | Applied | Not Applied | Applied |
| Build of Build (etc.) | Not Applied | Applied | Not Applied | Not Applied |
Related discussions regarding pinning build deps and the use of PIP_CONSTRAINT as a workaround across the ecosystem:
- https://github.com/pypa/pip/pull/13113
- https://github.com/pypa/pip/issues/13300
- https://github.com/pypa/pip/issues/4582#issuecomment-1856172641
- https://github.com/pypa/pip/issues/8439#issuecomment-1334243546
- https://github.com/pypa/build/issues/292
- https://github.com/pypa/cibuildwheel/pull/1675
FWIW I went with a design that somewhat breaks backwards compatibility, so you have to opt in by specifying --build-constraint ... or --use-feature=build-constraint (the later is when you don't want PIP_CONSTRAINT to affect build constraints and you don't want to specify build constraints, which is actually impossible without this feature) until at least pip 26.1.