Because of the build time of cockpit I don't have a full build log yet, but before the timeout, there was at least one error associated with Python 3.14 - see below. + /usr/bin/pytest /usr/lib/python3.14/site-packages/pytest_asyncio/plugin.py:208: PytestDeprecationWarning: The configuration option "asyncio_default_fixture_loop_scope" is unset. The event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: "function", "class", "module", "package", "session" warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET)) ============================= test session starts ============================== platform linux -- Python 3.14.0a5, pytest-8.3.4, pluggy-1.5.0 rootdir: /builddir/build/BUILD/cockpit-334-build/cockpit-334 configfile: pyproject.toml testpaths: test/pytest plugins: asyncio-0.24.0, timeout-2.3.1 asyncio: mode=Mode.STRICT, default_loop_scope=None collected 150 items test/pytest/test_beiboot.py::test_bridge_beiboot ERROR [ 0%] -------------------------------- live log call --------------------------------- ERROR asyncio:base_events.py:1868 Exception in callback BusMessage.reply_method_function_return_value.<locals>.<lambda>() at /builddir/build/BUILD/cockpit-334-build/cockpit-334/src/cockpit/_vendor/systemd_ctypes/bus.py:202 handle: <Handle BusMessage.reply_method_function_return_value.<locals>.<lambda>() at /builddir/build/BUILD/cockpit-334-build/cockpit-334/src/cockpit/_vendor/systemd_ctypes/bus.py:202> Traceback (most recent call last): File "/usr/lib64/python3.14/asyncio/events.py", line 98, in _run self._context.run(self._callback, *self._args) ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/builddir/build/BUILD/cockpit-334-build/cockpit-334/src/cockpit/_vendor/systemd_ctypes/bus.py", line 202, in <lambda> task.add_done_callback(lambda task: self._coroutine_task_complete(out_type, task)) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^ File "/builddir/build/BUILD/cockpit-334-build/cockpit-334/src/cockpit/_vendor/systemd_ctypes/bus.py", line 177, in _coroutine_task_complete self.reply_method_function_return_value(out_type, task.result()) ~~~~~~~~~~~^^ File "/builddir/build/BUILD/cockpit-334-build/cockpit-334/src/cockpit/superuser.py", line 241, in start await self.go(name, self) File "/builddir/build/BUILD/cockpit-334-build/cockpit-334/src/cockpit/superuser.py", line 189, in go await self.peer.start(init_host=self.router.init_host) File "/builddir/build/BUILD/cockpit-334-build/cockpit-334/src/cockpit/peer.py", line 100, in start init_message = await self.init_future ^^^^^^^^^^^^^^^^^^^^^^ File "/builddir/build/BUILD/cockpit-334-build/cockpit-334/src/cockpit/peer.py", line 84, in _connect_task_done task.result() ~~~~~~~~~~~^^ File "/builddir/build/BUILD/cockpit-334-build/cockpit-334/src/cockpit/superuser.py", line 76, in do_connect_transport transport = await self.spawn(self.args, env, stderr=agent, start_new_session=True) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/builddir/build/BUILD/cockpit-334-build/cockpit-334/src/cockpit/peer.py", line 62, in spawn return SubprocessTransport(loop, self, argv, env=dict(os.environ, **user_env), **kwargs) File "/builddir/build/BUILD/cockpit-334-build/cockpit-334/src/cockpit/transports.py", line 405, in __init__ self._get_watcher(loop).add_child_handler(self._process.pid, self._exited) ~~~~~~~~~~~~~~~~~^^^^^^ File "/builddir/build/BUILD/cockpit-334-build/cockpit-334/src/cockpit/transports.py", line 330, in _get_watcher watcher = SubprocessTransport._create_watcher() File "/builddir/build/BUILD/cockpit-334-build/cockpit-334/src/cockpit/transports.py", line 322, in _create_watcher return asyncio.SafeChildWatcher() ^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib64/python3.14/asyncio/__init__.py", line 65, in __getattr__ raise AttributeError(f"module {__name__!r} has no attribute {name!r}") AttributeError: module 'asyncio' has no attribute 'SafeChildWatcher' According to https://docs.python.org/dev/whatsnew/3.14.html: Remove the following classes and functions. They were all deprecated and emitted deprecation warnings since Python 3.12: asyncio.get_child_watcher() asyncio.set_child_watcher() asyncio.AbstractEventLoopPolicy.get_child_watcher() asyncio.AbstractEventLoopPolicy.set_child_watcher() asyncio.AbstractChildWatcher asyncio.FastChildWatcher asyncio.MultiLoopChildWatcher asyncio.PidfdChildWatcher asyncio.SafeChildWatcher asyncio.ThreadedChildWatcher (Contributed by Kumar Aditya in gh-120804.) The testing takes place in Copr, where you can see the previous attempts to build the package. https://copr.fedorainfracloud.org/coprs/g/python/python3.14/package/cockpit/ I'll try to make a full build with full log, and be back here in a few days. Reproducible: Always
The root cause of this issue is the removal of PidfdChildWatcher in https://github.com/python/cpython/pull/120893 The code in question only falls back to trying to use SafeChildWatcher if PidfdChildWatcher is not present: @staticmethod def _create_watcher() -> asyncio.AbstractChildWatcher: try: os.close(os.pidfd_open(os.getpid(), 0)) # check for kernel support return asyncio.PidfdChildWatcher() except (AttributeError, OSError): pass return asyncio.SafeChildWatcher() This was a public API, documented in the official documentation, and not deprecated nor officially slated for removal. https://docs.python.org/3/library/asyncio-policy.html#asyncio.PidfdChildWatcher
I just filed https://github.com/python/cpython/issues/130915 Hopefully they can change this before the release.
The Python asyncio maintainer has just indicated (in the linked bug report) that dropping a public documented symbol from one release to the next without deprecation or any other warning is "intended behavior". I think we're going to have to deal with this :(
I am currently looking into this, and I'm stumped how the API is actually supposed to work in current Python (i.e. >= 3.12): - https://docs.python.org/3/whatsnew/3.12.html#asyncio and https://github.com/python/cpython/issues/130915#issuecomment-2704219327 mention that the entire child watcher API is deprecated. - https://docs.python.org/3.13/library/asyncio-policy.html#process-watchers also has everything deprecated, i.e. it doesn't mention any current API - So maybe this cannot be used with arbitrary processes any more, but just with the "Process" class that asyncio.create_subprocess_exec() returns? But https://docs.python.org/3.13/library/asyncio-subprocess.html#asyncio.subprocess.Process *also* doesn't have anything like "invoke this callback then the process exits". The only thing it has is `async wait`, which could possibly be run in a task?
I proposed a fix upstream, can someone please have a look and/or test it? https://github.com/cockpit-project/cockpit/pull/21787
We now have a fix in https://github.com/cockpit-project/cockpit/pull/21775 which will land soon. Thanks Victor! Looking forward to the upstream discussion, maybe they can expose the watcher property as API.