Skip to content

How do you determine the file name that wheel will build? #601

@geofft

Description

@geofft

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 build

How 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.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions