I’ve done a fairly big refactoring of wheel in order to move it towards being the command line tool I want it to become. The PR can be seen here. The main reason I’m writing about it here because I’m permanently removing the last remaining setuptools link which was the wheel.bdist_wheel module and the corresponding entry point. Setuptools has not needed wheel to build wheels for almost a year now, so I figured the time is ripe to throw out the obsolete code.
I’ve made most of the internal modules private, save for wheel.wheelfile whose fate is still unclear. I also made the wheel.metadata import emit a warning, as abruptly removing it caused an issue before.
Let me know if you have objections or concerns about the modifications. If I hear nothing, I’ll just go ahead and merge the PR.
My only concern is that there are still some packages out there that import bdist_wheel from wheel to create their custom bdist_wheel command. But I do realize that deprecation warnings don’t really work, so feel free to disregard this.
The deprecation warning has been there for almost a year, so they could not really complain about such a change being abrupt
I could send a few PRs their way I guess, to make sure they have a clear migration path.
In general I would consider “almost a year” to be abrupt in terms of deprecation timelines. I don’t know what the impact or benefits of this change would be though.
From the code search above I see this:
I don’t know whether that code would be broken by this change but the comment suggests that some people find changes in the wheel package’s API troublesome.
The problem is that wheel doesn’t have a public API, as the README has stated for 7 years already. But people still use it. As for piwheels, they have an open PR that fixes the issue.
I think in light of how other changes to the core packaging tools have been received (there’s a huge thread about build backends breaking), you’ll have a better time by keeping as much compatibility shim as you can to avoid old code from breaking.
We keep seeing that the ecosystem of people who use these tools moves very slowly, and more and more Python users are slow to move. It’s harder to pin to particular package versions than overall Python version, and so you’re more likely to get complaints about breaking changes.
If you want to be passive aggressive about it towards people who have ignored the docs (your call, but I wouldn’t oppose it ), require an obnoxious environment variable be set to use the shims - ENABLE_OBSOLETE_INSECURE_AND_UNSUPPORTED_FEATURES=1 - the kind of thing that any security team is going to ask questions about. (Or if you’re really mean, put PASSWORD in the variable name.) Print the variable and a link to a doc page (or this discussion) when they try and use it without the variable set.
It directly makes users aware that they’re doing something wrong, but also gives them a way to immediately re-run with their own workaround, which is going to reduce the amount of issues opened by at least 90%. Your sanity will thank you.
I’m not sure I’m following. Do you mean that without this workaround, the imports would stop working? If so, why not just point out the real solution (from setuptools.command.bdist_wheel import bdist_wheel) if we’re going to break things for the offending projects anyway?
What is the scenario for this breaking sdist builds? That packages have pinned to an old version of setuptools in their build requirements but left wheel unpinned?
I don’t see how this would happen, as wheel was never involved in any way in sdist builds done by setuptools. And if they were importing wheel itself in their setup.py, well…we discussed that scenario already.
That’s because no one could find alternatives. Even trivial customisations like platform specific files have been (as far as I’m aware) impossible without monkeypatching distribution.package_data in a bdist_wheel subclass. No one goes digging through these internal APIs for fun.
Is switching to from setuptools.command.bdist_wheel import bdist_wheel a valid replacement or is that just someone else’s private API?
That’s because no one could find alternatives. Even trivial customisations like platform specific files have been (as far as I’m aware) impossible without monkeypatching distribution.package_data in a bdist_wheel subclass. No one goes digging through these internal APIs for fun.
Perhaps so at least in some cases, but they should expect to get burned if they don’t vendor code from private APIs. Note that I’m preserving wheel.wheelfile as-is without deprecation warnings until there is a viable alternative.
Is switching to from setuptools.command.bdist_wheel import bdist_wheel a valid replacement or is that just someone else’s private API?
It’s as valid as it has been for as long as I can remember. Certainly more so now that the command canonically lives in setuptools, and people have subclassed setuptools commands for ages.
Yes, but it’s only a viable option for the author of the package, not the person who’s suddenly failing to install it. And while everyone waits for the author to make a new release (which is hopefully compatible enough with the release users were using to do the upgrade…), they’ll come to your issue tracker to complain about it.
There are a few tricks you can use to have a wheel.bdist_wheel that just imports setuptools to get the implementation. Using any of them is a small price to pay for not upsetting users, in the overall scheme of things.
That’s exactly what I had in place until now, and it’s been emitting deprecation warnings since August 2024. I don’t want to remain stuck with compatibility shims forever, so I figured that if someone hasn’t seen them yet, they’re never likely to. That said, I could just replace it with a simpler shim that raises an ImportError if the setuptools.commands.bdist_wheel import fails, explaining why this happens (the user upgraded wheel but not setuptools for whatever reason). That ought to lessen the impact of these changes.
Yikes - but I honestly don’t expect this to have as big an impact even if something goes wrong, given how wheel is no longer a wheel-building dependency of setuptools.
I’ve softened the blow a bit by readding the bdist_wheel module as a shim for setuptools.command.bdist_wheel. The entry point and implementation are gone though, so if someone only upgrades wheel and not setuptools and tries to import wheel.bdist_wheel, they will get a human readable error prompting them to upgrade their setuptools.
Looks like these changes were released half an hour ago. SymPy pyodide CI job is immediately broken with:
packages/auditwheel_emscripten/__init__.py", line 1, in <module>
from .exports import get_exports
File "/opt/hostedtoolcache/Python/3.12.9/x64/lib/python3.12/site-packages/auditwheel_emscripten/exports.py", line 7, in <module>
from .wheel_utils import is_emscripten_wheel, unpack
File "/opt/hostedtoolcache/Python/3.12.9/x64/lib/python3.12/site-packages/auditwheel_emscripten/wheel_utils.py", line 9, in <module>
from wheel.cli.pack import pack as pack_wheel
ModuleNotFoundError: No module named 'wheel.cli'
I don’t consider that to be any major problem. The CI job is there to show whether things are working and right now it shows that something is not working. I assume it will get fixed somewhere fairly soon. I don’t think there is anything to be done about it on SymPy’s end except perhaps pin a version of something in CI. The fix would either have to be in wheel or in pyodide somewhere I guess.
This does not cause any great upset for me but as a heads up if I am noticing this within 30 minutes of the wheel release then I think you can expect that there will be others arriving with pitchforks. Hopefully it is not as unfriendly as the setuptools issue but I suggest being ready to revert some of the changes or add back compatibility shims or something.