Background
I have two related extensions/clarifications I’m interesting in making to PEP 517, although I am fully aware that there is much history here. Instead of putting a PEP forth (even for discussion) I’m interesting in looking for possible support and general feedback. I really want this to be a collaboration instead of a flogging . If all seems well, I can author the PEP.
Both of these extensions/clarifications stem from PEP 517 acknowledging backend wrappers in the “In-tree Backends” section. (Unfortunately after this mention, they aren’t mentioned again, and the reader/implementor is left to guess to what degree they are supported.)
The specific use-case I’m hoping to unlock is an out-of-tree build backend wrapper. Such a wrapper is incredibly useful for a (usually corporate) monorepo of Python packages. Easily obvious use-cases such as adding a the “Private” classifier to avoid accidental upload, or by enforcing dependency conventions/requirements. [1] The “out-of-tree” part here is mostly allowing “updirs” in backend-path
(however once you allow that, you really are allowing any out-of-tree path). [Reminder that PEP 517 explicitly calls out that this is a useful situation, albeit for a single project]
Such a use-case could be supported by uploading our backend wrapper to an internal cheeseshop (or worse, PyPI). However, that’s a very sub-optimal solution and goes greatly against the spirit of monorepos and their tooling. [Another reminder about PEP 517 admitting this is useful ]
Lastly, note I don’t think any part of this discussion should involve making it easier for build wrappers to exist. Like this semi-related proposal)
1: Clarify/encode the responsibilities when it comes to custom wrappers
(This is kind of an extension of this discussion: Nobody is following the metadata_directory promise in PEP 517)
FWIW such wrappers exist in the wild as packages (out-of-tree) such as setuptools-ext · PyPI. Additionally at least one build backend (hatch) has “build hooks” which are related but not the same.
There’s some misunderstanding/disagreement of the role of “final” build backends when it comes to build wrappers (usually around wrappers altering metadata).
2. Clarify/encode the support of out-of-tree “backends”
(Related to the original in-tree backends discussion PEP 517 Backend bootstrapping)
It seems consensus in the original discussion gravitated around in-tree due to simplicity and a lens on bootstrapping backends. (Although I could be wrong, it’s a very long discussion). AFAICT support for out-of-tree backends was never explicitly proposed, and therefore never discussed.
Open questions
1. Is there a way we can encode support for backend wrappers in a backwards-compatible way?
My gut says yes. It will likely involve wheel editing in certain cases, but that’s not that painful (example code). This likely looks something like clarifying the following quotes with the responsibilities of the parties in a world where wrappers exist:
If the build frontend has previously called
prepare_metadata_for_build_wheel
and depends on the wheel resulting from this call to have metadata matching this earlier call, then it should provide the path to the created.dist-info
directory as themetadata_directory
argument. If this argument is provided, thenbuild_wheel
MUST produce a wheel with identical metadata.
The hook MAY also create other files inside this directory, and a build frontend MUST preserve, but otherwise ignore, such files
If a build frontend needs this information and the method is not defined, it should call
build_wheel
and look at the resulting metadata directly.
I think this loosely looks like:
- If build wrappers want to provide
prepare_metadata_*
hooks, they MUST respect that the wrapped backend might not support it. In this case, they follow the frontend route and create a wheel, modify it, and return the relevant adjusted metadata. - If a build backend receives a
metadata_directory
inbuild_wheel
, they MUST respect it by using it verbatim in the resulting wheel (or error if doing so would be fundamentally incompatible with the backend). However, for backwards compatibility build wrappers SHOULD handle the case where backends don’t exhibit this behavior and either error or re-adjust the wheel. (Depending on how nice they wish to be to their users, or mean to their wrapped backends if you consider who might receive the the backlash of the error)
2. Is there a technical reason not to support arbitrary backend-path
s?
I totally agree with the decision to keep support limited and use the lens of build-backend bootstrapping. But without that lens (and fully acknowledging that there are potential valid use-cases that involve out-of-tree backends/wrappers) is there a technical reason to disallow out-of-tree paths?
To be clear you could easily accomplish this in a spec-compliant way (AFAICT) while going squarely against the spirit of the PEP with an outoftree
build backend that just adjusts sys.path
from a config and forwards the call.
You could enforce such things without a backend-wrapper, however that would require the enforcer being run. That’s not always the case when people are developing/iterating ↩︎