The version 3.0.2 installs the following entry points:
[setuptools.finalize_distribution_options] description_fields = util.packaging:derive_dist_description maintainer = util.packaging:derive_maintainer version = util.packaging:derive_version
However, the util package is not installed to the system (and shouldn't be). As a result, once python-daemon is installed, it is no longer possible to build anything using setuptools, as it is attempting to load the plugins:
util
# python3.12 -m build --no-iso * Getting build dependencies for sdist... Traceback (most recent call last): File "/usr/lib/python3.12/site-packages/pyproject_hooks/_in_process/_in_process.py", line 373, in <module> main() File "/usr/lib/python3.12/site-packages/pyproject_hooks/_in_process/_in_process.py", line 357, in main json_out["return_val"] = hook(**hook_input["kwargs"]) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/site-packages/pyproject_hooks/_in_process/_in_process.py", line 308, in get_requires_for_build_sdist return hook(config_settings) ^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/site-packages/setuptools/build_meta.py", line 330, in get_requires_for_build_sdist return self._get_build_requires(config_settings, requirements=[]) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/site-packages/setuptools/build_meta.py", line 297, in _get_build_requires self.run_setup() File "/usr/lib/python3.12/site-packages/setuptools/build_meta.py", line 313, in run_setup exec(code, locals()) File "<string>", line 1, in <module> File "/usr/lib/python3.12/site-packages/setuptools/__init__.py", line 108, in setup return distutils.core.setup(**attrs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/site-packages/setuptools/_distutils/core.py", line 146, in setup _setup_distribution = dist = klass(attrs) ^^^^^^^^^^^^ File "/usr/lib/python3.12/site-packages/setuptools/dist.py", line 289, in __init__ _Distribution.__init__(self, dist_attrs) File "/usr/lib/python3.12/site-packages/setuptools/_distutils/dist.py", line 286, in __init__ self.finalize_options() File "/usr/lib/python3.12/site-packages/setuptools/dist.py", line 640, in finalize_options for ep in sorted(loaded, key=by_order): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/site-packages/setuptools/dist.py", line 639, in <lambda> loaded = map(lambda e: e.load(), filtered) ^^^^^^^^ File "/usr/lib/python3.12/importlib/metadata/__init__.py", line 205, in load module = import_module(match.group('module')) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/importlib/__init__.py", line 90, in import_module return _bootstrap._gcd_import(name[level:], package, level) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "<frozen importlib._bootstrap>", line 1387, in _gcd_import File "<frozen importlib._bootstrap>", line 1360, in _find_and_load File "<frozen importlib._bootstrap>", line 1310, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed File "<frozen importlib._bootstrap>", line 1387, in _gcd_import File "<frozen importlib._bootstrap>", line 1360, in _find_and_load File "<frozen importlib._bootstrap>", line 1324, in _find_and_load_unlocked ModuleNotFoundError: No module named 'util' ERROR Backend subprocess exited when trying to invoke get_requires_for_build_sdist
Please yank the release because it completely breaks the environment after upgrading, and it is non-trivial to figure out what the cause is.
I can confirm that this breaks a lot of things. python-daemon is a dependency of ansible-runner, and when building Ansible Execution Environments, ansible-builder installs ansible-runner without allowing to specify any constraints, so basically every Ansible Execution Environment build gets python-daemon 3.0.2. And then once pip installs something that uses setup.py / setup.cfg, this bug stops the build. (Which in my case is only making CI red and not breaking anything in production: https://github.com/ansible-collections/community.routeros/actions/runs/10121136568)
Yanking 3.0.2 or fixing this ASAP would be very much appreciated :)
As a result, once python-daemon is installed, it is no longer possible to build anything using setuptools, as it is attempting to load the plugins
:cry: "Stop Setuptools from ever becoming so weird and fragile" is getting higher on my list of important uses for a time machine.
I have now yanked from PyPI the ‘python-daemon’ version “3.0.2” release.
I will keep this bug report open as we figure out a way to achieve the goals of these plug-ins, without breaking everyone's Setuptools.
Metadata Update from @bignose: - Issue assigned to bignose - Issue tagged with: confirmed, help-wanted
I have discussed ways to achieve the "derive distribution options at build time" goal, at discuss.python.org: Dynamic metadata populated by entry-points
but the implementation I came up with got us into this mess. I'll appreciate help to move to a better implementation that meets my goals for these functions.
Hi there, I would recommend moving all static metadata into pyproject.toml and let setup.py contain just the dynamic parts (which is also what the setuptools maintainer recommended here)
pyproject.toml
setup.py
setuptools
It would look like this: https://github.com/branchvincent/python-daemon/commit/23833185b9d0cd307b13d9ce5a774113cdc0bd53. Feel free to take as much or as little as you want from that diff or lmk if anything is unclear and I'm happy to explain in further detail (I would have made a pull request but for some reason pagure is rejecting my git push attempts)
Thank you @branchv. It's unfortunate you can't get your changes into Pagure for a merge request here? I hope you can get some success with that.
I would recommend moving all static metadata into pyproject.toml and let setup.py contain just the dynamic parts
Yes, that is the intention of the branch wip/maintenance/pyproject, addressing the requirements in this issue.
lmk if anything is unclear and I'm happy to explain in further detail
I see that your change implements many of the changes in the branch mentioned above; this is a good sign we're pulling in the same direction.
Unfortunately, I see you have modified some of the functions that deliberately get the ChangeLog file from the Distribution object, changing them to instead expect a static filesystem path for the ChangeLog file.
So, that doesn't satisfy the need to get this information from the Distribution object.
The changes you've implemented, expect the ChangeLog to be at a known static filesystem path. But the ChangeLog location is, at run time, only to be known by interrogating the Distribution object, because that's the object holding information for the specific environment where this distribution is installed.
Admittedly, that (getting this interrogation to work both at build time and at run time) is one aspect holding up implementing a fix for this issue.
Ah that's great, agreed!
I see, can you clarify this need and the motivation behind it? By runtime, do you mean at runtime for your end users or just during development? From my initial look at this issue, I must have misread the question as "How can I tell setuptools at build time about my dynamically-derived distribution metadata".
The changes you've implemented, expect the ChangeLog to be at a known static filesystem path. But the ChangeLog location is, at run time, only to be known by interrogating the Distribution object
Yes, the expectation is that your sdist and wheel are immutable after they are built and uploaded to PyPI. An sdist may have dynamic metadata but once built into a wheel and installed, the fully resolved metadata is written to disk in a METADATA file. For example, for the yanked release:
METADATA
$ uv venv && uv pip install --no-binary=python-daemon python-daemon==3.0.2 $ grep ^Version .venv/lib/python3.*/site-packages/python_daemon-3.0.2.dist-info/METADATA Version: 3.0.2 $ cat .venv/lib/python3.*/site-packages/python_daemon-3.0.2.dist-info/RECORD daemon/__init__.py,sha256=IiCxBMbNH3knrtWxmazfZUtrVwl6L2qnbWtYbdkEzsw,1665 daemon/_metadata.py,sha256=_IvsY6S8_tMD8l5Smffwr__LfMvA5vScgQbZgtdQh2I,1037 daemon/daemon.py,sha256=t9qiNXgrKI1Pm2LE0yTPI57YP4MGNaqTiqbWBOim3Bw,35324 daemon/pidfile.py,sha256=ab9Ja4x2gEVWLGx82sCcJ18GSik-lHWmSguXduJixLg,2186 python_daemon-3.0.2.dist-info/COPYING,sha256=cSNJE6wsokJsnzOFJMxnKyH7aiIAmRYG18_yWT-og98,1657 python_daemon-3.0.2.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2 python_daemon-3.0.2.dist-info/LICENSE.ASF-2,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358 python_daemon-3.0.2.dist-info/LICENSE.GPL-3,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147 python_daemon-3.0.2.dist-info/METADATA,sha256=w2jzuEXXSNQyvN91AmeRYSgjJnbTJzSnmrVLnlcn6mw,3131 python_daemon-3.0.2.dist-info/RECORD,, python_daemon-3.0.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 python_daemon-3.0.2.dist-info/WHEEL,sha256=Wyh-_nZ0DJYolHNn1_hMa4lM7uDedD_RGVwbmTjyItk,91 python_daemon-3.0.2.dist-info/entry_points.txt,sha256=im5-ox-L06PgBTwRZV6eNQtH9EQbmScaMUg9FXUf7cA,189 python_daemon-3.0.2.dist-info/top_level.txt,sha256=7tSe9oVFyd_dCLrotHDHVIQ6OAM26I6rF6ggOsDL0uk,7
So although your sdist intended for the version to be dynamic at runtime, it becomes resolved once installed (you can see the same is true for the description and maintainer fields here). Also note that the Changelog file is no longer present at runtime and has no need to be. But perhaps I'm missing something here.
sdist
version
Changelog
@branchv wrote:
By ["getting this interrogation to work both at build time and at run time"], do you mean at runtime for your end users or just during development?
Yes, at build time and at run time. The intention is:
Yes, the expectation is that your sdist and wheel are immutable after they are built and uploaded to PyPI.
Agreed.
To my understanding, the supported interface to interrogate the installed package from within a Python session, is to interrogate the Distribution object (of type setuptools.dist.Distribution) and read from there.
setuptools.dist.Distribution
So although your sdist intended for the version to be dynamic at runtime
The intention is to interrogate the package to discover its metadata, for those specific fields that are canonically recorded in ChangeLog. That is, the pyproject.toml is not the canonical record of this information, because that would be superfluous with the ChangeLog interface and risk one or the other being out of date.
ChangeLog
To my understanding, the way to make this happen is to tell the build system this is a "dynamic" metadata, because it's determined by an API call.
With the migration to 'changelog-chug' for interrogating the Change Log at build time, merged to the 'main' branch, this issue is now resolved.
Metadata Update from @bignose: - Issue close_status updated to: Fixed - Issue status updated to: Closed (was: Open)
Metadata Update from @bignose: - Issue untagged with: help-wanted