The key point that I left out of the message with the
backend-bootstrap-location proposal in it, is that I started out intending to have that message be in support of Option 1 and suggest a possible syntax for that approach, but actually trying to spec out the details convinced me that @njs has a valid point regarding the relative ease of explaining Option 3.
The starting point for that exploration was the location of
setuptools.build_meta in the setuptools repo: https://github.com/pypa/setuptools/blob/master/setuptools/build_meta.py
With my proposed Option 3 spelling above, it’s fairly easy to follow how the bootstrapping is supposed to work: the repo root directory (
".") gets added to the front of sys.path, then the
setuptools.build_meta backend gets imported the same way it would for any other package that declared it as its build backend. This is also how @takluyver’s
intreehooks helper backend for bootstrapping
flit already works, so we have prior art for it being a viable bootstrapping option.
We also know from the open pip 19.0.x PRs that it isn’t that hard to add a
sys.path injection feature to the
pep517 support library (I wouldn’t do it the way I did in those PRs as a public API, but that’s just a matter of replacing an environment variable with a command line argument and a magic prefix with a normal function parameter)
But what happens if we try to specify the location of the build backend directly? How would it be spelled in
pyproject.toml? What are frontends actually supposed to do with that information? How would folks introspecting project metadata determine which build backend is actually being bootstrapped? (that one’s not a functional requirement, it would just be nice to have)
Suppose we denoted a bootstrapped backend this way:
Should a frontend run that file as a script? Should it run it with
runpy.run_path()? Should it import it as a module, using the appropriate version dependent incantation to do so?
What are the implications for how
build_meta.py is written? Will explicit relative imports work? Will
setuptools.* absolute imports work? Will
There are (somewhat) reasonable answers available to all of those questions, but I didn’t think any of them were as elegant as the idea of just switching to a slightly more constrained version of Option 3 such that you specified where in the tree the backend implementation could be found, specified
build-backend as normal, and then the backend itself executed in just the same way as it would for any other project.
The other thing I realised is that the “What if non-backends use the backend bootstrapping option to add an extra in-tree path to their hook execution environment?” concern with Option 3 applies just as much to Option 1, as either way you can make a custom in-tree backend that includes
from my_real_build_backend import * as one of its lines and runs arbitrary code (including
sys.path adjustments) before and after that, and that’s something that
intreehooks already allows with PEP 517 today.