Repository navigation
Description
setuptools version
setuptools==82.0.0
Python version
Python 3.10
OS
n/a
Additional environment information
No response
Description
(I am reporting this a bug, though it's likely to be more of a discussion, at least initially. I don't see this kind of technical discussion happening in GitHub Discussion though).
setuptools 82.0.0 recently removed the pkg_resources library. This breaks all packages that rely on this for either build-time and runtime. While users can work around this at runtime by pre-installing an older setuptools version in the environment, doing so for build-time dependency on pkg_resources is far more difficult, given the rise of of build isolation in pip and other tools in recent years (I believe this was the key reason for closing #863). While workaround do exist for pip (which has the --no-build-isolation hammer), I don't believe other tools like tox have equivalent options. The removal of pkg_resources thus effectively breaks installation of older packages, which is very unfortunate given these are still quite common in the wild.
Expected behavior
The entire reason for build_meta.__legacy__ existence is to allow us to continue using packages that haven't migrated to newer packaging standards, whether that is because the packages are no longer maintained or we're intentionally testing older versions (for e.g. stable or historical release branches). Removing pkg_resources breaks this contract owing to pkg_resources's use as a build-time dependency for things like namespace packages.
I believe pkg_resources should continue to be installed in the environment legacy configuration. Whether this "installation" is handled by pip or setuptools is likely an implementation detail, but in either case the backing code to support it is small, and it could easily be filed away somewhere and never looked at again.
Am I missing something? Is there an alternative approach users can use and that we could document? As always, I am happy to work on a solution once one has been agreed on.
How to Reproduce
n/a
Output
n/a
Activity
abravalheri commentedon Feb 9, 2026
Hi @stephenfin, I think that there is a misalignment of expectations and assumptions in this phrase:
I don't believe the implementation of
build_meta.__legacy__was ever targeting the behaviour described above. Since the beginning the only thing thatbuild_meta.__legacy__was only concerned about a particular change introduced by the migration to PEP 517: once the installation/build was no longer performed usingpython setup.py ..., the side effect of the standard is that the current working directory was no longer available insys.path, which broke severalsetup.pyscripts.That is the only backwards compatibility provision that
build_meta.__legacy__ever introduced.Also, when PEP 517 was introduced, the spec said:
So that is what the
legacypart insetuptools.build_meta:__legacy__was about: an equivalent to runningpython setup.py ...directly (and let me say, not a perfect one, because build isolation, introduced in PEP 517, is not something setuptools itself have the power to waive, as it is in the complete control of the build frontend). The expectation in the original issue description is much bigger than the one described in the standard and in the actual implementation ofsetuptools.build_meta:__legacy__.I understand that your intention here is to initiate a debate on the topic, and that is completely fine. But this debate should also include considerations about who is going to provide and maintain such implementation (as far as I understand currently this project does not have the human power to do that).
I believe that the only alternative that users have to avoid tooling drift in general (not only regarding
setuptools/pkg_resources) is by using pre-built distributions. This means thatsetup.pydoes not run every single time a person executespip install ...1. There is a discussion about this topic and tips on how to do that in https://github.com/pypa/setuptools/blob/4966178dd707b5a470f2e5424b1b5c9c29c2f42f/docs/deprecated/sdist-reproducibility.rst (apologies the page should be present in the docs website but due to the Github general issues as of today, the RTD builds are not running correctly -- it should be fine soon). PRs for improvements on the docs are welcome.Footnotes
Ideally
setuptoolsis not used in runtime, only in build time, so if you already have the artifact pre-build,setuptoolsdoesn't even run. ↩stephenfin commentedon Feb 9, 2026
Thanks for the response, @abravalheri. Regarding your first point, pip documents that it will fallback to creating a stub
pyproject.tomlusing thesetuptools.build_meta:__legacy__build backend if a project has asetup.pybut does not have apyproject.toml. As you note, this matches the behavior defined in PEP-517. My reason for mentioning this backend is that it is the thing that thesepyproject.toml-less projects hit during installation, so if a solution were to be engineered in setuptools (where I suspect it will need to be), this would be a likely hook point. However, it's fair to say thatsetuptools.build_meta:__legacy__doesn't provide the fallback behavior - pip does. Point taken.That being said, my general point still stands, which is that the removal of
pkg_resourceshas broken installation of a large number of projects, in a way that is very difficult or impossible to fix.setuptoolshas long held a blessed position in Python and there is a massive corpus of released packages that depend on its APIs.pkg_resourcesis one of those APIs and its removal is functionally equivalent to removing thesetupfunction for these released packages. We obviously wouldn't remove thesetupfunction, at least not without serious considered (likely a PEP), so I'm not sure why we can removepkg_resourcesso easily.As I said in comment 0, I'm happy to work on an implementation and I'm also happy to sign up for maintenance. However, my expectation of maintenance it that there basically shouldn't be any. Treat it like TeX (or half the Python stdlib) and just mark it as done. We shouldn't be adding any more type hints or running other linters on it. Heck, maybe we shouldn't even be keeping the tests around. The code only uses stable stdlib libraries so it won't break unless Python breaks us (in which case we'll at least benefit from a 2 year window). Stick the code in a "private" module that only gets installed for building those legacy packages and forget it's there until such a time as PEP-517 gets a successor that formally drops support for installable projects without a
pyproject.tomlfile (which is not something I believe has happened yet). Or if that's not possible, revert #5007 (restoring thepkg_resourcesdirectory in the root dir) but stick a big warning in the code that no one should touch anything in the file and disable linting for same.EDIT: On the point of sdist reproducibility: I don't have the ability to do this for older releases of my projects, let along those of all my dependencies. This is a great goal to aim for, but it doesn't help the current situation.
stephenfin commentedon Feb 9, 2026
Some other points/alternatives that didn't really fit into the above, but which I feel are worth raising.
I have explored modifying
pipso that it would pin setuptools when running in "fallback mode". I believe this is significantly riskier though as, to the best of my knowledge, this fallback mode is not deprecated for removal and the chance of setuptools as a whole (rather than the single-filepkg_resourceslibrary) breaking on future Python versions or having a CVE is far higher. It also conflicts with what was specified in PEP-517.If we were insistent on removing
pkg_resources(and again, I'm not sure we need to do, given the low cost of maintaining it), we could tie its removal to a Python version, ideally backed by a PEP. At least that way people we avoid breaking stable branches for countless projects, since those run on released Python versions. This would be equivalent to Python's removal ofdistutilsin Python 3.12.Related to the above, if support for the fallback mechanism (and maybe
setup.pyfiles in general?) is not something that setuptools plans to support long-term, we really need a PEP to indicate this so people have sufficient notice to both rework their own projects and their dependency trees to handle this. I can't do anything about thefoobarlibrary that I rely on, which never migrated to apyproject.tomlfile and is no longer maintained, but at least I'll know that I need to find a replacement by Python 3.x.iXce commentedon Feb 9, 2026
this is indeed causing massive pain in the field, as @stephenfin points out due to build isolation and end users having 0 ability to control the setuptools version pulled during isolated builds
dimbleby commentedon Feb 9, 2026
Front-ends provide ways to control this eg pip uv poetry
stephenfin commentedon Feb 9, 2026
This is definitely worth noting, but it's also worth noting that tox (via https://github.com/pypa/pyproject-hooks), build, and hatch don't. I believe hatch doesn't even support "normal" constraints, and tox only gained support for these recently'ish.
Avasam commentedon Feb 10, 2026
IMO this goes towards the proper solution. Have build frontends be able to say "whenever you encounter one of these legacy projects lacking build definition, here's the set of dependencies to use". As well as "here's a set of build dependencies to override for project with broken build dependencies (likely due to a lack of an upper-bound pin)"
abravalheri commentedon Feb 10, 2026
The following is not a statement about the eventual outcome of this issue; these are simply comments on the topics discussed on this thread.
It is worth trying the pip environment variables described in
https://github.com/pypa/setuptools/blob/4966178dd707b5a470f2e5424b1b5c9c29c2f42f/docs/deprecated/sdist-reproducibility.rst.
I have not tested every possible tool combination, but in principle this should work. In general environment variables are inherited in subprocesses, but some tools may require you to explicitly allowlist these environment variables if they employ env var sanitisation.
Just to add a bit of context here, this has been many years in the making:
importlib.metadataandimportlib.resources(see discussion in Setuptools should not rely on pkg_resources #3085).pkg_resourcesin setuptools/PyPA channels reiterated its deprecated status and pointed to alternatives.pkg_resourceshad fundamental issues, with significant unintended side effects and known performance problems. Fixing these would have required dropping most of the API, and at that point it was basically as easy as deprecating the whole package.I understand that this require some effort, but it is good practice (and you possible can do it once and reuse elsewhere). Not only because of setuptools, but for any other dependency that you have. Tooling drift is a reality that everyone is subject to, so it is very good to have at least a side CI-job (outside the critical path, e.g. that run every 1 month) that will at least make some noise for warnings, so that you are prepared when the final changes come.
fix: install ghapi from wheel to work around setuptools 82 dropping p…
stephenfin commentedon Feb 10, 2026
Oh, I'm aware of
PIP_CONSTRAINT. However, there are issues with using this environment variable for testing, when the package under test is part of a global constraints file like OpenStack uses. This was the rationale for adding native constraints support to tox. The behavior ofPIP_CONSTRAINThas also changed significantly as of pip 25.3 with the introduction ofPIP_BUILD_CONSTRAINT, which is something people need to bear in mind, particularly for stable branches.I'm aware of the work that has gone in here, and I'm not dismissing any of the arguments in favour of its deprecation and replacement. However, deprecation != deprecation for removal.
optparsewas deprecated for 13 years (3.2 - 3.12). It wasn't deprecated for removal, and I don't believe anyone seriously considered removing it until perhaps PEP-594. PEP-594 in fact then led tooptparse's explicitly un-deprecation because "[a]lthough it has been deprecated for many years, it’s still too widely used to remove it" (per here. I don't see any reason to undeprecate pkg_resources, since it doesn't do anythingimportlib.metadatacan't, but I find it difficult to see howpkg_resourcesdoes not fall into the same camp with regards to its widespread use preventing removal.Once again, deprecation != deprecation for removal. It was only deprecated for removal less than 9 months ago.
Regarding the replacement,
importlib.metadatachanged its API quite significantly in the early days, and was provisional in 3.8 and 3.9. Even after being made non-provisional, there was significant change in 3.12 (iirc), which broke libraries I help maintain like stevedore. I certainly didn't consider it stable until quite recently, and I suspect we are all aware of similar criticism that came from some large figures in the Python community. While it may be stable now, thepkg_resourcesdeprecation was almost certainly premature given that its replacement wasn't stabilised until either Python 3.10 (October 2021) or Python 3.12 (October 2023), depending on your perspective.In addition, the removal of
pkg_resourcesindicates that we expect all consumers to have migrated across by now. Perhaps this is a fair assumption formain/masterbranches (though I suspect a lot of users of unmaintained by functional packages might disagree), but it wholly ignores maintained stable branches. Virtually all of OpenStack's stable branches are now broken since we only merged the final patches to multiple projects to removepkg_resourcesdependencies in the last release or two (@jaraco is aware of this to a degree, since he very helpfully communicated the need for these changes with pbr.Again, I'm not arguing against the deprecation of this package. I'm arguing against its removal, particularly in this manner (not tied to a Python release, for example).
I double checked this to ensure I wasn't missing something, but by default you don't see deprecation warnings when installing packages that rely on
pkg_resourcesat build-time. You only see these warnings at runtime. This is a large factor in why we (OpenStack) didn't rush its replacement in pbr more: we didn't see it.pip-install.log
Even if you did see these warnings, as an end-user of a package, you also have limited the ability to address their use of a deprecated
pkg_resourceslibrary.I appreciate what you're trying to say here, but I'll just reiterate what I said previously.
[-][BUG] Legacy build backend should continue making `pkg_resources` available[/-][+][BUG] Restore `pkg_resources`[/+]Pin setuptools to < 82.0
version stepping of dependencies
13 remaining items
Add setuptools<82 constraint due to pypa/setuptools#5174
Pin setuptools<82 in upper-constraints (#329)
Pin setuptools<82 in upper-constraints for stable/zed
Pin setuptools<82 in upper-constraints for stable/zed (#335)
ilaikim99 commentedon Feb 28, 2026
For those hitting broken builds after the setuptools 82 upgrade: constraint-based solutions exist that work with build isolation intact (no need for
--no-build-isolation). pip 25.3 introduced a dedicatedPIP_BUILD_CONSTRAINTenv var specifically for this scenario, and uv has abuild-constraint-dependenciesconfig option. Theimportlib.metadatamigration path (stdlib since Python 3.9) is also documented. you can find a full verified solution at https://cacheoverflow.dev/blog/HGrSBpg4fix: Use importlib.metadata instead of pkg_resources
fix: Use importlib.metadata instead of pkg_resources
fix: Use importlib.metadata instead of pkg_resources
fix: Use importlib.metadata instead of pkg_resources
pin setuptools<82
Pin setuptools<81 for razorpay pkg_resources import
Pin setuptools<81 for razorpay pkg_resources import
python3-pkg-resources: add for PX4's libuavcan DSDL compiler
Pin cltk==1.1.7 in venv setup instructions.
python3-pkg-resources: add for PX4's libuavcan DSDL compiler