File tree Expand file tree Collapse file tree 2 files changed +100
-1
lines changed Expand file tree Collapse file tree 2 files changed +100
-1
lines changed Original file line number Diff line number Diff line change 10
10
import inspect
11
11
import socket
12
12
import sys
13
+ import threading
13
14
import traceback
14
15
import warnings
15
16
from asyncio import AbstractEventLoop , AbstractEventLoopPolicy
@@ -602,6 +603,16 @@ def _set_event_loop(loop: AbstractEventLoop | None) -> None:
602
603
asyncio .set_event_loop (loop )
603
604
604
605
606
+ def _reinstate_event_loop_on_main_thread () -> None :
607
+ if threading .current_thread () is threading .main_thread ():
608
+ try :
609
+ _ = asyncio .get_event_loop_policy ().get_event_loop ()
610
+ except RuntimeError :
611
+ asyncio .get_event_loop_policy ().set_event_loop (
612
+ asyncio .get_event_loop_policy ().new_event_loop ()
613
+ )
614
+
615
+
605
616
@pytest .hookimpl (tryfirst = True , hookwrapper = True )
606
617
def pytest_pyfunc_call (pyfuncitem : Function ) -> object | None :
607
618
"""
@@ -663,7 +674,12 @@ def wrap_in_sync(
663
674
@functools .wraps (func )
664
675
def inner (* args , ** kwargs ):
665
676
coro = func (* args , ** kwargs )
666
- _loop = _get_event_loop_no_warn ()
677
+ try :
678
+ _loop = _get_event_loop_no_warn ()
679
+ except RuntimeError :
680
+ # Handle situation where asyncio.set_event_loop(None) removes shared loops.
681
+ _reinstate_event_loop_on_main_thread ()
682
+ _loop = _get_event_loop_no_warn ()
667
683
task = asyncio .ensure_future (coro , loop = _loop )
668
684
try :
669
685
_loop .run_until_complete (task )
Original file line number Diff line number Diff line change
1
+ from __future__ import annotations
2
+
3
+ from textwrap import dedent
4
+
5
+ import pytest
6
+ from pytest import Pytester
7
+
8
+
9
+ @pytest .mark .parametrize ("test_loop_scope" , ("function" , "module" , "session" ))
10
+ def test_set_event_loop_none (pytester : Pytester , test_loop_scope : str ):
11
+ pytester .makeini (
12
+ dedent (
13
+ f"""\
14
+ [pytest]
15
+ asyncio_default_test_loop_scope = { test_loop_scope }
16
+ asyncio_default_fixture_loop_scope = function
17
+ """
18
+ )
19
+ )
20
+ pytester .makepyfile (
21
+ dedent (
22
+ """\
23
+ import asyncio
24
+ import pytest
25
+
26
+ pytest_plugins = "pytest_asyncio"
27
+
28
+ @pytest.mark.asyncio
29
+ async def test_before():
30
+ pass
31
+
32
+
33
+ def test_set_event_loop_none():
34
+ asyncio.set_event_loop(None)
35
+
36
+
37
+ @pytest.mark.asyncio
38
+ async def test_after():
39
+ pass
40
+ """
41
+ )
42
+ )
43
+ result = pytester .runpytest_subprocess ()
44
+ result .assert_outcomes (passed = 3 )
45
+
46
+
47
+ def test_set_event_loop_none_class (pytester : Pytester ):
48
+ pytester .makeini (
49
+ dedent (
50
+ """\
51
+ [pytest]
52
+ asyncio_default_test_loop_scope = class
53
+ asyncio_default_fixture_loop_scope = function
54
+ """
55
+ )
56
+ )
57
+ pytester .makepyfile (
58
+ dedent (
59
+ """\
60
+ import asyncio
61
+ import pytest
62
+
63
+ pytest_plugins = "pytest_asyncio"
64
+
65
+
66
+ class TestClass:
67
+ @pytest.mark.asyncio
68
+ async def test_before(self):
69
+ pass
70
+
71
+
72
+ def test_set_event_loop_none(self):
73
+ asyncio.set_event_loop(None)
74
+
75
+
76
+ @pytest.mark.asyncio
77
+ async def test_after(self):
78
+ pass
79
+ """
80
+ )
81
+ )
82
+ result = pytester .runpytest_subprocess ()
83
+ result .assert_outcomes (passed = 3 )
You can’t perform that action at this time.
0 commit comments