@@ -145,10 +145,17 @@ def pytest_pyfunc_call(pyfuncitem):
145
145
function call.
146
146
"""
147
147
for marker_name , fixture_name in _markers_2_fixtures .items ():
148
- if marker_name in pyfuncitem .keywords \
149
- and not getattr (pyfuncitem .obj , 'is_hypothesis_test' , False ):
148
+ if marker_name in pyfuncitem .keywords :
150
149
event_loop = pyfuncitem .funcargs [fixture_name ]
151
-
150
+ if getattr (pyfuncitem .obj , 'is_hypothesis_test' , False ):
151
+ # Wrap the async function to execute in the pytest-asyncio event loop and yield to delegate
152
+ # test execution to the hypothesis plugin
153
+ pyfuncitem .obj .hypothesis .inner_test = wrap_in_sync (
154
+ pyfuncitem .obj .hypothesis .inner_test , event_loop
155
+ )
156
+ # It is important to yield, not return. Otherwise the event_loop fixture will get cleaned up too early
157
+ # when using a combination of hypothesis and pytest.mark.parametrize
158
+ yield None
152
159
funcargs = pyfuncitem .funcargs
153
160
testargs = {arg : funcargs [arg ]
154
161
for arg in pyfuncitem ._fixtureinfo .argnames }
@@ -159,19 +166,16 @@ def pytest_pyfunc_call(pyfuncitem):
159
166
return True
160
167
161
168
162
- def wrap_in_sync (func ):
163
- """Return a sync wrapper around an async function."""
169
+ def wrap_in_sync (func , loop ):
170
+ """Return a sync wrapper around an async function executing it in the
171
+ specified event loop."""
164
172
165
173
@functools .wraps (func )
166
174
def inner (** kwargs ):
167
- loop = asyncio .get_event_loop_policy ().new_event_loop ()
168
- try :
169
- coro = func (** kwargs )
170
- if coro is not None :
171
- future = asyncio .ensure_future (coro , loop = loop )
172
- loop .run_until_complete (future )
173
- finally :
174
- loop .close ()
175
+ coro = func (** kwargs )
176
+ if coro is not None :
177
+ future = asyncio .ensure_future (coro , loop = loop )
178
+ loop .run_until_complete (future )
175
179
176
180
return inner
177
181
@@ -181,13 +185,9 @@ def pytest_runtest_setup(item):
181
185
if marker in item .keywords and fixture not in item .fixturenames :
182
186
# inject an event loop fixture for all async tests
183
187
item .fixturenames .append (fixture )
184
- if item .get_closest_marker ("asyncio" ) is not None :
185
- if hasattr (item .obj , 'hypothesis' ):
186
- # If it's a Hypothesis test, we insert the wrap_in_sync decorator
187
- item .obj .hypothesis .inner_test = wrap_in_sync (
188
- item .obj .hypothesis .inner_test
189
- )
190
- elif getattr (item .obj , 'is_hypothesis_test' , False ):
188
+ if item .get_closest_marker ("asyncio" ) is not None \
189
+ and not getattr (item .obj , 'hypothesis' , False ) \
190
+ and getattr (item .obj , 'is_hypothesis_test' , False ):
191
191
pytest .fail (
192
192
'test function `%r` is using Hypothesis, but pytest-asyncio '
193
193
'only works with Hypothesis 3.64.0 or later.' % item
0 commit comments