9
9
import warnings
10
10
import concurrent .futures
11
11
12
- from ._handles import Handle , TimerHandle
12
+ from ._handles import ScopedHandle , AsyncHandle
13
13
from ._util import run_aio_future , run_aio_generator
14
14
from ._deprecate import deprecated , deprecated_alias
15
15
from . import _util
@@ -39,28 +39,6 @@ def clear(self):
39
39
pass
40
40
41
41
42
- def _h_raise (handle , exc ):
43
- """
44
- Convince a handle to raise an error.
45
-
46
- trio-asyncio enhanced handles have a method to do this
47
- but asyncio's native handles don't. Thus we need to fudge things.
48
- """
49
- if hasattr (handle , '_raise' ):
50
- handle ._raise (exc )
51
- return
52
-
53
- def _raise (exc ):
54
- raise exc
55
-
56
- cb , handle ._callback = handle ._callback , _raise
57
- ar , handle ._args = handle ._args , (exc ,)
58
- try :
59
- handle ._run ()
60
- finally :
61
- handle ._callback , handle ._args = cb , ar
62
-
63
-
64
42
class _TrioSelector (_BaseSelectorImpl ):
65
43
"""A selector that hooks into a ``TrioEventLoop``.
66
44
@@ -241,25 +219,6 @@ async def run_aio_coroutine(self, coro):
241
219
finally :
242
220
sniffio .current_async_library_cvar .reset (t )
243
221
244
- async def __run_trio (self , h ):
245
- """Helper for copying the result of a Trio task to an asyncio future"""
246
- f , proc , * args = h ._args
247
- if f .cancelled (): # pragma: no cover
248
- return
249
- try :
250
- with trio .CancelScope () as scope :
251
- h ._scope = scope
252
- res = await proc (* args )
253
- if scope .cancelled_caught :
254
- f .cancel ()
255
- return
256
- except BaseException as exc :
257
- if not f .cancelled (): # pragma: no branch
258
- f .set_exception (exc )
259
- else :
260
- if not f .cancelled (): # pragma: no branch
261
- f .set_result (res )
262
-
263
222
def trio_as_future (self , proc , * args ):
264
223
"""Start a new Trio task to run ``await proc(*args)`` asynchronously.
265
224
Return an `asyncio.Future` that will resolve to the value or exception
@@ -292,14 +251,7 @@ def trio_as_future(self, proc, *args):
292
251
an `asyncio.Future` which will resolve to the result of the call to *proc*
293
252
"""
294
253
f = asyncio .Future (loop = self )
295
- h = Handle (
296
- self .__run_trio , (
297
- f ,
298
- proc ,
299
- ) + args , self , context = None , is_sync = None
300
- )
301
- self ._queue_handle (h )
302
- f .add_done_callback (h ._cb_future_cancel )
254
+ self ._queue_handle (AsyncHandle (proc , args , self , result_future = f ))
303
255
return f
304
256
305
257
def run_trio_task (self , proc , * args ):
@@ -314,7 +266,7 @@ def run_trio_task(self, proc, *args):
314
266
Returns:
315
267
an `asyncio.Handle` which can be used to cancel the background task
316
268
"""
317
- return self ._queue_handle (Handle (proc , args , self , is_sync = False ))
269
+ return self ._queue_handle (AsyncHandle (proc , args , self ))
318
270
319
271
# Callback handling #
320
272
@@ -331,7 +283,7 @@ def _queue_handle(self, handle):
331
283
def _call_soon (self , * arks , ** kwargs ):
332
284
raise RuntimeError ("_call_soon() should not have been called" )
333
285
334
- def call_later (self , delay , callback , * args , context = None ):
286
+ def call_later (self , delay , callback , * args , ** context ):
335
287
"""asyncio's timer-based delay
336
288
337
289
Note that the callback is a sync function.
@@ -342,36 +294,36 @@ def call_later(self, delay, callback, *args, context=None):
342
294
"""
343
295
self ._check_callback (callback , 'call_later' )
344
296
assert delay >= 0 , delay
345
- h = TimerHandle (delay + self .time (), callback , args , self , context = context , is_sync = True )
297
+ h = asyncio . TimerHandle (delay + self .time (), callback , args , self , ** context )
346
298
self ._queue_handle (h )
347
299
return h
348
300
349
- def call_at (self , when , callback , * args , context = None ):
301
+ def call_at (self , when , callback , * args , ** context ):
350
302
"""asyncio's time-based delay
351
303
352
304
Note that the callback is a sync function.
353
305
"""
354
306
self ._check_callback (callback , 'call_at' )
355
307
return self ._queue_handle (
356
- TimerHandle (when , callback , args , self , context = context , is_sync = True )
308
+ asyncio . TimerHandle (when , callback , args , self , ** context )
357
309
)
358
310
359
- def call_soon (self , callback , * args , context = None ):
311
+ def call_soon (self , callback , * args , ** context ):
360
312
"""asyncio's defer-to-mainloop callback executor.
361
313
362
314
Note that the callback is a sync function.
363
315
"""
364
316
self ._check_callback (callback , 'call_soon' )
365
- return self ._queue_handle (Handle (callback , args , self , context = context , is_sync = True ))
317
+ return self ._queue_handle (asyncio . Handle (callback , args , self , ** context ))
366
318
367
- def call_soon_threadsafe (self , callback , * args , context = None ):
319
+ def call_soon_threadsafe (self , callback , * args , ** context ):
368
320
"""asyncio's thread-safe defer-to-mainloop
369
321
370
322
Note that the callback is a sync function.
371
323
"""
372
324
self ._check_callback (callback , 'call_soon_threadsafe' )
373
325
self ._check_closed ()
374
- h = Handle (callback , args , self , context = context , is_sync = True )
326
+ h = asyncio . Handle (callback , args , self , ** context )
375
327
self ._token .run_sync_soon (self ._q_send .send_nowait , h )
376
328
377
329
# drop all timers
@@ -471,7 +423,7 @@ async def synchronize(self):
471
423
472
424
"""
473
425
w = trio .Event ()
474
- self ._queue_handle (Handle (w .set , (), self , is_sync = True ))
426
+ self ._queue_handle (asyncio . Handle (w .set , (), self ))
475
427
await w .wait ()
476
428
477
429
# Signal handling #
@@ -488,7 +440,7 @@ def add_signal_handler(self, sig, callback, *args):
488
440
self ._check_signal (sig )
489
441
if sig == signal .SIGKILL :
490
442
raise RuntimeError ("SIGKILL cannot be caught" )
491
- h = Handle (callback , args , self , context = None , is_sync = True )
443
+ h = asyncio . Handle (callback , args , self )
492
444
assert sig not in self ._signal_handlers , \
493
445
"Signal %d is already being caught" % (sig ,)
494
446
self ._orig_signals [sig ] = signal .signal (sig , self ._handle_sig )
@@ -528,7 +480,7 @@ def add_reader(self, fd, callback, *args):
528
480
529
481
def _add_reader (self , fd , callback , * args ):
530
482
self ._check_closed ()
531
- handle = Handle (callback , args , self , context = None , is_sync = True )
483
+ handle = ScopedHandle (callback , args , self )
532
484
reader = self ._set_read_handle (fd , handle )
533
485
if reader is not None :
534
486
reader .cancel ()
@@ -547,20 +499,17 @@ def _set_read_handle(self, fd, handle):
547
499
self ._selector .modify (fd , mask | EVENT_READ , (handle , writer ))
548
500
return reader
549
501
550
- async def _reader_loop (self , fd , handle , task_status = trio .TASK_STATUS_IGNORED ):
551
- task_status .started ()
552
- with trio .CancelScope () as scope :
553
- handle ._scope = scope
502
+ async def _reader_loop (self , fd , handle ):
503
+ with handle ._scope :
554
504
try :
555
- while not handle . _cancelled : # pragma: no branch
505
+ while True :
556
506
await _wait_readable (fd )
557
- handle ._call_sync ()
507
+ if handle ._cancelled :
508
+ break
509
+ handle ._run ()
558
510
await self .synchronize ()
559
511
except Exception as exc :
560
- _h_raise (handle , exc )
561
- return
562
- finally :
563
- handle ._scope = None
512
+ handle ._raise (exc )
564
513
565
514
# writing to a file descriptor
566
515
@@ -583,7 +532,7 @@ def add_writer(self, fd, callback, *args):
583
532
584
533
def _add_writer (self , fd , callback , * args ):
585
534
self ._check_closed ()
586
- handle = Handle (callback , args , self , context = None , is_sync = True )
535
+ handle = ScopedHandle (callback , args , self )
587
536
writer = self ._set_write_handle (fd , handle )
588
537
if writer is not None :
589
538
writer .cancel ()
@@ -601,20 +550,17 @@ def _set_write_handle(self, fd, handle):
601
550
self ._selector .modify (fd , mask | EVENT_WRITE , (reader , handle ))
602
551
return writer
603
552
604
- async def _writer_loop (self , fd , handle , task_status = trio .TASK_STATUS_IGNORED ):
605
- with trio .CancelScope () as scope :
606
- handle ._scope = scope
607
- task_status .started ()
553
+ async def _writer_loop (self , fd , handle ):
554
+ with handle ._scope :
608
555
try :
609
- while not handle . _cancelled : # pragma: no branch
556
+ while True :
610
557
await _wait_writable (fd )
611
- handle ._call_sync ()
558
+ if handle ._cancelled :
559
+ break
560
+ handle ._run ()
612
561
await self .synchronize ()
613
562
except Exception as exc :
614
- _h_raise (handle , exc )
615
- return
616
- finally :
617
- handle ._scope = None
563
+ handle ._raise (exc )
618
564
619
565
def autoclose (self , fd ):
620
566
"""
@@ -717,7 +663,7 @@ async def _main_loop_one(self, no_wait=False):
717
663
# so restart from the beginning.
718
664
return
719
665
720
- if isinstance (obj , TimerHandle ):
666
+ if isinstance (obj , asyncio . TimerHandle ):
721
667
# A TimerHandle is added to the list of timers.
722
668
heapq .heappush (self ._timers , obj )
723
669
return
@@ -732,13 +678,17 @@ async def _main_loop_one(self, no_wait=False):
732
678
733
679
# Don't go through the expensive nursery dance
734
680
# if this is a sync function.
735
- if getattr (obj , '_is_sync' , True ):
681
+ if isinstance (obj , AsyncHandle ):
682
+ if hasattr (obj , '_context' ):
683
+ obj ._context .run (self ._nursery .start_soon , obj ._run , name = obj ._callback )
684
+ else :
685
+ self ._nursery .start_soon (obj ._run , name = obj ._callback )
686
+ await obj ._started .wait ()
687
+ else :
736
688
if hasattr (obj , '_context' ):
737
689
obj ._context .run (obj ._callback , * obj ._args )
738
690
else :
739
691
obj ._callback (* obj ._args )
740
- else :
741
- await self ._nursery .start (obj ._call_async )
742
692
743
693
async def _main_loop_exit (self ):
744
694
"""Finalize the loop. It may not be re-entered."""
0 commit comments