@@ -189,46 +189,6 @@ def pytest_runtest_setup(item):
189
189
)
190
190
191
191
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
-
232
192
# maps marker to the name of the event loop fixture that will be available
233
193
# to marked test functions
234
194
_markers_2_fixtures = {
@@ -245,10 +205,62 @@ def event_loop(request):
245
205
loop .close ()
246
206
247
207
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
+
248
260
@pytest .yield_fixture
249
261
def clock_event_loop (request ):
250
262
"""Create an instance of the default event loop for each test case."""
251
- loop = ClockEventLoop ()
263
+ loop = _clock_event_loop_class () ()
252
264
asyncio .get_event_loop_policy ().set_event_loop (loop )
253
265
yield loop
254
266
loop .close ()
0 commit comments