Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow setting build env constraints #292

Open
webknjaz opened this issue May 8, 2021 · 14 comments
Open

Allow setting build env constraints #292

webknjaz opened this issue May 8, 2021 · 14 comments
Labels
enhancement New feature or request

Comments

@webknjaz
Copy link
Member

webknjaz commented May 8, 2021

So normally folks put direct unrestricted dependencies into their requires under [build-system] in pyproject.toml. This means that building the same dist may become unpredictable over time. One way to solve this is to somehow generate a dependency tree with all transitive deps pinned and stick it there.

But this approach seems weird. Do you think it'd be reasonable to have something like python -m build ... --constraints=build-env-deps.txt pointing to constraints for use in pip install command?

@FFY00
Copy link
Member

FFY00 commented May 8, 2021

This is out of scope IMO. This package aims to be simple, as it is crucial for bootstraping Python environments, so I'd like to avoid bringing much complexity into it. It is a hard line to draw, and this use-case does not seem strong enough. We already provide all the CLI, or API, required for making this work, so not having the glue directly available in the project should not be an issue.

You can acheive the same with the following commands.

pip install -r contraints.txt
python -m build -n

@webknjaz
Copy link
Member Author

webknjaz commented May 8, 2021

The idea here is to avoid using constraints as requirements, because they are not that, though.

@gaborbernat
Copy link
Contributor

I feel like this should be discussed at the PEP level, not the tool level. Currently, PEP-518/517 does not handle your request.

@FFY00
Copy link
Member

FFY00 commented May 8, 2021

The idea here is to avoid using constraints as requirements, because they are not that, though.

I think I don't really understand this comment. Could you clarify?

@layday
Copy link
Member

layday commented May 8, 2021

Are you able to pass constraints in an env var? Does that work with pip?

@uranusjr
Copy link
Member

uranusjr commented May 8, 2021

Yes I think setting PIP_INSTALL_CONSTRAINTS should work (whether that’s a proper feature is up to debate).

@webknjaz
Copy link
Member Author

Yes I think setting PIP_INSTALL_CONSTRAINTS should work (whether that’s a proper feature is up to debate).

Woah, I haven't thought about this. I guess having such a workaround would be useful. Although, for pip install scenario (unrelated to build) it'd probably cause multiple transitive deps in the tree to fail the build...

I think I don't really understand this comment. Could you clarify?

I meant that I'd like to pass --constraints to pip like @layday and @uranusjr while having no pins in [build-system.requires].

@webknjaz
Copy link
Member Author

So while reflecting on this, I now have a slightly different feature idea for build.

Would it be possible to have a command for extracting the list of the build deps from toml? The idea is that if there's something like build --export-sdist-build-deps-to=build-requirements.txt, this would facilitate the manual build env provisioning process w/o having to have an additional to build config parsing implementation.

@layday
Copy link
Member

layday commented May 11, 2021 via email

@FFY00 FFY00 added the enhancement New feature or request label Jun 17, 2021
@webknjaz
Copy link
Member Author

Yes I think setting PIP_INSTALL_CONSTRAINTS should work (whether that’s a proper feature is up to debate).

I've recently verified that setting PIP_CONSTRAINT works: cherrypy/cheroot@5c1ac08#diff-ef2cef9f88b4fe09ca3082140e67f5ad34fb65fb6e228f119d3812261ae51449R51.

webknjaz referenced this issue in cherrypy/cheroot Dec 22, 2021
This change adds pinned constraints to the PEP 517 based distribution
package build process by adding a pip-tools managed lock file. It is
also auto-updatable by GitHub Dependabot.
@nitzmahone
Copy link

So long as the envvar passes all the way through to the actual build environment when the build deps are installed, that's probably good enough for now, but yeah, agreed that this is a common problem that we've been nailed on numerous times, and just manually syncing the requirements is a lot more problematic than constraining known problem cases. It seems like this is already a problem that every backend needs to solve, so long-term, having a common way to do it would be a Good Thing.

@layday
Copy link
Member

layday commented Dec 22, 2021

I don't see a future where build allows you to constrain your build deps the way it's set up currently - that sounds like the job of a locker/env manager, which build is not. If build had a more pluggable architecture and you could write 'drivers' for pip/Poetry/pdm/pip-lock/who knows what, then it could make sense. But I can't imagine who's gonna make that happen or if build is the place where it should happen.

@webknjaz
Copy link
Member Author

I think that the locker thing is separate, yes. I use pip-tools to produce the constraints file. But what is the problem with making pip consume it? It's already being called under the hood anyway.

@joerick
Copy link

joerick commented Nov 19, 2023

I'd like to add a +1 to this feature request.

build makes a virtualenv and installs the packages listed in build-system.requires before invoking the build-backend. I think it should be possible to specify a pin/constraint for these packages at runtime.

There are a couple of use-cases.

  • Build repeatability users like @webknjaz above want more determinism in their builds, for consistency, predictability, easier use in CI, easier debugging, reduced supply-chain attack surface area.

    For this use-case, we might argue that you can get around this by pinning the versions of tools in build-system.requires. But this is not ideal, because it guarantees that the package cannot move with the times, for a new version of Python for example. And, it's not possible to pin to a specific SHA-256 digest this way (something that was noted in this recent packaging complain-o-post).

  • Embedding into other tools (selfishly!) cibuildwheel has been using the PIP_CONSTRAINTS workaround for a few years now to ensure that if a user pins a version of cibuildwheel, then the versions of build tools like pip and setuptools remain static for repeatability. This is accomplished via PIP_CONSTRAINTS too, but it means that users can't do their own pinning too.

The solution above, using PIP_CONSTRAINTS is really working around the absence of this feature by reaching into the internals of pypa/build and configuring its pip invocation. This happens to work, but it risks hitting other invocations of pip, and is unsupported. There is no other way to make the build repeatable, without disabling build isolation.

I'd like to propose a command line option, like-

build ...
    [--dependency-constraints FILE]
    ....

Options:
...
  --dependency-constraints FILE   Use a pip constraints file to control versions
                                  of packages in build-system.requires. Can be
                                  used multiple times.
    

Which could be routed through to the pip install line at https://github.com/pypa/build/blob/main/src/build/env.py#L133 .

I understand that the maintainers here want to keep the tool small, but given that build is doing the job of installing the build-env dependencies, it seems natural to give users control over this small part, before the build-backend takes over.

joerick added a commit to pypa/cibuildwheel that referenced this issue Jan 20, 2024
Reasons to do this:

- setuptools is no longer the only game in town. When cibuildwheel was created, setuptools was the only way to make wheels. these days, there are many build backends so special casing setuptools doesn't make so much sense
- we don't need to preinstall `wheel` any more, setuptools will do that itself when it needs it.
- projects with pyproject.toml (i.e. the vast majority of projects going forward) don't benefit from the pin anyway, because both `pip` and `build` create an isolated environment to install `build-system.requires` into.
- this makes it easier for end users (such as @webknjaz) to control build-system versions using `PIP_CONSTRAINT`, because there's less potential for a user-specified version to conflict with one of our pins.
  - (long-term, I'd love `build` to [support this directly](pypa/build#292), and then we could have a proper way to keep pyproject.toml dependencies loose and forward-compatible while retaining build determinism. But PIP_CONSTRAINT is the best we have for now. PIP_CONSTRAINT isn't ideal because it affects other things, like the test virtualenv).

This PR also adds a pin for pypa/build. It appears that was missing before, but we should pin it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

7 participants