Skip to content

Commit cb62205

Browse files
committed
chore(asyncio): simplify cancelled-startup teardown
- reuse __aexit__ for teardown when __aenter__ fails or is cancelled, mirroring the sync context manager - move _stopped_future and wait_until_stopped() into the Transport base, deleting both subclass copies - reuse request_stop() when connect() finishes after a stop request - skip sending __abort__ over a closed connection
1 parent df715cd commit cb62205

5 files changed

Lines changed: 26 additions & 38 deletions

File tree

playwright/_impl/_connection.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -461,16 +461,17 @@ def _send_message_to_server(
461461
async def _abort(
462462
self, object: ChannelOwner, callback: ProtocolCallback, reason: str
463463
) -> None:
464-
try:
465-
self._transport.send(
466-
{
467-
"guid": object._guid,
468-
"method": "__abort__",
469-
"params": {"id": callback.id, "reason": reason},
470-
}
471-
)
472-
except (Error, OSError):
473-
pass
464+
if not self._closed_error:
465+
try:
466+
self._transport.send(
467+
{
468+
"guid": object._guid,
469+
"method": "__abort__",
470+
"params": {"id": callback.id, "reason": reason},
471+
}
472+
)
473+
except (Error, OSError):
474+
pass
474475
try:
475476
await asyncio.wait(
476477
{
@@ -486,11 +487,9 @@ async def _abort(
486487
# retrieved' errors.
487488
if not callback.future.done():
488489
callback.future.cancel()
489-
elif not callback.future.cancelled():
490-
callback.future.exception()
491-
error_future = self._transport.on_error_future
492-
if error_future.done() and not error_future.cancelled():
493-
error_future.exception()
490+
for future in (callback.future, self._transport.on_error_future):
491+
if future.done() and not future.cancelled():
492+
future.exception()
494493

495494
def dispatch(self, msg: ParsedMessagePayload) -> None:
496495
if self._closed_error:

playwright/_impl/_json_pipe.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,7 @@ def dispose(self) -> None:
4242
self.on_error_future.cancel()
4343
self._stopped_future.cancel()
4444

45-
async def wait_until_stopped(self) -> None:
46-
await self._stopped_future
47-
4845
async def connect(self) -> None:
49-
self._stopped_future: asyncio.Future = asyncio.Future()
50-
5146
def handle_message(message: Dict) -> None:
5247
if self._stop_requested:
5348
return

playwright/_impl/_transport.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def __init__(self, loop: asyncio.AbstractEventLoop) -> None:
5050
self._loop = loop
5151
self.on_message: Callable[[ParsedMessagePayload], None] = lambda _: None
5252
self.on_error_future: asyncio.Future = loop.create_future()
53+
self._stopped_future: asyncio.Future = loop.create_future()
5354

5455
@abstractmethod
5556
def request_stop(self) -> None:
@@ -58,9 +59,8 @@ def request_stop(self) -> None:
5859
def dispose(self) -> None:
5960
pass
6061

61-
@abstractmethod
6262
async def wait_until_stopped(self) -> None:
63-
pass
63+
await self._stopped_future
6464

6565
@abstractmethod
6666
async def connect(self) -> None:
@@ -93,7 +93,6 @@ def __init__(self, loop: asyncio.AbstractEventLoop) -> None:
9393
super().__init__(loop)
9494
self._stopped = False
9595
self._output: Optional[asyncio.StreamWriter] = None
96-
self._stopped_future: asyncio.Future = loop.create_future()
9796

9897
def request_stop(self) -> None:
9998
self._stopped = True
@@ -102,9 +101,6 @@ def request_stop(self) -> None:
102101
if self._output:
103102
self._output.close()
104103

105-
async def wait_until_stopped(self) -> None:
106-
await self._stopped_future
107-
108104
async def connect(self) -> None:
109105
try:
110106
# For pyinstaller and Nuitka
@@ -131,14 +127,13 @@ async def connect(self) -> None:
131127
startupinfo=startupinfo,
132128
)
133129
except Exception as exc:
134-
if not self._stopped_future.done():
135-
self._stopped_future.set_result(None)
130+
self._stopped_future.set_result(None)
136131
self.on_error_future.set_exception(exc)
137132
raise exc
138133

139134
self._output = self._proc.stdin
140-
if self._stopped and self._output:
141-
self._output.close()
135+
if self._stopped:
136+
self.request_stop()
142137

143138
async def run(self) -> None:
144139
assert self._proc.stdout

playwright/async_api/_context_manager.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,15 @@ async def __aenter__(self) -> AsyncPlaywright:
4242
{self._connection._transport.on_error_future, playwright_future},
4343
return_when=asyncio.FIRST_COMPLETED,
4444
)
45-
except asyncio.CancelledError:
46-
# Cancelled while connecting - stop the driver process and the
47-
# background tasks, otherwise they keep running with no owner.
4845
if not playwright_future.done():
4946
playwright_future.cancel()
50-
await self._connection.stop_async()
51-
raise
52-
if not playwright_future.done():
47+
playwright = AsyncPlaywright(next(iter(done)).result())
48+
except BaseException:
49+
# Startup failed or was cancelled - stop the driver process and the
50+
# background tasks, otherwise they keep running with no owner.
5351
playwright_future.cancel()
54-
playwright = AsyncPlaywright(next(iter(done)).result())
52+
await self.__aexit__()
53+
raise
5554
playwright.stop = self.__aexit__ # type: ignore
5655
return playwright
5756

tests/async/test_asyncio.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ async def main(delay):
174174
pass
175175
176176
177-
for delay in (0.001, 0.01, 0.05, 0.1, 0.5):
177+
for delay in (0.001, 0.05, 0.5):
178178
asyncio.run(main(delay))
179179
print("DONE", flush=True)
180180
"""

0 commit comments

Comments
 (0)