-
Notifications
You must be signed in to change notification settings - Fork 3k
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
pyproject.toml (PEP518), build isolation (PEP517) and optional build dependencies #6144
Comments
You can use the |
From the help message "--no-build-isolation Disable isolation when building a modern source distribution. Build dependencies specified by PEP 518 must be already installed if this option is used." i don't think it is a solution ! The easy solution is to get rid of the pyproject.toml file. But it would actually be good to be able to use it (because of real build dependencies). More generally, the solution can not be a pip option. There are many situations (for example install with tox) where you cannot use a pip option. |
Here's a workaround I suggest to you: install all build-system.requires items that you want available manually (for eg, via Please include the pip version you are using and other details. What version of pip are you using? You are mentioning PEP 517, but PEP 517 isn't out in a public release yet.
If you disable isolation, the user has to manually install the build-time dependencies that they want to be available. The docstring is written assuming that all PEP 518
tox can: https://tox.readthedocs.io/en/latest/example/basic.html#further-customizing-installation Honestly, if your CLI tool doesn't allow passing custom options to pip, I don't think that would be pip's problem. |
I get this (correct) behavior with the last release of pip (18.1). it is why I didn't mention it. |
Adding more general features to |
Really, this option
|
Good to know! But once again, it is not a solution to this problem. |
PEP 518 is still "Provisional". Could it be modified to add a way to declare optional dependencies? |
Not likely, Provisional in this case pretty much just means it's accepted, but it hasn't been implemented/released yet so we might need to make small tweaks still in order to make it functional in the real world. Adding new features is generally out of scope. |
Then packages with optional build dependencies CAN NOT (and won't be able to) use pyproject.toml ? it is a problem! it is not something completely crazy to have a Note that the solution with |
I mean, then the question becomes, what if there are two things listed in What if we want to have groups of optional dependencies? Should that be supported? All of the same questions asked above apply to that too. None of these questions are, on the surface, super hard. But they all require sitting down and working through the options and making a decision about how they should function. That's something that deserves wider discussion. By all means, you're free to try and raise a discussion on the discuss.python.org Packaging category or on distutils-sig to see if other people are open to amending PEP 518 for this feature. I just think it's more likely going to be the case that we want an additional PEP for that feature. |
I agree with @dstufft. There's nothing fundamentally difficult to decide here, but it needs to be driven by use cases and a reasonable sense of what's important and what is generalisation for its own sake. I see this as being a follow-up PEP that extends PEP 518, and not suitable as an amendment to PEP 518. If you want to propose and champion such a PEP, then as @dstufft says, you need to start the discussion on distutils-sig or the Discource category. |
That being said, PEP 518 is released in pip now I think yea? We should probably move it out of provisional anyways. |
It seems very complicated whereas the need is really simple. It could be that the name "optional" is not appropriate. Maybe something like "used_if_importable" would be better. pip does not have to try to install packages listed in I hope the if yes, a simple implementation of
It is sad that this very useful feature pyproject.py, which has been presented as the new clean universal way to declare build dependencies can not be used for all packages having optional build dependencies. For example, I think for mpi4py it's bad news. There is the function |
@paugier But... if a project is "used if importable", then why isn't I guess I don't follow how you expect pip to choose whether to install "used if importable" build dependencies? What criteria should we use? Your sample code sets Apologies if I'm being dumb here somehow. (Note that "to explain the use case clearly to people who don't understand the requirement" is another benefit of writing this stuff up in a PEP, by the way 😉) |
This was my thought as well, but I see where @paugier is coming from. They want the "hard dependencies" installed automatically, and the optional dependencies used opportunistically. Installing the "hard dependencies" separately requires either parsing pyproject.toml or specifying build dependencies separately. Basically what they are asking for (which I think is reasonable) is a way for the "isolated" build environment still be created, but as an environment similar to a virtualenv created with --system-site-packages. I don't think the PEP needs to be modified in order for pip to support this use case. |
Let's take an example. Fluidsim is a package to run numerical simulations. it is used for research with very big simulations on clusters. it is also used for education by students with small simulations on laptops. It would be good if users could install with just Without pyproject.toml, the minimal installation with pip is something like
Then, we have 2 optional build requirements that are used only if they have been installed before by the user.
So that from a clean environment, i would like to have:
if we want to use pyproject (to get 1.), we would need for case 3. to tell users to install with:
which is worth that what we have now without To summarize,
We need to be able to tell pip not to isolate from some packages, in my case mpi4py and pythran, maybe with something like:
|
OK, thanks, I see what is being requested now. That sounds like a new pip flag, that enables behaviour somewhere between the default build isolation and That's not what the original request said, though (it was asking for a new key in
The relevant PEP for build isolation is PEP 517, specifically here. For a Agreed, the isolation change does not require a change to the PEP. The originally requested new key in It's not necessarily simple to provide the new feature (pip doesn't use virtualenv, so there's no existing means to provide |
Exactly! It seems to me that it would be much better to write this information (that some packages need to be accessible to setup.py opportunistically) in the repository (in practice in the pyproject.toml file) rather than to ask all users to add an option to the pip command line. It's a property of the package not of one installation. And we have a file to contain such types of information, called pyproject.toml... Moreover, it would be nearly useless to install packages that need this feature without this feature. The maintainers would get several installation issues just because users forget to use this unknown pip option, especially if we have How would it work for dependencies? All dependencies would be installed with this mode even if they don't need that? If not, how would one add this option for one dependency? |
This is not something I would expect you to want end users to do at all. It seems like it would be a terribly bad idea to have the capabilities of your deployed application depend on the build-time environment of the users, except in very rare cases. I don't like the idea of opportunistic dependencies at build time - that means what gets installed depends on what happened to be installed when you were doing the build, which is something I think should be opt-in for end users. What may be useful would be a build-time equivalent of I think the traditional way to do this is to break out the "optional" parts of your package into separate packages and make them extras dependencies, though I don't think that would work in the case of something like |
OK, then if you want that you definitely need a PEP revision/update. Some things that will need to be considered:
As a pip option, this is simply a quality of implementation option for pip. As a standard As another possibility, maybe there's an option to make it a pip option, but add a feature to pip to read project-specific options from a tool-specific
Good question. Conversely, for your option, how would something like |
Optional build dependencies seem to me like a bad idea. This would also means that the wheel cache should be deactivated for such packages. Or we would need to have different caches depending on the currently installed packages 🙅♂️ |
Interesting that you think it's bad. Can you please propose a better approach? I didn't experience so many "painful debugging" related to this aspect of some packages I work with. If someone see that a feature is not present (for example no MPI support), it's pretty simple to rebuild the package ( Note that optional build dependencies are quite common for non-Python dependencies. See for example how mpi4py chooses which MPI library should be used. Or how projects choose which Blas implementation should be used. I use optional build dependencies for (1) MPI support and (2) Python-Numpy compilers (here, only Pythran).
Also pip is of course not able to install the MPI library so pip can not install mpi4py on machines for which the user has not previously install OpenMPI or another implementation. Then, we can think about alternatives to my "bad idea" (build depending on installed packages) :
@xavfernandez How would you solve this problem then?
I think it's going to be more and more important to be able to compile the same Python-Numpy code with different tools, for example to target different hardware. So the package should be able to use opportunistically such tools. Note that such tools are quite new (not 100% sure every works everywhere) and can lead to long and memory consuming build. We really don't want to add pythran as a hard build dependency (except if we provide a wheel, but here I can't). I agree that in that case, we could use
(which is reasonable from the user point of view) would lead to no Pythran compilation. "This seems like a perfect recipe for painful debugging" as you say 🙂 |
@paugier FTR I've hacked this via another PEP517 backend which under the hood tries doing |
Hello, I'm not sure about the current state of this subject, and although it's over my head and I'm unsure if it's relevant, I cannot read about this optional dependencies subject without mentioning how Gentoo handles them (start to look at "USE-Conditional Dependencies") https://devmanual.gentoo.org/general-concepts/dependencies/ |
@Ckarles yea, when we started the discussion back at PyCon 2019 I mentioned those to folks. The most dynamic discussions are happening at https://discuss.python.org so I recommend subscribing to those and maybe participating in pushing the efforts forward :) |
I’m sure build-time feature detection and conditional compilation has its use cases, but I believe it is, in the most majority of cases, a suboptimal design, and would encourage people wanting this behaviour looking into alternatives if possible. Modern Python packages are always installed via wheels, which is also a distribution format. With conditional compilation, two wheels with the same name may contain logically very different things, which makes me feel quite uncomfortable. But maybe I’m just misunderstanding the wheel format here. But the more important issue to me is that, the choice whether to include a functionality in a library should always be an explicit flag exposed to the user, instead of implicitly set based on the build-time environment. This is kind of a problem with pip, in fact; CPython’s configure script by default disables parts of the stdlib if the underlying C library is not available, e.g. OpenSSL for Following this line of thought, I feel the best approach to the issue, if viable, is to split the features into separate packages, and manage them with extras.
Now this does not work too well in pip’s current environment isolation approach, since This got a bit longer than I initially anticipated. Sorry for sticking with my rambling. |
@uranusjr I think the idea is that we need a better naming convention for wheels so that feature-flagged builds could be distinguishable. |
That's indeed the key thing here, but no-one has yet come up with a suitable naming/tagging convention. That's the first step, and only once that's been done can we really start looking at adding tool support. Such a convention needs to be proposed as a PEP, and discussed with the whole packaging community, not just on the pip tracker. |
I'd like to share that I now solved the case we had in @aio-libs (and some other places) by using an in-tree backend that wraps the setuptools' one (which is documented https://setuptools.pypa.io/en/latest/build_meta.html#dynamic-build-dependencies-and-other-build-meta-tweaks). My implementation is somewhat more invasive, though. The feature toggling interface is exposed via PEP 517 This case doesn't really need special tagging support for wheels since it's either a pure-python wheel of one of the platform-specific ones. And the Cython line tracing is only useful in the context of development/testing/contributing to the project itself, so it's not like people would be using that when installing from PyPI, especially with that they would hit the published wheels almost certainly. |
I think I'm going to go ahead and close this out on the basis that the proper solution here is to have some mechanism to convey "features" in a generated wheel such that it is possible to indicate whether or not it is compatible with a more complex requirement specification than what exists already for Python packages. As Paul said in #6144 (comment), this is something that needs wider design discussion than pip's issue tracker. |
What's the problem this feature will solve?
Projects that have build requirements and optional build requirements can not use pyproject.toml because of the build isolation.
Example (https://bitbucket.org/fluiddyn/fluidfft): depending if mpi4py is installed, MPI extensions are built or not. It's very important to be able to install/use the package without MPI so mpi4py can not be added in
build-system.requires
.If a pyproject.toml is used, we get ImportError when importing mpi4py in the setup.py even when mpi4py is installed because of the isolation! So the MPI extensions are never build.
Describe the solution you'd like
Something like this could work:
Then mpi4py would be available during the build only if it is installed. We keep the advantages of the isolation (discussed in https://www.python.org/dev/peps/pep-0517/) but optional build dependencies are allowed.
Alternative Solutions
The text was updated successfully, but these errors were encountered: