Sure sure, I understand all that, and why we think we need some special error signal from `build_sdist`, as currently written.
What I'm suggesting, is maybe calling `build_sdist` without knowing if it can succeed is already a mistake.
Consider instead, if we make the following small changes:
1. `get_requires_for_build_*` is passed the sdist and wheel directories, just like `build_*`, giving them the chance to actually look at tree before deciding what other reqs might be necessary.
2. `get_requires_for_build_*` returns None to signal `build_*` is unsupported (superceded by static reqs defined in TOML) and [...] to signal support (can be empty).
3. `get_requires_for_build_*` assumed to return None if missing (so optional and implies no support).
4. sdist reqs = `get_requires_for_build_sdist` (dynamic) + ??? (static)
5. wheel reqs = `get_requires_for_build_wheel` (dynamic) + `build-system.requires` (static)
6. If no reqs are found for sdist (no declared reqs in TOML and `get_requires_for_build_sdist` is missing or returns None), then `build_sdist` is unsupported.
7. If no reqs are found for wheel (no declared reqs in TOML and `get_requires_for_build_wheel` is missing or returns None), then `build_wheel` is unsupported. This one is a spec violation because at least one req is expected here (the backed itself).
This arrangement allows pip to know ahead-of-time if `build_sdist` is appropriate. If no sdist reqs are explicitly acknowledged, then no sdist can be created. Full stop.
Example usages:
* Backeds that only support wheel creation do not implement `get_requires_for_build_sdist` at all.
* Backeds that conditionally support sdist creation implement `get_requires_for_build_sdist` and return None if unsupported. This is where flit signals "impossible" from an unpacked sdist and [...] from VCS.
* Backeds that always support sdist creation (setuptools) implement `get_requires_for_build_sdist` and return [...] unconditionally.
So for pip's sdist -> unpack -> wheel path, it knows right away if it should build an sdist or skip right to building a wheel because the backend will inform via `get_requires_for_build_sdist` instead of overloading `build_sdist`.
I also think this achieves nice parity across sdist and wheel operations, keeps the same hooks optional, adds no special cases, and maybe even less overhead.
What say you?
--
C Anthony