File py314.patch of Package python-uvicorn
From 208a37a4de8f2fd6697dc3eaf076bac7442f5628 Mon Sep 17 00:00:00 2001
From: Thomas Grainger <tagrain@gmail.com>
Date: Sat, 14 Oct 2023 11:48:19 +0100
Subject: [PATCH 01/19] use asyncio.run(..., loop_factory) to avoid
asyncio.set_event_loop_policy
---
tests/test_auto_detection.py | 11 ++---
uvicorn/_compat.py | 86 ++++++++++++++++++++++++++++++++++++
uvicorn/config.py | 17 +++----
uvicorn/loops/asyncio.py | 13 ++++--
uvicorn/loops/auto.py | 18 +++++---
uvicorn/loops/uvloop.py | 9 +++-
uvicorn/main.py | 4 +-
uvicorn/server.py | 4 +-
uvicorn/workers.py | 6 +--
9 files changed, 138 insertions(+), 30 deletions(-)
create mode 100644 uvicorn/_compat.py
Index: uvicorn-0.36.0/tests/test_auto_detection.py
===================================================================
--- uvicorn-0.36.0.orig/tests/test_auto_detection.py
+++ uvicorn-0.36.0/tests/test_auto_detection.py
@@ -1,6 +1,7 @@
import asyncio
import contextlib
import importlib
+import sys
import pytest
@@ -12,9 +13,14 @@ from uvicorn.server import ServerState
try:
importlib.import_module("uvloop")
- expected_loop = "uvloop" # pragma: py-win32
except ImportError: # pragma: py-not-win32
expected_loop = "asyncio"
+except AttributeError: # pragma: py-lt-314 # pragma: py-win32
+ if sys.version_info < (3, 14): # pragma: no cover
+ raise
+ expected_loop = "asyncio"
+else: # pragma: py-win32 # pragma: py-gte-314
+ expected_loop = "uvloop"
try:
importlib.import_module("httptools")
Index: uvicorn-0.36.0/uvicorn/_compat.py
===================================================================
--- uvicorn-0.36.0.orig/uvicorn/_compat.py
+++ uvicorn-0.36.0/uvicorn/_compat.py
@@ -5,6 +5,13 @@ import sys
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):
Index: uvicorn-0.36.0/uvicorn/config.py
===================================================================
--- uvicorn-0.36.0.orig/uvicorn/config.py
+++ uvicorn-0.36.0/uvicorn/config.py
@@ -16,6 +16,7 @@ from typing import IO, Any, Callable, Li
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
Index: uvicorn-0.36.0/uvicorn/loops/auto.py
===================================================================
--- uvicorn-0.36.0.orig/uvicorn/loops/auto.py
+++ uvicorn-0.36.0/uvicorn/loops/auto.py
@@ -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)
Index: uvicorn-0.36.0/pyproject.toml
===================================================================
--- uvicorn-0.36.0.orig/pyproject.toml
+++ uvicorn-0.36.0/pyproject.toml
@@ -25,6 +25,7 @@ classifiers = [
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
+ "Programming Language :: Python :: 3.14",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Internet :: WWW/HTTP",
@@ -160,6 +161,7 @@ exclude_lines = [
"tests/supervisors/test_multiprocess.py",
]
"sys_platform != 'win32'" = ["uvicorn/loops/asyncio.py"]
+"sys_version_info >= (3, 14)" = ["uvicorn/loops/uvloop.py"]
[tool.coverage.coverage_conditional_plugin.rules]
py-win32 = "sys_platform == 'win32'"
@@ -173,3 +175,5 @@ py-gte-310 = "sys_version_info >= (3, 10
py-lt-310 = "sys_version_info < (3, 10)"
py-gte-311 = "sys_version_info >= (3, 11)"
py-lt-311 = "sys_version_info < (3, 11)"
+py-gte-314 = "sys_version_info >= (3, 14)"
+py-lt-314 = "sys_version_info < (3, 14)"
Index: uvicorn-0.36.0/tests/test_compat.py
===================================================================
--- uvicorn-0.36.0.orig/tests/test_compat.py
+++ uvicorn-0.36.0/tests/test_compat.py
@@ -1,6 +1,7 @@
from __future__ import annotations
import asyncio
+import sys
from asyncio import AbstractEventLoop
import pytest
@@ -23,7 +24,7 @@ def test_asyncio_run__custom_loop_factor
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,