14
14
from functools import wraps
15
15
16
16
17
- def convert_fixtures (fixturedef , request , node ):
17
+ def convert_fixtures (ctx , fixturedef , request , node ):
18
18
"""Used to replace async fixtures"""
19
19
if not hasattr (fixturedef , "func" ):
20
20
return
21
21
22
+ if hasattr (fixturedef .func , "__alt_asyncio_pytest_converted__" ):
23
+ return
24
+
22
25
if inspect .iscoroutinefunction (fixturedef .func ):
23
- convert_async_coroutine_fixture (fixturedef , request , node )
26
+ convert_async_coroutine_fixture (ctx , fixturedef , request , node )
27
+ fixturedef .func .__alt_asyncio_pytest_converted__ = True
24
28
25
29
elif inspect .isasyncgenfunction (fixturedef .func ):
26
- convert_async_gen_fixture (fixturedef , request , node )
30
+ convert_async_gen_fixture (ctx , fixturedef , request , node )
31
+ fixturedef .func .__alt_asyncio_pytest_converted__ = True
32
+
33
+ elif inspect .isgeneratorfunction (fixturedef .func ):
34
+ convert_sync_gen_fixture (ctx , fixturedef )
35
+ fixturedef .func .__alt_asyncio_pytest_converted__ = True
36
+
37
+ else :
38
+ convert_sync_fixture (ctx , fixturedef )
39
+ fixturedef .func .__alt_asyncio_pytest_converted__ = True
40
+
41
+
42
+ def convert_sync_fixture (ctx , fixturedef ):
43
+ """
44
+ Used to make sure a non-async fixture is run in our
45
+ asyncio contextvars
46
+ """
47
+ original = fixturedef .func
48
+
49
+ @wraps (original )
50
+ def run_fixture (* args , ** kwargs ):
51
+ try :
52
+ ctx .run (lambda : None )
53
+ run = lambda func , * a , ** kw : ctx .run (func , * a , ** kw )
54
+ except RuntimeError :
55
+ run = lambda func , * a , ** kw : func (* a , ** kw )
27
56
57
+ return run (original , * args , ** kwargs )
28
58
29
- def converted_async_test (test_tasks , func , timeout , * args , ** kwargs ):
59
+ fixturedef .func = run_fixture
60
+
61
+
62
+ def convert_sync_gen_fixture (ctx , fixturedef ):
63
+ """
64
+ Used to make sure a non-async generator fixture is run in our
65
+ asyncio contextvars
66
+ """
67
+ original = fixturedef .func
68
+
69
+ @wraps (original )
70
+ def run_fixture (* args , ** kwargs ):
71
+ try :
72
+ ctx .run (lambda : None )
73
+ run = lambda func , * a , ** kw : ctx .run (func , * a , ** kw )
74
+ except RuntimeError :
75
+ run = lambda func , * a , ** kw : func (* a , ** kw )
76
+
77
+ cm = original (* args , ** kwargs )
78
+ value = run (cm .__next__ )
79
+ try :
80
+ yield value
81
+ run (cm .__next__ )
82
+ except StopIteration :
83
+ pass
84
+
85
+ fixturedef .func = run_fixture
86
+
87
+
88
+ def converted_async_test (ctx , test_tasks , func , timeout , * args , ** kwargs ):
30
89
"""Used to replace async tests"""
31
90
__tracebackhide__ = True
32
91
@@ -39,7 +98,7 @@ def look_at_task(t):
39
98
info ["func" ] = func
40
99
41
100
return _run_and_raise (
42
- loop , info , func , async_runner (func , timeout , info , args , kwargs ), look_at_task
101
+ ctx , loop , info , func , async_runner (func , timeout , info , args , kwargs ), look_at_task
43
102
)
44
103
45
104
@@ -83,15 +142,15 @@ def raise_error():
83
142
raise_error ()
84
143
85
144
86
- def _run_and_raise (loop , info , func , coro , look_at_task = None ):
145
+ def _run_and_raise (ctx , loop , info , func , coro , look_at_task = None ):
87
146
__tracebackhide__ = True
88
147
89
148
def silent_done_task (res ):
90
149
if res .cancelled ():
91
150
pass
92
151
res .exception ()
93
152
94
- task = loop .create_task (coro )
153
+ task = loop .create_task (coro , context = ctx )
95
154
task .add_done_callback (silent_done_task )
96
155
97
156
if look_at_task :
@@ -148,7 +207,7 @@ def wrapper(*args, **kwargs):
148
207
return wrapper
149
208
150
209
151
- def convert_async_coroutine_fixture (fixturedef , request , node ):
210
+ def convert_async_coroutine_fixture (ctx , fixturedef , request , node ):
152
211
"""
153
212
Run our async fixture in our event loop and capture the error from
154
213
inside the loop.
@@ -161,12 +220,14 @@ def override(extra, *args, **kwargs):
161
220
162
221
info = {"func" : func }
163
222
loop = asyncio .get_event_loop_policy ().get_event_loop ()
164
- return _run_and_raise (loop , info , func , async_runner (func , timeout , info , args , kwargs ))
223
+ return _run_and_raise (
224
+ ctx , loop , info , func , async_runner (func , timeout , info , args , kwargs )
225
+ )
165
226
166
227
fixturedef .func = _wrap (fixturedef , [], override , func )
167
228
168
229
169
- def convert_async_gen_fixture (fixturedef , request , node ):
230
+ def convert_async_gen_fixture (ctx , fixturedef , request , node ):
170
231
"""
171
232
Return the yield'd value from the generator and ensure the generator is
172
233
finished.
@@ -204,11 +265,12 @@ async def async_finalizer():
204
265
else :
205
266
info ["e" ] = ValueError ("Async generator fixture should only yield once" )
206
267
207
- _run_and_raise (loop , info , generator , async_finalizer ())
268
+ _run_and_raise (ctx , loop , info , generator , async_finalizer ())
208
269
209
270
request .addfinalizer (finalizer )
210
271
211
272
return _run_and_raise (
273
+ ctx ,
212
274
loop ,
213
275
info ,
214
276
generator ,
0 commit comments