Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions playwright/_impl/_browser_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,15 +257,8 @@ def handle_transport_close(reason: Optional[str]) -> None:
for page in context.pages:
page._on_close()
context._on_close()
connection.cleanup(reason)
# Give a chance to any API call promises to reject upon page/context closure.
# This happens naturally when we receive page.onClose and browser.onClose from the server
# in separate tasks. However, upon pipe closure we used to dispatch them all synchronously
# here and promises did not have a chance to reject.
# The order of rejects vs closure is a part of the API contract and our test runner
# relies on it to attribute rejections to the right test.
if browser:
connection._loop.call_soon(browser._on_close)
connection.cleanup(reason)

transport.once("close", handle_transport_close)

Expand Down
43 changes: 20 additions & 23 deletions playwright/_impl/_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,23 +144,14 @@ async def _inner_send(
self._object, method, augmented_params, timeout
)
try:
done, _ = await asyncio.wait(
{
self._connection._transport.on_error_future,
callback.future,
},
return_when=asyncio.FIRST_COMPLETED,
)
result = await callback.future
except asyncio.CancelledError as exc:
await self._connection._abort(
self._object,
callback,
str(exc) or "Task was cancelled",
)
raise
if not callback.future.done():
callback.future.cancel()
result = next(iter(done)).result()
# Protocol now has named return values, assume result is one level deeper unless
# there is explicit ambiguity.
if not result:
Expand Down Expand Up @@ -351,9 +342,20 @@ async def init() -> None:
if not self.playwright_future.done():
self.playwright_future.set_exception(exc)

await self._transport.connect()
self._init_task = self._loop.create_task(init())
await self._transport.run()
try:
await self._transport.connect()
self._init_task = self._loop.create_task(init())
await self._transport.run()
finally:
cause = None
if (
self._transport.on_error_future.done()
and not self._transport.on_error_future.cancelled()
):
transport_exc = self._transport.on_error_future.exception()
if transport_exc is not None:
cause = str(transport_exc)
self.cleanup(cause)

def stop_sync(self) -> None:
self._transport.request_stop()
Expand All @@ -367,6 +369,8 @@ async def stop_async(self) -> None:
self.cleanup()

def cleanup(self, cause: str = None) -> None:
if self._closed_error:
return
self._closed_error = TargetClosedError(cause) if cause else TargetClosedError()
if self._init_task and not self._init_task.done():
self._init_task.cancel()
Expand Down Expand Up @@ -463,19 +467,12 @@ async def _abort(
except (Error, OSError):
pass
try:
done, _ = await asyncio.wait(
{
self._transport.on_error_future,
callback.future,
},
return_when=asyncio.FIRST_COMPLETED,
)
await callback.future
except (Exception, asyncio.CancelledError):
pass
finally:
if not callback.future.done():
callback.future.cancel()
for future in done:
if not future.cancelled():
future.exception()

def dispatch(self, msg: ParsedMessagePayload) -> None:
if self._closed_error:
Expand Down