python-trio fails to build with Python 3.13.0a1. This report is automated and not very verbose, but we'll try to get back here with details. + /usr/bin/pytest trio/_core/tests -k 'not test_nursery_cancel_doesnt_create_cyclic_garbage' ImportError while loading conftest '/builddir/build/BUILD/trio-0.22.0/trio/_core/tests/conftest.py'. trio/__init__.py:70: in <module> from ._path import Path trio/_path.py:134: in <module> class Path(metaclass=AsyncAutoWrapperType): trio/_path.py:85: in __init__ type(cls).generate_forwards(cls, attrs) trio/_path.py:102: in generate_forwards raise TypeError(attr_name, type(attr)) E TypeError: ('pathmod', <class 'module'>) https://docs.python.org/3.13/whatsnew/3.13.html For the build logs, see: https://copr-be.cloud.fedoraproject.org/results/@python/python3.13/fedora-rawhide-x86_64/06559373-python-trio/ For all our attempts to build python-trio with Python 3.13, see: https://copr.fedorainfracloud.org/coprs/g/python/python3.13/package/python-trio/ Testing and mass rebuild of packages is happening in copr. You can follow these instructions to test locally in mock if your package builds with Python 3.13: https://copr.fedorainfracloud.org/coprs/g/python/python3.13/ Let us know here if you have any questions. Python 3.13 is planned to be included in Fedora 41. To make that update smoother, we're building Fedora packages with all pre-releases of Python 3.13. A build failure prevents us from testing all dependent packages (transitive [Build]Requires), so if this package is required a lot, it's important for us to get it fixed soon. We'd appreciate help from the people who know this package best, but if you don't want to work on this now, let us know so we can try to work around it on our side.
With the current python-trio from Rawhide the failure is slightly different: + /usr/bin/pytest --pyargs trio -p trio._tests.pytest_plugin --verbose --skip-optional-imports Traceback (most recent call last): File "/usr/bin/pytest", line 8, in <module> sys.exit(console_main()) ^^^^^^^^^^^^^^ File "/usr/lib/python3.13/site-packages/_pytest/config/__init__.py", line 192, in console_main code = main() ^^^^^^ File "/usr/lib/python3.13/site-packages/_pytest/config/__init__.py", line 150, in main config = _prepareconfig(args, plugins) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.13/site-packages/_pytest/config/__init__.py", line 331, in _prepareconfig config = pluginmanager.hook.pytest_cmdline_parse( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.13/site-packages/pluggy/_hooks.py", line 493, in __call__ return self._hookexec(self.name, self._hookimpls, kwargs, firstresult) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.13/site-packages/pluggy/_manager.py", line 115, in _hookexec return self._inner_hookexec(hook_name, methods, kwargs, firstresult) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.13/site-packages/pluggy/_callers.py", line 130, in _multicall teardown[0].send(outcome) File "/usr/lib/python3.13/site-packages/_pytest/helpconfig.py", line 104, in pytest_cmdline_parse config: Config = outcome.get_result() ^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.13/site-packages/pluggy/_result.py", line 114, in get_result raise exc.with_traceback(exc.__traceback__) File "/usr/lib/python3.13/site-packages/pluggy/_callers.py", line 77, in _multicall res = hook_impl.function(*args) ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.13/site-packages/_pytest/config/__init__.py", line 1075, in pytest_cmdline_parse self.parse(args) File "/usr/lib/python3.13/site-packages/_pytest/config/__init__.py", line 1425, in parse self._preparse(args, addopts=addopts) File "/usr/lib/python3.13/site-packages/_pytest/config/__init__.py", line 1301, in _preparse self.pluginmanager.consider_preparse(args, exclude_only=False) File "/usr/lib/python3.13/site-packages/_pytest/config/__init__.py", line 709, in consider_preparse self.consider_pluginarg(parg) File "/usr/lib/python3.13/site-packages/_pytest/config/__init__.py", line 735, in consider_pluginarg self.import_plugin(arg, consider_entry_points=True) File "/usr/lib/python3.13/site-packages/_pytest/config/__init__.py", line 781, in import_plugin __import__(importspec) File "/builddir/build/BUILDROOT/python-trio-0.23.1-1.fc40.x86_64/usr/lib/python3.13/site-packages/trio/__init__.py", line 77, in <module> from ._path import Path as Path File "/builddir/build/BUILDROOT/python-trio-0.23.1-1.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_path.py", line 201, in <module> class Path(metaclass=AsyncAutoWrapperType): File "/builddir/build/BUILDROOT/python-trio-0.23.1-1.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_path.py", line 145, in __init__ type(cls).generate_forwards(cls, attrs) File "/builddir/build/BUILDROOT/python-trio-0.23.1-1.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_path.py", line 162, in generate_forwards raise TypeError(attr_name, type(attr)) TypeError: ('pathmod', <class 'module'>)
I built trio with this change locally in mock: https://github.com/python-trio/trio/pull/2918 Tests run now, but 8 of them fail. =================================== FAILURES =================================== ___________________ test_compare_async_stat_methods[is_dir] ____________________ method_name = 'is_dir' @pytest.mark.parametrize("method_name", ["is_dir", "is_file"]) async def test_compare_async_stat_methods(method_name: str) -> None: > method, async_method = method_pair(".", method_name) ../../BUILDROOT/python-trio-0.23.1-4.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_tests/test_path.py:119: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../../BUILDROOT/python-trio-0.23.1-4.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_tests/test_path.py:26: in method_pair return getattr(sync_path, method_name), getattr(async_path, method_name) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = trio.Path('.'), name = 'is_dir' def __getattr__(self, name): if name in self._forward: value = getattr(self._wrapped, name) return rewrap_path(value) > raise AttributeError(name) E AttributeError: is_dir ../../BUILDROOT/python-trio-0.23.1-4.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_path.py:236: AttributeError ___________________ test_compare_async_stat_methods[is_file] ___________________ method_name = 'is_file' @pytest.mark.parametrize("method_name", ["is_dir", "is_file"]) async def test_compare_async_stat_methods(method_name: str) -> None: > method, async_method = method_pair(".", method_name) ../../BUILDROOT/python-trio-0.23.1-4.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_tests/test_path.py:119: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../../BUILDROOT/python-trio-0.23.1-4.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_tests/test_path.py:26: in method_pair return getattr(sync_path, method_name), getattr(async_path, method_name) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = trio.Path('.'), name = 'is_file' def __getattr__(self, name): if name in self._forward: value = getattr(self._wrapped, name) return rewrap_path(value) > raise AttributeError(name) E AttributeError: is_file ../../BUILDROOT/python-trio-0.23.1-4.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_path.py:236: AttributeError _________________________ test_forward_methods_rewrap __________________________ path = trio.Path('/tmp/pytest-of-mockbuild/pytest-0/test_forward_methods_rewrap0/test') tmp_path = PosixPath('/tmp/pytest-of-mockbuild/pytest-0/test_forward_methods_rewrap0') async def test_forward_methods_rewrap(path: trio.Path, tmp_path: pathlib.Path) -> None: with_name = path.with_name("foo") > with_suffix = path.with_suffix(".py") ../../BUILDROOT/python-trio-0.23.1-4.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_tests/test_path.py:145: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = trio.Path('/tmp/pytest-of-mockbuild/pytest-0/test_forward_methods_rewrap0/test') name = 'with_suffix' def __getattr__(self, name): if name in self._forward: value = getattr(self._wrapped, name) return rewrap_path(value) > raise AttributeError(name) E AttributeError: with_suffix ../../BUILDROOT/python-trio-0.23.1-4.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_path.py:236: AttributeError _____________________ test_forward_methods_without_rewrap ______________________ path = trio.Path('/tmp/pytest-of-mockbuild/pytest-0/test_forward_methods_without_r0') async def test_forward_methods_without_rewrap(path: trio.Path) -> None: path = await path.parent.resolve() > assert path.as_uri().startswith("file:///") E AttributeError: 'coroutine' object has no attribute 'startswith' ../../BUILDROOT/python-trio-0.23.1-4.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_tests/test_path.py:160: AttributeError _______________________________ test_globmethods _______________________________ path = trio.Path('/tmp/pytest-of-mockbuild/pytest-0/test_globmethods0/test') async def test_globmethods(path: trio.Path) -> None: # Populate a directory tree await path.mkdir() await (path / "foo").mkdir() > await (path / "foo" / "_bar.txt").write_bytes(b"") ../../BUILDROOT/python-trio-0.23.1-4.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_tests/test_path.py:231: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = trio.Path('/tmp/pytest-of-mockbuild/pytest-0/test_globmethods0/test/foo/_bar.txt') name = 'write_bytes' def __getattr__(self, name): if name in self._forward: value = getattr(self._wrapped, name) return rewrap_path(value) > raise AttributeError(name) E AttributeError: write_bytes. Did you mean: 'write_text'? ../../BUILDROOT/python-trio-0.23.1-4.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_path.py:236: AttributeError _________________________________ test_iterdir _________________________________ path = trio.Path('/tmp/pytest-of-mockbuild/pytest-0/test_iterdir0/test') async def test_iterdir(path: trio.Path) -> None: # Populate a directory await path.mkdir() await (path / "foo").mkdir() > await (path / "bar.txt").write_bytes(b"") ../../BUILDROOT/python-trio-0.23.1-4.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_tests/test_path.py:260: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = trio.Path('/tmp/pytest-of-mockbuild/pytest-0/test_iterdir0/test/bar.txt') name = 'write_bytes' def __getattr__(self, name): if name in self._forward: value = getattr(self._wrapped, name) return rewrap_path(value) > raise AttributeError(name) E AttributeError: write_bytes. Did you mean: 'write_text'? ../../BUILDROOT/python-trio-0.23.1-4.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_path.py:236: AttributeError ______________________________ test_classmethods _______________________________ async def test_classmethods() -> None: > assert isinstance(await trio.Path.home(), trio.Path) E AttributeError: type object 'Path' has no attribute 'home' ../../BUILDROOT/python-trio-0.23.1-4.fc40.x86_64/usr/lib/python3.13/site-packages/trio/_tests/test_path.py:271: AttributeError _______________________ test_timeouts_raise_value_error ________________________ cls = <class '_pytest.runner.CallInfo'> func = <function call_runtest_hook.<locals>.<lambda> at 0x7f3b396119e0> when = 'call' reraise = (<class '_pytest.outcomes.Exit'>, <class 'KeyboardInterrupt'>) @classmethod def from_call( cls, func: "Callable[[], TResult]", when: "Literal['collect', 'setup', 'call', 'teardown']", reraise: Optional[ Union[Type[BaseException], Tuple[Type[BaseException], ...]] ] = None, ) -> "CallInfo[TResult]": """Call func, wrapping the result in a CallInfo. :param func: The function to call. Called without arguments. :param when: The phase in which the function is called. :param reraise: Exception or exceptions that shall propagate if raised by the function, instead of being wrapped in the CallInfo. """ excinfo = None start = timing.time() precise_start = timing.perf_counter() try: > result: Optional[TResult] = func() /usr/lib/python3.13/site-packages/_pytest/runner.py:341: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.13/site-packages/_pytest/runner.py:262: in <lambda> lambda: ihook(item=item, **kwds), when=when, reraise=reraise /usr/lib/python3.13/site-packages/pluggy/_hooks.py:493: in __call__ return self._hookexec(self.name, self._hookimpls, kwargs, firstresult) /usr/lib/python3.13/site-packages/pluggy/_manager.py:115: in _hookexec return self._inner_hookexec(hook_name, methods, kwargs, firstresult) /usr/lib/python3.13/site-packages/_pytest/unraisableexception.py:88: in pytest_runtest_call yield from unraisable_exception_runtest_hook() _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ def unraisable_exception_runtest_hook() -> Generator[None, None, None]: with catch_unraisable_exception() as cm: yield if cm.unraisable: if cm.unraisable.err_msg is not None: err_msg = cm.unraisable.err_msg else: err_msg = "Exception ignored in" msg = f"{err_msg}: {cm.unraisable.object!r}\n\n" msg += "".join( traceback.format_exception( cm.unraisable.exc_type, cm.unraisable.exc_value, cm.unraisable.exc_traceback, ) ) > warnings.warn(pytest.PytestUnraisableExceptionWarning(msg)) E pytest.PytestUnraisableExceptionWarning: Exception ignored in: <coroutine object Path.as_uri at 0x7f3b393ba140> E E Traceback (most recent call last): E File "/usr/lib64/python3.13/warnings.py", line 688, in _warn_unawaited_coroutine E warn(msg, category=RuntimeWarning, stacklevel=2, source=coro) E ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E RuntimeWarning: coroutine 'Path.as_uri' was never awaited /usr/lib/python3.13/site-packages/_pytest/unraisableexception.py:78: PytestUnraisableExceptionWarning =========================== short test summary info ============================ FAILED _tests/test_path.py::test_compare_async_stat_methods[is_dir] - Attribu... FAILED _tests/test_path.py::test_compare_async_stat_methods[is_file] - Attrib... FAILED _tests/test_path.py::test_forward_methods_rewrap - AttributeError: wit... FAILED _tests/test_path.py::test_forward_methods_without_rewrap - AttributeEr... FAILED _tests/test_path.py::test_globmethods - AttributeError: write_bytes. D... FAILED _tests/test_path.py::test_iterdir - AttributeError: write_bytes. Did y... FAILED _tests/test_path.py::test_classmethods - AttributeError: type object '... FAILED _tests/test_timeouts.py::test_timeouts_raise_value_error - pytest.Pyte... ================== 8 failed, 579 passed, 75 skipped in 4.26s ===================
This bug appears to have been reported against 'rawhide' during the Fedora Linux 40 development cycle. Changing version to 40.
Support for Python 3.13 was added in trio 0.25, which requires anyio to be updated to version 4, but we've got some packages which requires anyio < 4 in Fedora: python-fastapi.src : (python3dist(anyio) < 4~~ with python3dist(anyio) >= 3.2.1) python-sentry-sdk.src : python3dist(anyio) < 4~~ python-watchgod.src : (python3dist(anyio) < 4~~ with python3dist(anyio) >= 3)
FastAPI should actually be OK with anyio 4 at runtime: it’s used only in fastapi.concurrency, and the dependency is indirect via Starlette, which *does* support anyio 4. The upper-bound "anyio[trio] >=3.2.1,<4.0.0" is in requirements-tests.txt, and it’s very likely that it can be removed once trio supports anyio; if not, it is very likely that any tests with problems are simple enough to patch. I’m happy to test it against a PR or a COPR with trio 0.25 and anyio 4. See https://src.fedoraproject.org/rpms/python-anyio/pull-request/9, where I tried to get anyio updated to 4.x but there were just too many things not ready at the time. In https://src.fedoraproject.org/rpms/python-anyio/pull-request/9#comment-181751, Carl George indicated he would be happy to retire python-watchgod if it can’t be easily made to work with anyio 4, since it’s been replaced upstream by python-watchfiles anyway. I don’t know python-sentry-sdk as well, but it doesn’t use anyio directly, and the version bound was added over six months ago “because new major 4.0.0 breaks tests.” It would be worth checking if current dependency versions have made this bound unnecessary too.
Please check https://src.fedoraproject.org/rpms/python-trio/pull-request/6 and https://src.fedoraproject.org/rpms/python-anyio/pull-request/9 for a current analysis. The number of packages blocking anyio 4 and trio 0.25 is now very small. I don’t have any concrete plans for further work on this in the immediate future, but please let me know if there *is* something I can do to help.
We might need to backport https://github.com/python-trio/trio/pull/2955 if we cannot update.
I've meant https://github.com/python-trio/trio/pull/2959 (2955 does not work)
Looking into it.
https://src.fedoraproject.org/rpms/python-trio/pull-request/7 backports that Path refactor but there are more failures, reported upstream as https://github.com/python-trio/trio/issues/3004