8000 Enforce using ASYNCIO for the websocket connection, as uvloop is bugg… · SimplyPrint/printer-ws-client@7d47b75 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7d47b75

Browse files
committed
Enforce using ASYNCIO for the websocket connection, as uvloop is bugged. python/cpython#118950
1 parent 7c09ed1 commit 7d47b75

File tree

4 files changed

+41
-12
lines changed

4 files changed

+41
-12
lines changed

simplyprint_ws_client/client/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def run_blocking(self, debug=False, contexts=None):
121121

122122
contexts.append(functools.partial(traceability.enable_traceable, debug))
123123

124-
with EventLoopRunner(debug, contexts) as runner:
124+
with EventLoopRunner(debug, contexts, self.options.event_loop_backend) as runner:
125125
runner.run(self.run())
126126

127127
def run_detached(self, *args, **kwargs):

simplyprint_ws_client/client/options.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from .factory import TClientFactory
88
from .instance import Instance, MultiPrinter, SinglePrinter
99
from ..helpers.url_builder import SimplyPrintBackend
10+
from ..utils.event_loop_runner import EventLoopBackend
1011

1112

1213
class ClientMode(Enum):
@@ -28,6 +29,9 @@ def get_class(self) -> Type[Instance]:
2829
class ClientOptions(NamedTuple):
2930
mode: ClientMode = ClientMode.SINGLE
3031
backend: Optional[SimplyPrintBackend] = None
32+
# UVLoop is bugged, so we default to asyncio.
33+
# See issue_118950_patch.py for mere.
34+
event_loop_backend: EventLoopBackend = EventLoopBackend.ASYNCIO
3135
development: bool = False
3236

3337
# Client name and version used for various purposes.
Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,56 @@
11
import asyncio
22
import contextlib
33
import contextvars
4-
from typing import List, Callable
4+
from enum import Enum
5+
from typing import List, Callable, Optional
56

67
try:
7-
""" Prefer faster event loop implementation. """
8-
from uvloop import run as async_run
8+
import uvloop
99
except ImportError:
10-
from asyncio import run as async_run
10+
uvloop = None
1111

12-
_asyncio_debug_enabled = contextvars.ContextVar("_debug_enabled", default=False)
12+
13+
class EventLoopBackend(Enum):
14+
AUTO = "auto"
15+
UVLOOP = "uvloop"
16+
ASYNCIO = "asyncio"
17+
18+
@property
19+
def runner(self) -> Callable:
20+
if self is EventLoopBackend.AUTO:
21+
# Prefer UVLoop if available
22+
return uvloop.run if uvloop is not None else asyncio.run
23+
24+
if self is EventLoopBackend.UVLOOP:
25+
assert uvloop is not None, "uvloop is not installed"
26+
return uvloop.run
27+
28+
return asyncio.run
29+
30+
31+
_loop_debug_enabled = contextvars.ContextVar("_loop_debug_enabled", default=False)
32+
_loop_backend = contextvars.ContextVar("_loop_backend", default=EventLoopBackend.AUTO)
1333

1434

1535
@contextlib.contextmanager
1636
def enable_asyncio_debug():
17-
token = _asyncio_debug_enabled.set(True)
37+
token = _loop_debug_enabled.set(True)
1838
try:
1939
yield
2040
finally:
21-
_asyncio_debug_enabled.reset(token)
41+
_loop_debug_enabled.reset(token)
2242

2343

2444
class EventLoopRunner:
2545
""" Wrapper around uvloop/asyncio implementations for running the main event loop. """
2646
debug = False
2747
context_stack: List[Callable[[], contextlib.AbstractContextManager]]
48+
backend: Optional[EventLoopBackend] = None
2849

29-
def __init__(self, debug=False, context_stack=None):
50+
def __init__(self, debug=False, context_stack=None, backend=None):
3051
self.debug = debug
3152
self.context_stack = [] if context_stack is None else context_stack
53+
self.backend = backend
3254

3355
def __enter__(self):
3456
return self
@@ -42,6 +64,9 @@ def run(self, *args, **kwargs) -> None:
4264
for context_func in self.context_stack:
4365
stack.enter_context(context_func())
4466

45-
return async_run(*args, debug=_asyncio_debug_enabled.get() or self.debug, **kwargs)
67+ 629A
debug = self.debug or _loop_debug_enabled.get()
68+
backend = self.backend or _loop_backend.get()
69+
70+
return backend.runner(*args, debug=debug, **kwargs)
4671
except asyncio.CancelledError:
4772
pass

simplyprint_ws_client/utils/issue_118950_patch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Implements https://github.com/python/cpython/pull/118960
22
# Without needing to modify the source code of the library.
3+
# UVLoop also experiences this issue, so we default to asyncio.
4+
# Issue: https://github.com/python/cpython/issues/118950
35

4-
import functools
5-
import logging
66
from asyncio.sslproto import _SSLProtocolTransport, SSLProtocol
77

88

0 commit comments

Comments
 (0)
0