Skip to content

Commit

Permalink
fixes for 3.14
Browse files Browse the repository at this point in the history
  • Loading branch information
graingert committed Dec 30, 2024
1 parent fc81194 commit 7a84fd6
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 7 deletions.
5 changes: 5 additions & 0 deletions tests/test_auto_detection.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import asyncio
import contextlib
import importlib
import sys

import pytest

Expand All @@ -15,6 +16,10 @@
expected_loop = "uvloop" # pragma: py-win32
except ImportError: # pragma: py-not-win32
expected_loop = "asyncio"
except AttributeError:
if sys.version_info < (3, 14):
raise
expected_loop = "asyncio"

try:
importlib.import_module("httptools")
Expand Down
3 changes: 2 additions & 1 deletion tests/test_compat.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import asyncio
import sys
from asyncio import AbstractEventLoop

import pytest
Expand All @@ -23,7 +24,7 @@ def test_asyncio_run__custom_loop_factory() -> None:


def test_asyncio_run__passing_a_non_awaitable_callback_should_throw_error() -> None:
with pytest.raises(ValueError):
with pytest.raises(TypeError if sys.version_info >= (3, 14) else ValueError):
asyncio_run(
lambda: None, # type: ignore
loop_factory=CustomLoop,
Expand Down
7 changes: 7 additions & 0 deletions uvicorn/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
from collections.abc import Callable, Coroutine
from typing import Any, TypeVar

__all__ = ["asyncio_run", "iscoroutinefunction"]

if sys.version_info >= (3, 14):
from inspect import iscoroutinefunction
else:
from asyncio import iscoroutinefunction

_T = TypeVar("_T")

if sys.version_info >= (3, 12):
Expand Down
5 changes: 3 additions & 2 deletions uvicorn/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import click

from uvicorn._compat import iscoroutinefunction
from uvicorn._types import ASGIApplication
from uvicorn.importer import ImportFromStringError, import_from_string
from uvicorn.logging import TRACE_LOG_LEVEL
Expand Down Expand Up @@ -453,10 +454,10 @@ def load(self) -> None:
if inspect.isclass(self.loaded_app):
use_asgi_3 = hasattr(self.loaded_app, "__await__")
elif inspect.isfunction(self.loaded_app):
use_asgi_3 = asyncio.iscoroutinefunction(self.loaded_app)
use_asgi_3 = iscoroutinefunction(self.loaded_app)
else:
call = getattr(self.loaded_app, "__call__", None)
use_asgi_3 = asyncio.iscoroutinefunction(call)
use_asgi_3 = iscoroutinefunction(call)
self.interface = "asgi3" if use_asgi_3 else "asgi2"

if self.interface == "wsgi":
Expand Down
14 changes: 10 additions & 4 deletions uvicorn/loops/auto.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
from __future__ import annotations

import asyncio
import sys
from collections.abc import Callable


def auto_loop_factory(use_subprocess: bool = False) -> Callable[[], asyncio.AbstractEventLoop]:
def auto_loop_factory(use_subprocess: bool = False) -> Callable[[], asyncio.AbstractEventLoop]: # pragma: no cover
try:
import uvloop # noqa
except ImportError: # pragma: no cover
from uvicorn.loops.asyncio import asyncio_loop_factory as loop_factory

return loop_factory(use_subprocess=use_subprocess)
pass
except AttributeError: # pragma: no cover
if sys.version_info < (3, 14):
raise
else: # pragma: no cover
from uvicorn.loops.uvloop import uvloop_loop_factory

return uvloop_loop_factory(use_subprocess=use_subprocess)

from uvicorn.loops.asyncio import asyncio_loop_factory as loop_factory

return loop_factory(use_subprocess=use_subprocess)

0 comments on commit 7a84fd6

Please sign in to comment.