Skip to content

Commit d66df03

Browse files
committed
Define EventLoopPolicy lazily to avoid warning
1 parent ae50a8e commit d66df03

File tree

1 file changed

+91
-77
lines changed

1 file changed

+91
-77
lines changed

uvloop/__init__.py

Lines changed: 91 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -127,88 +127,102 @@ def _cancel_all_tasks(loop: _AbstractEventLoop) -> None:
127127

128128

129129
if _sys.version_info[:2] < (3, 16):
130-
import threading as _threading
131-
132130
__all__ += ('install', 'EventLoopPolicy')
133131

134-
def install() -> None:
135-
"""A helper function to install uvloop policy.
136-
137-
This function is deprecated and will be removed in Python 3.16.
138-
Use `uvloop.run()` instead.
139-
"""
140-
if _sys.version_info[:2] >= (3, 12):
141-
_warnings.warn(
142-
'uvloop.install() is deprecated in favor of uvloop.run() '
143-
'starting with Python 3.12.',
144-
DeprecationWarning,
145-
stacklevel=1,
146-
)
147-
__asyncio.set_event_loop_policy(EventLoopPolicy())
148-
149-
class EventLoopPolicy(
150-
__asyncio.AbstractEventLoopPolicy # type: ignore
151-
):
152-
"""Event loop policy for uvloop.
153-
154-
This class is deprecated and will be removed in Python 3.16.
155-
Use `uvloop.run()` instead.
156-
157-
>>> import asyncio
158-
>>> import uvloop
159-
>>> asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
160-
>>> asyncio.get_event_loop()
161-
<uvloop.Loop running=False closed=False debug=False>
162-
"""
163-
164-
def _loop_factory(self) -> Loop:
165-
return new_event_loop()
166-
167-
if _typing.TYPE_CHECKING:
168-
# EventLoopPolicy doesn't implement these, but since they are
169-
# marked as abstract in typeshed, we have to put them in so mypy
170-
# thinks the base methods are overridden. This is the same approach
171-
# taken for the Windows event loop policy classes in typeshed.
172-
def get_child_watcher(self) -> _typing.NoReturn:
173-
...
174-
175-
def set_child_watcher(
176-
self, watcher: _typing.Any
177-
) -> _typing.NoReturn:
178-
...
132+
def __getattr__(name: str) -> _typing.Any:
133+
if name not in __all__:
134+
raise AttributeError(f"module 'uvloop' has no attribute '{name}'")
179135

180-
class _Local(_threading.local):
181-
_loop: _typing.Optional[_AbstractEventLoop] = None
136+
import threading
182137

183-
def __init__(self) -> None:
184-
self._local = self._Local()
138+
def install() -> None:
139+
"""A helper function to install uvloop policy.
185140
186-
def get_event_loop(self) -> _AbstractEventLoop:
187-
"""Get the event loop for the current context.
188-
189-
Returns an instance of EventLoop or raises an exception.
141+
This function is deprecated and will be removed in Python 3.16.
142+
Use `uvloop.run()` instead.
190143
"""
191-
if self._local._loop is None:
192-
raise RuntimeError(
193-
'There is no current event loop in thread %r.'
194-
% _threading.current_thread().name
195-
)
196-
197-
return self._local._loop
198-
199-
def set_event_loop(self, loop: _AbstractEventLoop) -> None:
200-
"""Set the event loop."""
201-
if loop is not None and not isinstance(loop, _AbstractEventLoop):
202-
raise TypeError(
203-
f"loop must be an instance of AbstractEventLoop or None, "
204-
f"not '{type(loop).__name__}'"
144+
if _sys.version_info[:2] >= (3, 12):
145+
_warnings.warn(
146+
'uvloop.install() is deprecated in favor of uvloop.run() '
147+
'starting with Python 3.12.',
148+
DeprecationWarning,
149+
stacklevel=1,
205150
)
206-
self._local._loop = loop
207-
208-
def new_event_loop(self) -> Loop:
209-
"""Create a new event loop.
210-
211-
You must call set_event_loop() to make this the current event
212-
loop.
151+
__asyncio.set_event_loop_policy(EventLoopPolicy())
152+
153+
class EventLoopPolicy(
154+
# This is to avoid a mypy error about AbstractEventLoopPolicy
155+
getattr(__asyncio, 'AbstractEventLoopPolicy') # type: ignore[misc]
156+
):
157+
"""Event loop policy for uvloop.
158+
159+
This class is deprecated and will be removed in Python 3.16.
160+
Use `uvloop.run()` instead.
161+
162+
>>> import asyncio
163+
>>> import uvloop
164+
>>> asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
165+
>>> asyncio.get_event_loop()
166+
<uvloop.Loop running=False closed=False debug=False>
213167
"""
214-
return self._loop_factory()
168+
169+
def _loop_factory(self) -> Loop:
170+
return new_event_loop()
171+
172+
if _typing.TYPE_CHECKING:
173+
# EventLoopPolicy doesn't implement these, but since they are
174+
# marked as abstract in typeshed, we have to put them in so
175+
# mypy thinks the base methods are overridden. This is the same
176+
# approach taken for the Windows event loop policy classes in
177+
# typeshed.
178+
def get_child_watcher(self) -> _typing.NoReturn:
179+
...
180+
181+
def set_child_watcher(
182+
self, watcher: _typing.Any
183+
) -> _typing.NoReturn:
184+
...
185+
186+
class _Local(threading.local):
187+
_loop: _typing.Optional[_AbstractEventLoop] = None
188+
189+
def __init__(self) -> None:
190+
self._local = self._Local()
191+
192+
def get_event_loop(self) -> _AbstractEventLoop:
193+
"""Get the event loop for the current context.
194+
195+
Returns an instance of EventLoop or raises an exception.
196+
"""
197+
if self._local._loop is None:
198+
raise RuntimeError(
199+
'There is no current event loop in thread %r.'
200+
% threading.current_thread().name
201+
)
202+
203+
return self._local._loop
204+
205+
def set_event_loop(
206+
self, loop: _typing.Optional[_AbstractEventLoop]
207+
) -> None:
208+
"""Set the event loop."""
209+
if loop is not None and not isinstance(
210+
loop, _AbstractEventLoop
211+
):
212+
raise TypeError(
213+
f"loop must be an instance of AbstractEventLoop or "
214+
f"None, not '{type(loop).__name__}'"
215+
)
216+
self._local._loop = loop
217+
218+
def new_event_loop(self) -> Loop:
219+
"""Create a new event loop.
220+
221+
You must call set_event_loop() to make this the current event
222+
loop.
223+
"""
224+
return self._loop_factory()
225+
226+
globals()['install'] = install
227+
globals()['EventLoopPolicy'] = EventLoopPolicy
228+
return globals()[name]

0 commit comments

Comments
 (0)