33import sys as _sys
44import warnings as _warnings
55
6- from asyncio .events import BaseDefaultEventLoopPolicy as __BasePolicy
7-
86from . import includes as __includes # NOQA
97from .loop import Loop as __BaseLoop # NOQA
108from ._version import __version__ # NOQA
119
1210
13- __all__ = ('new_event_loop' , 'install' , 'EventLoopPolicy' )
11+ __all__ : _typing .Tuple [str , ...] = ('new_event_loop' , 'run' )
12+ _AbstractEventLoop = __asyncio .AbstractEventLoop
1413
1514
1615_T = _typing .TypeVar ("_T" )
1716
1817
19- class Loop (__BaseLoop , __asyncio . AbstractEventLoop ): # type: ignore[misc]
18+ class Loop (__BaseLoop , _AbstractEventLoop ): # type: ignore[misc]
2019 pass
2120
2221
@@ -25,18 +24,6 @@ def new_event_loop() -> Loop:
2524 return Loop ()
2625
2726
28- def install () -> None :
29- """A helper function to install uvloop policy."""
30- if _sys .version_info [:2 ] >= (3 , 12 ):
31- _warnings .warn (
32- 'uvloop.install() is deprecated in favor of uvloop.run() '
33- 'starting with Python 3.12.' ,
34- DeprecationWarning ,
35- stacklevel = 1 ,
36- )
37- __asyncio .set_event_loop_policy (EventLoopPolicy ())
38-
39-
4027if _typing .TYPE_CHECKING :
4128 def run (
4229 main : _typing .Coroutine [_typing .Any , _typing .Any , _T ],
@@ -114,7 +101,7 @@ async def wrapper():
114101 )
115102
116103
117- def _cancel_all_tasks (loop : __asyncio . AbstractEventLoop ) -> None :
104+ def _cancel_all_tasks (loop : _AbstractEventLoop ) -> None :
118105 # Copied from python/cpython
119106
120107 to_cancel = __asyncio .all_tasks (loop )
@@ -139,30 +126,108 @@ def _cancel_all_tasks(loop: __asyncio.AbstractEventLoop) -> None:
139126 })
140127
141128
142- class EventLoopPolicy (__BasePolicy ):
143- """Event loop policy.
129+ _deprecated_names = ('install' , 'EventLoopPolicy' )
130+
131+
132+ if _sys .version_info [:2 ] < (3 , 16 ):
133+ __all__ += _deprecated_names
134+
135+
136+ def __getattr__ (name : str ) -> _typing .Any :
137+ if name not in _deprecated_names :
138+ raise AttributeError (f"module 'uvloop' has no attribute '{ name } '" )
139+ elif _sys .version_info [:2 ] >= (3 , 16 ):
140+ raise AttributeError (
141+ f"module 'uvloop' has no attribute '{ name } ' "
142+ f"(it was removed in Python 3.16, use uvloop.run() instead)"
143+ )
144+
145+ import threading
146+
147+ def install () -> None :
148+ """A helper function to install uvloop policy.
149+
150+ This function is deprecated and will be removed in Python 3.16.
151+ Use `uvloop.run()` instead.
152+ """
153+ if _sys .version_info [:2 ] >= (3 , 12 ):
154+ _warnings .warn (
155+ 'uvloop.install() is deprecated in favor of uvloop.run() '
156+ 'starting with Python 3.12.' ,
157+ DeprecationWarning ,
158+ stacklevel = 1 ,
159+ )
160+ __asyncio .set_event_loop_policy (EventLoopPolicy ())
161+
162+ class EventLoopPolicy (
163+ # This is to avoid a mypy error about AbstractEventLoopPolicy
164+ getattr (__asyncio , 'AbstractEventLoopPolicy' ) # type: ignore[misc]
165+ ):
166+ """Event loop policy for uvloop.
167+
168+ This class is deprecated and will be removed in Python 3.16.
169+ Use `uvloop.run()` instead.
170+
171+ >>> import asyncio
172+ >>> import uvloop
173+ >>> asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
174+ >>> asyncio.get_event_loop()
175+ <uvloop.Loop running=False closed=False debug=False>
176+ """
177+
178+ def _loop_factory (self ) -> Loop :
179+ return new_event_loop ()
180+
181+ if _typing .TYPE_CHECKING :
182+ # EventLoopPolicy doesn't implement these, but since they are
183+ # marked as abstract in typeshed, we have to put them in so mypy
184+ # thinks the base methods are overridden. This is the same approach
185+ # taken for the Windows event loop policy classes in typeshed.
186+ def get_child_watcher (self ) -> _typing .NoReturn :
187+ ...
188+
189+ def set_child_watcher (
190+ self , watcher : _typing .Any
191+ ) -> _typing .NoReturn :
192+ ...
193+
194+ class _Local (threading .local ):
195+ _loop : _typing .Optional [_AbstractEventLoop ] = None
196+
197+ def __init__ (self ) -> None :
198+ self ._local = self ._Local ()
199+
200+ def get_event_loop (self ) -> _AbstractEventLoop :
201+ """Get the event loop for the current context.
202+
203+ Returns an instance of EventLoop or raises an exception.
204+ """
205+ if self ._local ._loop is None :
206+ raise RuntimeError (
207+ 'There is no current event loop in thread %r.'
208+ % threading .current_thread ().name
209+ )
144210
145- The preferred way to make your application use uvloop:
211+ return self . _local . _loop
146212
147- >>> import asyncio
148- >>> import uvloop
149- >>> asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
150- >>> asyncio.get_event_loop()
151- <uvloop.Loop running=False closed=False debug=False>
152- """
213+ def set_event_loop (
214+ self , loop : _typing .Optional [_AbstractEventLoop ]
215+ ) -> None :
216+ """Set the event loop."""
217+ if loop is not None and not isinstance (loop , _AbstractEventLoop ):
218+ raise TypeError (
219+ f"loop must be an instance of AbstractEventLoop or None, "
220+ f"not '{ type (loop ).__name__ } '"
221+ )
222+ self ._local ._loop = loop
153223
154- def _loop_factory (self ) -> Loop :
155- return new_event_loop ()
224+ def new_event_loop (self ) -> Loop :
225+ """Create a new event loop.
156226
157- if _typing .TYPE_CHECKING :
158- # EventLoopPolicy doesn't implement these, but since they are marked
159- # as abstract in typeshed, we have to put them in so mypy thinks
160- # the base methods are overridden. This is the same approach taken
161- # for the Windows event loop policy classes in typeshed.
162- def get_child_watcher (self ) -> _typing .NoReturn :
163- ...
227+ You must call set_event_loop() to make this the current event loop.
228+ """
229+ return self ._loop_factory ()
164230
165- def set_child_watcher (
166- self , watcher : _typing .Any
167- ) -> _typing .NoReturn :
168- ...
231+ globals ()['install' ] = install
232+ globals ()['EventLoopPolicy' ] = EventLoopPolicy
233+ return globals ()[name ]
0 commit comments