Skip to content

Commit a53ffa9

Browse files
committed
fix: suppress 3.14 DeprecationWarning in uvicorn thread + Windows Proactor GC warning
Two separate CI failures, both exposed by moving from subprocess to in-thread: Python 3.14 (hang → 10m timeout): pyproject.toml's filterwarnings=error is inherited by the server thread. On 3.14, uvicorn's config.load() calls asyncio.iscoroutinefunction which is deprecated, so the warning-turned-error kills the thread before it starts serving. Because we pre-bind the socket, the kernel listen queue still accepts connections — clients see ReadTimeout (~5m) instead of ConnectError. Fixed by catch_warnings inside the thread (thread-local since 3.12). Windows Proactor (flaky unraisable warning): force_exit skips graceful drain, so the Proactor's overlapped AcceptEx on the listening socket may not finish cancellation before the event loop is torn down. GC finds it pending during a later unrelated test. Previously hidden by subprocess isolation. Suppressed at module level — this is Windows asyncio internals, not a real leak.
1 parent 21a3979 commit a53ffa9

File tree

2 files changed

+21
-1
lines changed

2 files changed

+21
-1
lines changed

tests/shared/test_streamable_http.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@
6363
)
6464
from tests.test_helpers import run_uvicorn_in_thread
6565

66+
# When the in-thread uvicorn server force-exits, the Proactor's overlapped
67+
# AcceptEx on the listening socket may not finish cancellation before the
68+
# event loop is torn down; GC later finds it pending and pytest's unraisable
69+
# collector surfaces it during an unrelated test. Previously hidden by
70+
# subprocess isolation. This is Windows asyncio internals, not a real leak.
71+
pytestmark = pytest.mark.filterwarnings("ignore::pytest.PytestUnraisableExceptionWarning")
72+
6673
# Test constants
6774
SERVER_NAME = "test_streamable_http_server"
6875
TEST_SESSION_ID = "test-session-id-12345"

tests/test_helpers.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import socket
44
import threading
55
import time
6+
import warnings
67
from collections.abc import Generator
78
from contextlib import contextmanager
89
from typing import Any
@@ -74,7 +75,19 @@ def run_uvicorn_in_thread(app: Any, **config_kwargs: Any) -> Generator[str, None
7475

7576
config = uvicorn.Config(app=app, **config_kwargs)
7677
server = uvicorn.Server(config=config)
77-
thread = threading.Thread(target=server.run, args=([sock],), daemon=True)
78+
79+
def _run() -> None:
80+
# pyproject.toml sets filterwarnings=error, which is inherited by this
81+
# thread. On Python 3.14 uvicorn's config.load() triggers the
82+
# asyncio.iscoroutinefunction DeprecationWarning, killing the thread
83+
# before it starts serving — the pre-bound socket keeps accepting
84+
# connections into the kernel queue, so clients see ReadTimeout rather
85+
# than ConnectError. catch_warnings is thread-local since 3.12.
86+
with warnings.catch_warnings():
87+
warnings.simplefilter("ignore", DeprecationWarning)
88+
server.run(sockets=[sock])
89+
90+
thread = threading.Thread(target=_run, daemon=True)
7891
thread.start()
7992

8093
try:

0 commit comments

Comments
 (0)