Skip to content

Commit bad9920

Browse files
Move WebLoop patch to conftest.py
1 parent 81f5df3 commit bad9920

File tree

2 files changed

+40
-40
lines changed

2 files changed

+40
-40
lines changed

src/zarr/core/sync.py

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import atexit
55
import logging
66
import os
7-
import sys
87
import threading
98
from concurrent.futures import ThreadPoolExecutor, wait
109
from typing import TYPE_CHECKING, Any, TypeVar
@@ -38,45 +37,6 @@ class SyncError(Exception):
3837
pass
3938

4039

41-
# TODO: not sure if there is a better place to put this function, so I've kept it here for now.
42-
def _make_shutdown_asyncgens_noop_for_pyodide() -> None:
43-
"""
44-
Patch Pyodide's WebLoop to fix interoperability with pytest-asyncio.
45-
46-
WebLoop.shutdown_asyncgens() raises NotImplementedError, which causes
47-
pytest-asyncio to issue warnings during test cleanup and potentially
48-
cause resource leaks that make tests hang. This is a bit of a
49-
hack, but it allows us to run tests that use pytest-asyncio.
50-
51-
This is necessary because pytest-asyncio tries to clean up async generators
52-
when tearing down test event loops, but Pyodide's WebLoop doesn't support
53-
this as it integrates with the browser's event loop rather than managing
54-
its own lifecycle.
55-
"""
56-
try:
57-
if not IS_WASM and "pyodide" not in sys.modules:
58-
return
59-
60-
import pyodide.webloop
61-
62-
if hasattr(pyodide.webloop.WebLoop, "shutdown_asyncgens"):
63-
64-
async def no_op_shutdown_asyncgens(self) -> None: # type: ignore[no-untyped-def] # noqa: ANN001
65-
return
66-
67-
pyodide.webloop.WebLoop.shutdown_asyncgens = no_op_shutdown_asyncgens
68-
logger.debug("Patched WebLoop.shutdown_asyncgens for pytest-asyncio compatibility")
69-
70-
# If patching fails for any reason, we log it, but we won't want to crash Zarr
71-
except Exception as e:
72-
msg = f"Could not patch WebLoop for pytest compatibility: {e}"
73-
logger.debug(msg)
74-
75-
76-
if IS_WASM:
77-
_make_shutdown_asyncgens_noop_for_pyodide()
78-
79-
8040
def _get_lock() -> threading.Lock:
8141
"""Allocate or return a threading lock.
8242

tests/conftest.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import pathlib
4+
import sys
45
from dataclasses import dataclass, field
56
from typing import TYPE_CHECKING
67

@@ -106,6 +107,45 @@ def sync_store(request: pytest.FixtureRequest, tmp_path: LEGACY_PATH) -> Store:
106107
return result
107108

108109

110+
@pytest.fixture(autouse=(IS_WASM and "pyodide" in sys.modules), scope="session")
111+
def patch_pyodide_webloop_for_pytest() -> Generator[None, None, None]:
112+
"""
113+
Patch Pyodide's WebLoop to fix interoperability with pytest-asyncio.
114+
115+
WebLoop.shutdown_asyncgens() raises NotImplementedError, which causes
116+
pytest-asyncio to issue warnings during test cleanup and potentially
117+
cause resource leaks that make tests hang. This is a bit of a
118+
hack, but it allows us to run tests that use pytest-asyncio.
119+
120+
This is necessary because pytest-asyncio tries to clean up async generators
121+
when tearing down test event loops, but Pyodide's WebLoop doesn't support
122+
this as it integrates with the browser's event loop rather than managing
123+
its own lifecycle.
124+
"""
125+
import logging
126+
127+
logger = logging.getLogger(__name__)
128+
129+
try:
130+
import pyodide.webloop
131+
132+
if hasattr(pyodide.webloop.WebLoop, "shutdown_asyncgens"):
133+
134+
async def no_op_shutdown_asyncgens(self) -> None: # type: ignore[no-untyped-def]
135+
return
136+
137+
pyodide.webloop.WebLoop.shutdown_asyncgens = no_op_shutdown_asyncgens
138+
logger.debug("Patched WebLoop.shutdown_asyncgens for pytest-asyncio compatibility")
139+
140+
yield
141+
142+
# If patching fails for any reason, we log it, but we won't want to crash the tests
143+
except Exception as e:
144+
msg = f"Could not patch WebLoop for pytest compatibility: {e}"
145+
logger.debug(msg)
146+
yield
147+
148+
109149
@dataclass
110150
class AsyncGroupRequest:
111151
zarr_format: ZarrFormat

0 commit comments

Comments
 (0)