66import socket
77
88import pytest
9+
910try :
1011 from _pytest .python import transfer_markers
1112except ImportError : # Pytest 4.1.0 removes the transfer_marker api (#104)
13+
1214 def transfer_markers (* args , ** kwargs ): # noqa
1315 """Noop when over pytest 4.1.0"""
1416 pass
1517
18+
1619from inspect import isasyncgenfunction
1720
1821
@@ -23,10 +26,12 @@ def _is_coroutine(obj):
2326
2427def pytest_configure (config ):
2528 """Inject documentation."""
26- config .addinivalue_line ("markers" ,
27- "asyncio: "
28- "mark the test as a coroutine, it will be "
29- "run using an asyncio event loop" )
29+ config .addinivalue_line (
30+ "markers" ,
31+ "asyncio: "
32+ "mark the test as a coroutine, it will be "
33+ "run using an asyncio event loop" ,
34+ )
3035
3136
3237@pytest .mark .tryfirst
@@ -41,12 +46,13 @@ def pytest_pycollect_makeitem(collector, name, obj):
4146 transfer_markers (obj , item .cls , item .module )
4247 item = pytest .Function .from_parent (collector , name = name ) # To reload keywords.
4348
44- if ' asyncio' in item .keywords :
49+ if " asyncio" in item .keywords :
4550 return list (collector ._genfunctions (name , obj ))
4651
4752
4853class FixtureStripper :
4954 """Include additional Fixture, and then strip them"""
55+
5056 REQUEST = "request"
5157 EVENT_LOOP = "event_loop"
5258
@@ -59,7 +65,7 @@ def add(self, name):
5965 and record in to_strip list (If not previously included)"""
6066 if name in self .fixturedef .argnames :
6167 return
62- self .fixturedef .argnames += (name , )
68+ self .fixturedef .argnames += (name ,)
6369 self .to_strip .add (name )
6470
6571 def get_and_strip_from (self , name , data_dict ):
@@ -69,6 +75,7 @@ def get_and_strip_from(self, name, data_dict):
6975 del data_dict [name ]
7076 return result
7177
78+
7279@pytest .hookimpl (trylast = True )
7380def pytest_fixture_post_finalizer (fixturedef , request ):
7481 """Called after fixture teardown"""
@@ -77,14 +84,16 @@ def pytest_fixture_post_finalizer(fixturedef, request):
7784 asyncio .set_event_loop_policy (None )
7885
7986
80-
8187@pytest .hookimpl (hookwrapper = True )
8288def pytest_fixture_setup (fixturedef , request ):
8389 """Adjust the event loop policy when an event loop is produced."""
8490 if fixturedef .argname == "event_loop" :
8591 outcome = yield
8692 loop = outcome .get_result ()
8793 policy = asyncio .get_event_loop_policy ()
94+ old_loop = policy .get_event_loop ()
95+ if old_loop is not loop :
96+ old_loop .close ()
8897 policy .set_event_loop (loop )
8998 return
9099
@@ -96,10 +105,13 @@ def pytest_fixture_setup(fixturedef, request):
96105 fixture_stripper .add (FixtureStripper .EVENT_LOOP )
97106 fixture_stripper .add (FixtureStripper .REQUEST )
98107
99-
100108 def wrapper (* args , ** kwargs ):
101- loop = fixture_stripper .get_and_strip_from (FixtureStripper .EVENT_LOOP , kwargs )
102- request = fixture_stripper .get_and_strip_from (FixtureStripper .REQUEST , kwargs )
109+ loop = fixture_stripper .get_and_strip_from (
110+ FixtureStripper .EVENT_LOOP , kwargs
111+ )
112+ request = fixture_stripper .get_and_strip_from (
113+ FixtureStripper .REQUEST , kwargs
114+ )
103115
104116 gen_obj = generator (* args , ** kwargs )
105117
@@ -109,6 +121,7 @@ async def setup():
109121
110122 def finalizer ():
111123 """Yield again, to finalize."""
124+
112125 async def async_finalizer ():
113126 try :
114127 await gen_obj .__anext__ ()
@@ -118,6 +131,7 @@ async def async_finalizer():
118131 msg = "Async generator fixture didn't stop."
119132 msg += "Yield only once."
120133 raise ValueError (msg )
134+
121135 loop .run_until_complete (async_finalizer ())
122136
123137 request .addfinalizer (finalizer )
@@ -131,7 +145,9 @@ async def async_finalizer():
131145 fixture_stripper .add (FixtureStripper .EVENT_LOOP )
132146
133147 def wrapper (* args , ** kwargs ):
134- loop = fixture_stripper .get_and_strip_from (FixtureStripper .EVENT_LOOP , kwargs )
148+ loop = fixture_stripper .get_and_strip_from (
149+ FixtureStripper .EVENT_LOOP , kwargs
150+ )
135151
136152 async def setup ():
137153 res = await coro (* args , ** kwargs )
@@ -149,16 +165,15 @@ def pytest_pyfunc_call(pyfuncitem):
149165 Run asyncio marked test functions in an event loop instead of a normal
150166 function call.
151167 """
152- if ' asyncio' in pyfuncitem .keywords :
153- if getattr (pyfuncitem .obj , ' is_hypothesis_test' , False ):
168+ if " asyncio" in pyfuncitem .keywords :
169+ if getattr (pyfuncitem .obj , " is_hypothesis_test" , False ):
154170 pyfuncitem .obj .hypothesis .inner_test = wrap_in_sync (
155171 pyfuncitem .obj .hypothesis .inner_test ,
156- _loop = pyfuncitem .funcargs [' event_loop' ]
172+ _loop = pyfuncitem .funcargs [" event_loop" ],
157173 )
158174 else :
159175 pyfuncitem .obj = wrap_in_sync (
160- pyfuncitem .obj ,
161- _loop = pyfuncitem .funcargs ['event_loop' ]
176+ pyfuncitem .obj , _loop = pyfuncitem .funcargs ["event_loop" ]
162177 )
163178 yield
164179
@@ -181,22 +196,25 @@ def inner(**kwargs):
181196 if task .done () and not task .cancelled ():
182197 task .exception ()
183198 raise
199+
184200 return inner
185201
186202
187203def pytest_runtest_setup (item ):
188- if ' asyncio' in item .keywords :
204+ if " asyncio" in item .keywords :
189205 # inject an event loop fixture for all async tests
190- if 'event_loop' in item .fixturenames :
191- item .fixturenames .remove ('event_loop' )
192- item .fixturenames .insert (0 , 'event_loop' )
193- if item .get_closest_marker ("asyncio" ) is not None \
194- and not getattr (item .obj , 'hypothesis' , False ) \
195- and getattr (item .obj , 'is_hypothesis_test' , False ):
196- pytest .fail (
197- 'test function `%r` is using Hypothesis, but pytest-asyncio '
198- 'only works with Hypothesis 3.64.0 or later.' % item
199- )
206+ if "event_loop" in item .fixturenames :
207+ item .fixturenames .remove ("event_loop" )
208+ item .fixturenames .insert (0 , "event_loop" )
209+ if (
210+ item .get_closest_marker ("asyncio" ) is not None
211+ and not getattr (item .obj , "hypothesis" , False )
212+ and getattr (item .obj , "is_hypothesis_test" , False )
213+ ):
214+ pytest .fail (
215+ "test function `%r` is using Hypothesis, but pytest-asyncio "
216+ "only works with Hypothesis 3.64.0 or later." % item
217+ )
200218
201219
202220@pytest .fixture
@@ -210,7 +228,7 @@ def event_loop(request):
210228def _unused_tcp_port ():
211229 """Find an unused localhost TCP port from 1024-65535 and return it."""
212230 with contextlib .closing (socket .socket ()) as sock :
213- sock .bind ((' 127.0.0.1' , 0 ))
231+ sock .bind ((" 127.0.0.1" , 0 ))
214232 return sock .getsockname ()[1 ]
215233
216234
@@ -219,7 +237,7 @@ def unused_tcp_port():
219237 return _unused_tcp_port ()
220238
221239
222- @pytest .fixture (scope = ' session' )
240+ @pytest .fixture (scope = " session" )
223241def unused_tcp_port_factory ():
224242 """A factory function, producing different unused TCP ports."""
225243 produced = set ()
@@ -234,4 +252,5 @@ def factory():
234252 produced .add (port )
235253
236254 return port
255+
237256 return factory
0 commit comments