Skip to content

Commit a5140e5

Browse files
fix(sync): deactivate resume callbacks when waits end
Fixes: #3307
1 parent 0fcb2ee commit a5140e5

2 files changed

Lines changed: 12 additions & 3 deletions

File tree

‎playwright/_impl/_greenlets.py‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,14 @@ def wait_for_future(
9494
) -> None:
9595
__tracebackhide__ = True
9696
g_self = greenlet.getcurrent()
97+
waiting = True
9798

9899
def resume(_: "asyncio.Future") -> None:
99-
g_self.switch()
100+
if waiting:
101+
g_self.switch()
100102

101103
# The wait owns the callback that resumes this greenlet, so that it can
102-
# remove it again when the wait is abandoned. A callback left behind would
104+
# remove it again when the wait ends. A callback left behind would
103105
# resume this greenlet at an arbitrary later point.
104106
future.add_done_callback(resume)
105107
try:
@@ -114,10 +116,13 @@ def resume(_: "asyncio.Future") -> None:
114116
# waited for the driver, see greenlet_main in _context_manager.py.
115117
dispatcher_fiber.switch()
116118
except BaseException:
117-
future.remove_done_callback(resume)
118119
future.cancel()
119120
raise
120121
finally:
122+
# A done future has already queued its callbacks; removing them from the
123+
# future cannot stop them, so also make a queued callback inactive.
124+
waiting = False
125+
future.remove_done_callback(resume)
121126
# The loop is only running for as long as the dispatcher fiber is alive.
122127
# Also after a signal handler interrupted it: run_forever() cleared this
123128
# on its way out, but the dispatcher is going to run the loop again.

‎tests/sync/python/test_sync.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ def _test_call_sync_method_after_playwright_close_with_own_loop(
186186
context = browser.new_context()
187187
page = context.new_page()
188188
page.goto(empty_page)
189+
with page.expect_console_message() as console_info:
190+
page.evaluate("console.log('hello')")
191+
assert console_info.value.text == "hello"
189192
playwright.stop()
190193
with pytest.raises(Error) as exc:
191194
page.evaluate("1+1")
@@ -196,6 +199,7 @@ def _test_call_sync_method_after_playwright_close_with_own_loop(
196199
def test_call_sync_method_after_playwright_close_with_own_loop(
197200
server: Server, browser_name: str, launch_arguments: Dict[str, Any]
198201
) -> None:
202+
# Regression test for https://github.com/microsoft/playwright-python/issues/3307.
199203
p = multiprocessing.get_context("spawn").Process(
200204
target=_test_call_sync_method_after_playwright_close_with_own_loop,
201205
args=[browser_name, launch_arguments, server.EMPTY_PAGE],

0 commit comments

Comments
 (0)