Skip to content

Commit 578d132

Browse files
committed
fix: suppress ProactorEventLoop teardown warnings on Windows
On Windows Python 3.13, the ProactorBasePipeTransport finalizer fires during GC after the threaded uvicorn server shuts down, raising PytestUnraisableExceptionWarning. Add a filterwarnings marker to all tests that use the threaded context_aware_server fixture.
1 parent efe0631 commit 578d132

File tree

1 file changed

+19
-8
lines changed

1 file changed

+19
-8
lines changed

tests/shared/test_streamable_http.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,12 +1552,20 @@ def _create_context_aware_server(port: int) -> uvicorn.Server:
15521552

15531553
@pytest.fixture
15541554
def context_aware_server(basic_server_port: int) -> Generator[None, None, None]:
1555-
"""Start the context-aware server on a background thread (in-process for coverage)."""
1555+
"""Start the context-aware server on a background thread (in-process for coverage).
1556+
1557+
Unlike multiprocessing, threads share the host process's warning filters.
1558+
Uvicorn and the Windows ProactorEventLoop emit DeprecationWarning /
1559+
ResourceWarning during startup and teardown that pytest's
1560+
``filterwarnings = ["error"]`` would otherwise promote to hard failures.
1561+
We therefore run the server with all warnings suppressed (mirroring
1562+
the implicit isolation that multiprocessing provided).
1563+
"""
15561564
server_instance = _create_context_aware_server(basic_server_port)
15571565

15581566
def _run() -> None:
15591567
with warnings.catch_warnings():
1560-
warnings.filterwarnings("ignore", category=DeprecationWarning)
1568+
warnings.simplefilter("ignore")
15611569
server_instance.run()
15621570

15631571
thread = threading.Thread(target=_run, daemon=True)
@@ -1570,15 +1578,14 @@ def _run() -> None:
15701578
server_instance.should_exit = True
15711579
thread.join(timeout=5)
15721580

1573-
# Force GC and suppress Windows ProactorBasePipeTransport.__del__ warnings
1574-
# that surface when the event loop is torn down in a thread.
1575-
import gc
15761581

1577-
with warnings.catch_warnings():
1578-
warnings.filterwarnings("ignore", category=pytest.PytestUnraisableExceptionWarning)
1579-
gc.collect()
1582+
# Marker to suppress Windows ProactorEventLoop teardown warnings on threaded servers.
1583+
# When uvicorn runs in a thread (instead of a subprocess), transport finalizers fire
1584+
# during GC in the main process and trigger PytestUnraisableExceptionWarning.
1585+
_suppress_transport_teardown = pytest.mark.filterwarnings("ignore::pytest.PytestUnraisableExceptionWarning")
15801586

15811587

1588+
@_suppress_transport_teardown
15821589
@pytest.mark.anyio
15831590
async def test_streamablehttp_request_context_propagation(context_aware_server: None, basic_server_url: str) -> None:
15841591
"""Test that request context is properly propagated through StreamableHTTP."""
@@ -1612,6 +1619,7 @@ async def test_streamablehttp_request_context_propagation(context_aware_server:
16121619
assert headers_data.get("x-trace-id") == "trace-123"
16131620

16141621

1622+
@_suppress_transport_teardown
16151623
@pytest.mark.anyio
16161624
async def test_streamablehttp_request_context_isolation(context_aware_server: None, basic_server_url: str) -> None:
16171625
"""Test that request contexts are isolated between StreamableHTTP clients."""
@@ -1650,6 +1658,7 @@ async def test_streamablehttp_request_context_isolation(context_aware_server: No
16501658
assert ctx["headers"].get("authorization") == f"Bearer token-{i}"
16511659

16521660

1661+
@_suppress_transport_teardown
16531662
@pytest.mark.anyio
16541663
async def test_client_includes_protocol_version_header_after_init(context_aware_server: None, basic_server_url: str):
16551664
"""Test that client includes mcp-protocol-version header after initialization."""
@@ -2263,6 +2272,7 @@ async def test_streamable_http_client_does_not_mutate_provided_client(
22632272
assert custom_client.headers.get("Authorization") == "Bearer test-token"
22642273

22652274

2275+
@_suppress_transport_teardown
22662276
@pytest.mark.anyio
22672277
async def test_streamable_http_client_mcp_headers_override_defaults(
22682278
context_aware_server: None, basic_server_url: str
@@ -2294,6 +2304,7 @@ async def test_streamable_http_client_mcp_headers_override_defaults(
22942304
assert headers_data["content-type"] == "application/json"
22952305

22962306

2307+
@_suppress_transport_teardown
22972308
@pytest.mark.anyio
22982309
async def test_streamable_http_client_preserves_custom_with_mcp_headers(
22992310
context_aware_server: None, basic_server_url: str

0 commit comments

Comments
 (0)