1
1
import asyncio as __asyncio
2
2
import typing as _typing
3
+ import sys as _sys
4
+ import warnings as _warnings
3
5
4
6
from asyncio .events import BaseDefaultEventLoopPolicy as __BasePolicy
5
7
@@ -22,9 +24,103 @@ def new_event_loop() -> Loop:
22
24
23
25
def install () -> None :
24
26
"""A helper function to install uvloop policy."""
27
+ if _sys .version_info [:2 ] >= (3 , 12 ):
28
+ _warnings .warn (
29
+ 'uvloop.install() is deprecated in favor of uvloop.run() '
30
+ 'starting with Python 3.12.' ,
31
+ DeprecationWarning ,
32
+ stacklevel = 1 ,
33
+ )
25
34
__asyncio .set_event_loop_policy (EventLoopPolicy ())
26
35
27
36
37
+ def run (main , * , loop_factory = new_event_loop , debug = None , ** run_kwargs ):
38
+ """The preferred way of running a coroutine with uvloop."""
39
+
40
+ async def wrapper ():
41
+ # If `loop_factory` is provided we want it to return
42
+ # either uvloop.Loop or a subtype of it, assuming the user
43
+ # is using `uvloop.run()` intentionally.
44
+ loop = __asyncio ._get_running_loop ()
45
+ if not isinstance (loop , Loop ):
46
+ raise TypeError ('uvloop.run() uses a non-uvloop event loop' )
47
+ return await main
48
+
49
+ vi = _sys .version_info [:2 ]
50
+
51
+ if vi <= (3 , 10 ):
52
+ # Copied from python/cpython
53
+
54
+ if __asyncio ._get_running_loop () is not None :
55
+ raise RuntimeError (
56
+ "asyncio.run() cannot be called from a running event loop" )
57
+
58
+ if not __asyncio .iscoroutine (main ):
59
+ raise ValueError ("a coroutine was expected, got {!r}" .format (main ))
60
+
61
+ loop = loop_factory ()
62
+ try :
63
+ __asyncio .set_event_loop (loop )
64
+ if debug is not None :
65
+ loop .set_debug (debug )
66
+ return loop .run_until_complete (wrapper ())
67
+ finally :
68
+ try :
69
+ _cancel_all_tasks (loop )
70
+ loop .run_until_complete (loop .shutdown_asyncgens ())
71
+ if hasattr (loop , 'shutdown_default_executor' ):
72
+ loop .run_until_complete (loop .shutdown_default_executor ())
73
+ finally :
74
+ __asyncio .set_event_loop (None )
75
+ loop .close ()
76
+
77
+ elif vi == (3 , 11 ):
78
+ if __asyncio ._get_running_loop () is not None :
79
+ raise RuntimeError (
80
+ "asyncio.run() cannot be called from a running event loop" )
81
+
82
+ with __asyncio .Runner (
83
+ loop_factory = loop_factory ,
84
+ debug = debug ,
85
+ ** run_kwargs
86
+ ) as runner :
87
+ return runner .run (wrapper ())
88
+
89
+ else :
90
+ assert vi >= (3 , 12 )
91
+ return __asyncio .run (
92
+ wrapper (),
93
+ loop_factory = loop_factory ,
94
+ debug = debug ,
95
+ ** run_kwargs
96
+ )
97
+
98
+
99
+ def _cancel_all_tasks (loop ):
100
+ # Copied from python/cpython
101
+
102
+ to_cancel = __asyncio .all_tasks (loop )
103
+ if not to_cancel :
104
+ return
105
+
106
+ for task in to_cancel :
107
+ task .cancel ()
108
+
109
+ loop .run_until_complete (
110
+ __asyncio .gather (* to_cancel , return_exceptions = True )
111
+ )
112
+
113
+ for task in to_cancel :
114
+ if task .cancelled ():
115
+ continue
116
+ if task .exception () is not None :
117
+ loop .call_exception_handler ({
118
+ 'message' : 'unhandled exception during asyncio.run() shutdown' ,
119
+ 'exception' : task .exception (),
120
+ 'task' : task ,
121
+ })
122
+
123
+
28
124
class EventLoopPolicy (__BasePolicy ):
29
125
"""Event loop policy.
30
126
0 commit comments