-
Notifications
You must be signed in to change notification settings - Fork 171
Description
We have a set of Makefiles that orchestrate some builds, including wheel builds. Here's a super simplified conceptual version (that is heavily abstracted from what we're actually doing, but I think it's illustrative):
all: ... ${XYZ_WHEEL} ...
XYZ_SDIST := xyz-1.0.tar.gz
XYZ_WHL := xyz-???.whl
${XYZ_WHL}: ${XYZ_SDIST}
pip wheel ${XYZ_SDIST}or perhaps
XYZ_SOURCES := this.py that.py
XYZ_WHEEL := dist/xyz-???.whl
${XYZ_WHEEL}: ${XYZ_SOURCES}
python -m buildHow do we figure out what the wheel filename is going to be?
In the past, we did this by setting a variable to the output of
from wheel import pep425tags
print("-".join(pep425tags.get_supported()[0]))for the current interpreter, and setting XYZ_WHEEL := xyz-1.0-${WHEEL_SUFFIX}. Obviously this broke after the removal of pep425tags in 2020 (yes, I'm a little behind on filing this).
The recommendation in e.g. #370 is to use packaging.tags, but as far as I can tell that's not quite helpful here. That gets you a list of all possible tags that the current interpreter could install. It's perhaps of some use in wildcarding a directory after it's built, but for writing a Makefile (or several other types of similar build orchestration logic, judging from the pings on #346), you'd want to know the filename in advance. What we need is a way to ask wheel what particular tag it's going to use.
I'm currently going with the following, which seems to work:
from setuptools import Distribution
from wheel import bdist_wheel
cmd = bdist_wheel.bdist_wheel(Distribution())
print("-".join(cmd.get_tag()))but that seems pretty fragile too - apart from wheel not having a public API at all, this constructing a setuptools command object by hand seems particularly fragile. (The proposed public API in #472 does not seem to refactor the get_tag() logic into a public function, as far as I can tell.)
Furthermore, there is a legitimate objection to what we're even trying to do: the concept of "what filename will get used" is not a constant, it's a function of what's going on in the particular source package. For instance, for universal / pure wheels, they get a more generic tag. (You can get this out of the second approach with cmd.universal = cmd.root_is_pure = True, but that just makes it even more fragile....) Arguably we should be looking at the specific sdist / pyproject.toml / whatever to get the exact answer, but I think you can approximate this in most practical use cases with a couple of flags about whether it's universal / pure / limited API / etc.
Is there a more obvious way to do this that I'm missing? Judging from the fact that the actual logic is in bdist_wheel.get_tag() and not in a separate library like packaging, I think there is not.
In that case, would you be willing to expose a command like python -m wheel get-tag or a public API function to address this use case? I think something like the following would work for a command line:
usage:
wheel get-tag [--universal] [--pure] [--limited-api] [--platform PLATFORM]
wheel get-tag <sdist.tar.gz>
wheel get-tag <directory>
or maybe python -m wheel get-filename which requires passing in the distribution's name and version in the first case, or something. (In the sdist case, it would be nice if it could avoid unpacking the entire sdist and can just look around in the tarball for pyproject.toml/setup.cfg.)
(I could probably send in a PR to implement this, if the approach is acceptable to you, but I mostly just want to get discussion on what you think of the problem in general.)