Skip to content

Commit c3df015

Browse files
committed
refactor clock_event_loop fixture to become default event_loop
- uses a custom policy meta class that uses the existing policy to modify the new loop it creates. - The new loop it creates is modified to provide `advance_time` coroutine for testing - Extends pytest-dev#96 to make ClockEventLoop the default policy for testing
1 parent ed8b05d commit c3df015

File tree

2 files changed

+45
-64
lines changed

2 files changed

+45
-64
lines changed

pytest_asyncio/plugin.py

+40-42
Original file line numberDiff line numberDiff line change
@@ -193,64 +193,62 @@ def pytest_runtest_setup(item):
193193
# to marked test functions
194194
_markers_2_fixtures = {
195195
'asyncio': 'event_loop',
196-
'asyncio_clock': 'clock_event_loop',
197196
}
198197

199198

200-
@pytest.yield_fixture
201-
def event_loop(request):
202-
"""Create an instance of the default event loop for each test case."""
203-
loop = asyncio.get_event_loop_policy().new_event_loop()
204-
yield loop
205-
loop.close()
206-
207-
208-
def _clock_event_loop_class():
199+
def _event_loop_policy():
209200
"""
210201
Create a new class for ClockEventLoop based on the current
211202
class-type produced by `asyncio.new_event_loop()`. This is important
212203
for instances in which the enent-loop-policy has been changed.
213204
"""
214-
class ClockEventLoop(asyncio.new_event_loop().__class__):
205+
class ClockEventLoopPolicy(asyncio.get_event_loop_policy().__class__):
215206
"""
216207
A custom event loop that explicitly advances time when requested. Otherwise,
217208
this event loop advances time as expected.
218209
"""
219-
def __init__(self, *args, **kwargs):
220-
super().__init__(*args, **kwargs)
221-
self._offset = 0
222-
223-
def time(self):
224-
"""
225-
Return the time according the event loop's clock.
226-
227-
This time is adjusted by the stored offset that allows for advancement
228-
with `advance_time`.
229-
"""
230-
return super().time() + self._offset
231-
232-
def advance_time(self, seconds):
233-
'''
234-
Advance time by a given offset in seconds. Returns an awaitable
235-
that will complete after all tasks scheduled for after advancement
236-
of time are proceeding.
237-
'''
238-
if seconds > 0:
239-
# advance the clock by the given offset
240-
self._offset += seconds
241-
242-
# Once the clock is adjusted, new tasks may have just been
243-
# scheduled for running in the next pass through the event loop
244-
return self.create_task(asyncio.sleep(0))
245-
246-
return ClockEventLoop
210+
def new_event_loop(self):
211+
parent_loop = super().new_event_loop()
212+
parent_loop.close()
213+
214+
class ClockEventLoop(parent_loop.__class__):
215+
def __init__(self, *args, **kwargs):
216+
super().__init__(*args, **kwargs)
217+
self._clockoffset = 0
218+
219+
def time(self):
220+
"""
221+
Return the time according the event loop's clock.
222+
223+
This time is adjusted by the stored offset that allows for advancement
224+
with `advance_time`.
225+
"""
226+
return super().time() + self._clockoffset
227+
228+
def advance_time(self, seconds):
229+
'''
230+
Advance time by a given offset in seconds. Returns an awaitable
231+
that will complete after all tasks scheduled for after advancement
232+
of time are proceeding.
233+
'''
234+
if seconds > 0:
235+
# advance the clock by the given offset
236+
self._clockoffset += seconds
237+
238+
# Once the clock is adjusted, new tasks may have just been
239+
# scheduled for running in the next pass through the event loop
240+
return self.create_task(asyncio.sleep(0))
241+
242+
return ClockEventLoop()
243+
return ClockEventLoopPolicy()
247244

248245

249246
@pytest.yield_fixture
250-
def clock_event_loop(request):
247+
def event_loop(request):
251248
"""Create an instance of the default event loop for each test case."""
252-
loop = _clock_event_loop_class()()
253-
asyncio.get_event_loop_policy().set_event_loop(loop)
249+
# reset the event loop policy: modify existing policy to give time advancement
250+
asyncio.set_event_loop_policy(_event_loop_policy())
251+
loop = asyncio.get_event_loop_policy().new_event_loop()
254252
yield loop
255253
loop.close()
256254

tests/test_simple_35.py

+5-22
Original file line numberDiff line numberDiff line change
@@ -88,39 +88,22 @@ def test_async_close_loop(event_loop):
8888
return 'ok'
8989

9090

91-
@pytest.mark.asyncio_clock
92-
async def test_mark_asyncio_clock():
93-
"""
94-
Test that coroutines marked with asyncio_clock are run with a ClockEventLoop
95-
"""
96-
assert hasattr(asyncio.get_event_loop(), 'advance_time')
97-
98-
99-
def test_clock_loop_loop_fixture(clock_event_loop):
100-
"""
101-
Test that the clock_event_loop fixture returns a proper instance of the loop
102-
"""
103-
assert hasattr(asyncio.get_event_loop(), 'advance_time')
104-
clock_event_loop.close()
105-
return 'ok'
106-
107-
108-
@pytest.mark.asyncio_clock
109-
async def test_clock_loop_advance_time(clock_event_loop):
91+
@pytest.mark.asyncio
92+
async def test_event_loop_advance_time(event_loop):
11093
"""
11194
Test the sliding time event loop fixture
11295
"""
11396
# A task is created that will sleep some number of seconds
11497
SLEEP_TIME = 10
11598

11699
# create the task
117-
task = clock_event_loop.create_task(asyncio.sleep(SLEEP_TIME))
100+
task = event_loop.create_task(asyncio.sleep(SLEEP_TIME))
118101
assert not task.done()
119102

120103
# start the task
121-
await clock_event_loop.advance_time(0)
104+
await event_loop.advance_time(0)
122105
assert not task.done()
123106

124107
# process the timeout
125-
await clock_event_loop.advance_time(SLEEP_TIME)
108+
await event_loop.advance_time(SLEEP_TIME)
126109
assert task.done()

0 commit comments

Comments
 (0)