16
16
import sys
17
17
import threading
18
18
import traceback
19
+ import warnings
20
+ import contextlib
19
21
20
22
from asyncio import compat
21
23
@@ -507,28 +509,52 @@ def get_debug(self):
507
509
def set_debug (self , enabled ):
508
510
raise NotImplementedError
509
511
512
+ # Running context
513
+
514
+ def _running_context (self ):
515
+ return get_event_loop_policy ().running_loop_context (self )
516
+
510
517
511
518
class AbstractEventLoopPolicy :
512
519
"""Abstract policy for accessing the event loop."""
513
520
514
- def get_event_loop (self ):
515
- """Get the event loop for the current context.
521
+ def get_default_loop (self ):
522
+ """Get the default event loop for the current context.
516
523
517
524
Returns an event loop object implementing the BaseEventLoop interface,
518
525
or raises an exception in case no event loop has been set for the
519
526
current context and the current policy does not specify to create one.
520
527
521
- It should never return None."""
528
+ It should never return None.
529
+ """
530
+ raise NotImplementedError
531
+
532
+ def set_default_loop (self , loop ):
533
+ """Set the default event loop for the current context to loop."""
522
534
raise NotImplementedError
523
535
524
- def set_event_loop (self , loop ):
525
- """Set the event loop for the current context to loop."""
536
+ def get_running_loop (self ):
537
+ """Get the running event loop running for the current context, if any.
538
+
539
+ Returns an event loop object implementing the BaseEventLoop interface.
540
+ If no running loop is set, it returns None.
541
+ """
542
+ raise NotImplementedError
543
+
544
+ def set_running_loop (self , loop ):
545
+ """Set the running event loop for the current context.
546
+
547
+ The loop argument can be None to clear the former running loop.
548
+ This method should be called by the event loop itself to set the
549
+ running loop when it starts, and clear it when it's done.
550
+ """
526
551
raise NotImplementedError
527
552
528
553
def new_event_loop (self ):
529
554
"""Create and return a new event loop object according to this
530
- policy's rules. If there's need to set this loop as the event loop for
531
- the current context, set_event_loop must be called explicitly."""
555
+ policy's rules. If there's need to set this loop as the default loop
556
+ for the current context, set_event_loop must be called explicitly.
557
+ """
532
558
raise NotImplementedError
533
559
534
560
# Child processes handling (Unix only).
@@ -541,6 +567,37 @@ def set_child_watcher(self, watcher):
541
567
"""Set the watcher for child processes."""
542
568
raise NotImplementedError
543
569
570
+ # Non-abstract methods
571
+
572
+ def get_event_loop (self ):
573
+ """Return the running event loop if any, and the default event
574
+ loop otherwise.
575
+ """
576
+ running_loop = self .get_running_loop ()
577
+ if running_loop is not None :
578
+ return running_loop
579
+ return self .get_default_loop ()
580
+
581
+ def set_event_loop (self , loop ):
582
+ """Set the default event loop if the former loop is not currently
583
+ running.
584
+ """
585
+ if self .get_running_loop () is not None :
586
+ raise RuntimeError ('The former loop is currently running' )
587
+ self .set_default_loop (loop )
588
+
589
+ @contextlib .contextmanager
590
+ def running_loop_context (self , loop ):
591
+ """Convenience context to set and clear the given loop as running
592
+ loop. It is meant to be used inside the loop run methods.
593
+ """
594
+ assert isinstance (loop , AbstractEventLoop )
595
+ self .set_running_loop (loop )
596
+ try :
597
+ yield
598
+ finally :
599
+ self .set_running_loop (None )
600
+
544
601
545
602
class BaseDefaultEventLoopPolicy (AbstractEventLoopPolicy ):
546
603
"""Default policy implementation for accessing the event loop.
@@ -556,16 +613,23 @@ class BaseDefaultEventLoopPolicy(AbstractEventLoopPolicy):
556
613
"""
557
614
558
615
_loop_factory = None
616
+ _warnings = True
559
617
560
618
class _Local (threading .local ):
561
619
_loop = None
620
+ _running_loop = None
562
621
_set_called = False
563
622
564
623
def __init__ (self ):
565
624
self ._local = self ._Local ()
566
625
567
- def get_event_loop (self ):
568
- """Get the event loop.
626
+ def warn (self , * args ):
627
+ if self ._warnings :
628
+ raise RuntimeError (* args )
629
+ warnings .warn (* args )
630
+
631
+ def get_default_loop (self ):
632
+ """Get the default event loop for the current thread.
569
633
570
634
This may be None or an instance of EventLoop.
571
635
"""
@@ -578,12 +642,38 @@ def get_event_loop(self):
578
642
% threading .current_thread ().name )
579
643
return self ._local ._loop
580
644
581
- def set_event_loop (self , loop ):
582
- """Set the event loop."""
645
+ def set_default_loop (self , loop ):
646
+ """Set the default event loop for the current thread ."""
583
647
self ._local ._set_called = True
584
648
assert loop is None or isinstance (loop , AbstractEventLoop )
585
649
self ._local ._loop = loop
586
650
651
+ def get_running_loop (self ):
652
+ """Get the running event loop for the current thread if any.
653
+
654
+ This may be None or an instance of EventLoop.
655
+ """
656
+ return self ._local ._running_loop
657
+
658
+ def set_running_loop (self , loop ):
659
+ """Set the running event loop for the current thread."""
660
+ assert loop is None or isinstance (loop , AbstractEventLoop )
661
+ default_loop = self ._local ._loop
662
+ running_loop = self ._local ._running_loop
663
+ if running_loop is not None and loop is not None :
664
+ raise RuntimeError ('A loop is already running' )
665
+ # Warnings
666
+ if loop is not None :
667
+ if default_loop is None :
668
+ self .warn (
669
+ 'Running a loop with no default loop set' ,
670
+ RuntimeWarning )
671
+ elif loop != default_loop :
672
+ self .warn (
673
+ 'Running a loop different from the default loop' ,
674
+ RuntimeWarning )
675
+ self ._local ._running_loop = loop
676
+
587
677
def new_event_loop (self ):
588
678
"""Create a new event loop.
589
679
0 commit comments