@@ -189,46 +189,6 @@ def pytest_runtest_setup(item):
189189 )
190190
191191
192- class ClockEventLoop (asyncio .new_event_loop ().__class__ ):
193- """
194- A custom event loop that explicitly advances time when requested. Otherwise,
195- this event loop advances time as expected.
196- """
197- def __init__ (self , * args , ** kwargs ):
198- super ().__init__ (* args , ** kwargs )
199- self ._offset = 0
200-
201- def time (self ):
202- """
203- Return the time according the event loop's clock.
204-
205- This time is adjusted by the stored offset that allows for advancement
206- with `advance_time`.
207- """
208- return super ().time () + self ._offset
209-
210- async def advance_time (self , seconds ):
211- '''
212- Advance time by a given offset in seconds.
213- '''
214- if seconds < 0 :
215- # cannot go backwards in time, so return immediately
216- return
217-
218- # advance the clock by the given offset
219- self ._offset += seconds
220-
221- # ensure waiting callbacks are run before advancing the clock
222- await asyncio .sleep (0 , loop = self )
223-
224- if seconds > 0 :
225- # Once the clock is adjusted, new tasks may have just been scheduled for running
226- # in the next pass through the event loop and advance again for the task
227- # that calls `advance_time`
228- await asyncio .sleep (0 , loop = self )
229- await asyncio .sleep (0 , loop = self )
230-
231-
232192# maps marker to the name of the event loop fixture that will be available
233193# to marked test functions
234194_markers_2_fixtures = {
@@ -245,10 +205,62 @@ def event_loop(request):
245205 loop .close ()
246206
247207
208+ def _clock_event_loop_class ():
209+ """
210+ Create a new class for ClockEventLoop based on the current
211+ class-type produced by `asyncio.new_event_loop()`. This is important
212+ for instances in which the enent-loop-policy has been changed.
213+ """
214+ class ClockEventLoop (asyncio .new_event_loop ().__class__ ):
215+ """
216+ A custom event loop that explicitly advances time when requested. Otherwise,
217+ this event loop advances time as expected.
218+ """
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+ # cannot go backwards in time, so return after one iteration of a loop
240+ return asyncio .sleep (0 )
241+
242+ # Add a task associated with iterating the currently "ready" tasks and handles
243+ #
244+ # NOTE: This can actually take place after the offset changed, but
245+ # it is here to highlight that the loop is for currently ready
246+ # items before offset is applied
247+ self .create_task (asyncio .sleep (0 ))
248+
249+ # advance the clock by the given offset
250+ self ._offset += seconds
251+
252+ # Once the clock is adjusted, new tasks may have just been
253+ # scheduled for running in the next pass through the event loop and
254+ # advance again for the newly ready tasks
255+ return self .create_task (asyncio .sleep (0 ))
256+
257+ return ClockEventLoop
258+
259+
248260@pytest .yield_fixture
249261def clock_event_loop (request ):
250262 """Create an instance of the default event loop for each test case."""
251- loop = ClockEventLoop ()
263+ loop = _clock_event_loop_class () ()
252264 asyncio .get_event_loop_policy ().set_event_loop (loop )
253265 yield loop
254266 loop .close ()
0 commit comments