Skip to content

Conversation

@musicinmybrain
Copy link
Contributor

Summary

In Python 3.14, asyncio.events.BaseDefaultEventLoopPolicy, which was always a private/undocumented API, was renamed with a leading underscore. See python/cpython#131148.

This PR adapts test_loop_auto, which contains a type check against this undocumented type, to support either name depending on the interpreter version, fixing failures like the following on Python 3.14:

________________________________ test_loop_auto ________________________________

    def test_loop_auto():
        auto_loop_setup()
        policy = asyncio.get_event_loop_policy()
>       assert isinstance(policy, asyncio.events.BaseDefaultEventLoopPolicy)
E       AttributeError: module 'asyncio.events' has no attribute 'BaseDefaultEventLoopPolicy'

tests/test_auto_detection.py:38: AttributeError

Checklist

  • I understand that this PR may be closed in case there was no previous discussion. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change. (The change was to a test, so no new test was required.)
  • I've updated the documentation accordingly. (No documentation changes were needed.)

In Python 3.14, asyncio.events.BaseDefaultEventLoopPolicy, which was
always a private/undocumented API, was renamed with a leading
underscore. See python/cpython#131148.
This is probably less clear than the previous implementation, but it
should achieve the artificial metric of 100% test-line coverage.
@musicinmybrain musicinmybrain force-pushed the BaseDefaultEventLoopPolicy branch from c1cbd7f to 4287e25 Compare June 27, 2025 02:46
@Kludex
Copy link
Owner

Kludex commented Jul 2, 2025

I'll close this PR since we remove that logic from master.

Does master still fail on 3.14?

@Kludex Kludex closed this Jul 2, 2025
@musicinmybrain
Copy link
Contributor Author

I'll close this PR since we remove that logic from master.

Does master still fail on 3.14?

It’s a bit awkward to test the Fedora package right now, as we’re in the middle of a datacenter move for Fedora infrastructure, but in a quick trial in a git checkout:

$ uv venv --python 3.14
$ . .venv/bin/activate
(uvicorn) $ uv pip install -r requirements.txt
(uvicorn) $ pytest -W 'ignore::DeprecationWarning'
======================================== test session starts =========================================
platform linux -- Python 3.14.0b3, pytest-8.3.5, pluggy-1.6.0
rootdir: /home/ben/src/forks/uvicorn
configfile: pyproject.toml
plugins: anyio-4.9.0, xdist-3.6.1, mock-3.14.0
8 workers [930 items]   
.............................................................................................. [ 10%]
.............................................................................................. [ 20%]
.............................................................................................. [ 30%]
.............................................................................................. [ 40%]
.............................................................................................. [ 50%]
.............................................................................................. [ 60%]
.............................................................................ss............... [ 70%]
...............ss.........................ss........F......................................... [ 80%]
.............................................................................................. [ 90%]
...............................................................................s....           [100%]
============================================== FAILURES ==============================================
_______________ test_asyncio_run__passing_a_non_awaitable_callback_should_throw_error ________________
[gw1] linux -- Python 3.14.0 /home/ben/src/forks/uvicorn/.venv/bin/python3

    def test_asyncio_run__passing_a_non_awaitable_callback_should_throw_error() -> None:
        with pytest.raises(ValueError):
>           asyncio_run(
                lambda: None,  # type: ignore
                loop_factory=CustomLoop,
            )

tests/test_compat.py:27:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib64/python3.14/asyncio/runners.py:204: in run
    return runner.run(main)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <asyncio.runners.Runner object at 0x7f970d0ce2d0>
coro = <function test_asyncio_run__passing_a_non_awaitable_callback_should_throw_error.<locals>.<lambda> at 0x7f970d0bb060>

    def run(self, coro, *, context=None):
        """Run code in the embedded event loop."""
        if events._get_running_loop() is not None:
            # fail fast with short traceback
            raise RuntimeError(
                "Runner.run() cannot be called from a running event loop")

        self._lazy_init()

        if not coroutines.iscoroutine(coro):
            if inspect.isawaitable(coro):
                async def _wrap_awaitable(awaitable):
                    return await awaitable

                coro = _wrap_awaitable(coro)
            else:
>               raise TypeError('An asyncio.Future, a coroutine or an '
                                'awaitable is required')
E               TypeError: An asyncio.Future, a coroutine or an awaitable is required

/usr/lib64/python3.14/asyncio/runners.py:103: TypeError
====================================== short test summary info =======================================
SKIPPED [2] tests/protocols/test_websocket.py:948: WebSocketsSansIOProtocol sends both start and body messages in one message.
SKIPPED [2] tests/protocols/test_websocket.py:986: WebSocketsSansIOProtocol sends both start and body messages in one message.
SKIPPED [2] tests/protocols/test_websocket.py:914: WebSocketsSansIOProtocol sends both start and body messages in one message.
SKIPPED [1] tests/supervisors/test_multiprocess.py:110: platform unsupports SIGBREAK
============================= 1 failed, 922 passed, 7 skipped in 22.98s ==============================

The -W 'ignore::DeprecationWarning' avoids hundreds of test failures mostly due to what should be an easy fix:

E           DeprecationWarning: 'asyncio.iscoroutinefunction' is deprecated and slated for removal in Python 3.16; use inspect.iscoroutinefunction() instead

So it looks like at least in a virtualenv, there’s just one “real” regression in Python 3.14.0b3. Results might be a little different in Fedora due to things like different dependency versions.

@musicinmybrain
Copy link
Contributor Author

The -W 'ignore::DeprecationWarning' avoids hundreds of test failures mostly due to what should be an easy fix:

E           DeprecationWarning: 'asyncio.iscoroutinefunction' is deprecated and slated for removal in Python 3.16; use inspect.iscoroutinefunction() instead

#2659

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants