Repository: microsoft/playwright-python

Issue:
[BUG] NameError: name 'Page' is not defined (bad use of typing.cast() in playwright)
<!-- ⚠️⚠️ Do not delete this template ⚠️⚠️ -->

<!-- 🔎 Search existing issues to avoid creating duplicates. -->
<!-- 🧪 Test using the latest Playwright release to see if your issue has already been fixed -->
<!-- 💡 Provide enough information for us to be able to reproduce your issue locally -->

### System info
- Playwright Version: v1.40.0
- Operating System: All
- Browser: Chromium
- Other info: python3.8/python3.10

### Source code

I didn't prepare code sample since it is an obvious defect in source code.

**Expected**

`Page` class should be defined to use it in [this `cast()` call](https://github.com/microsoft/playwright-python/blob/f371be968607ed2fa8affc75e6fed19179ccf2e9/playwright/_impl/_frame.py#L159C23-L159C23). However, this will cause circular import error. Maybe it's possible to wrap `Page` in quotes (inside `cast()` call), I need to test it.

**Actual**

`Page` class is used in `cast`, however [it's imported only in `typing.TYPE_CHECKING` mode](https://github.com/microsoft/playwright-python/blob/f371be968607ed2fa8affc75e6fed19179ccf2e9/playwright/_impl/_frame.py#L81). It seems like python tries to find `Page` type in runtime while reading arguments for the `cast()`, since `cast()` call is not separated from other runtime calls.

<img width="313" alt="Screenshot 2023-12-30 at 16 40 14" src="https://github.com/microsoft/playwright-python/assets/49389276/a858bf4b-1cef-416a-a50b-c5e86d540098">
<img width="560" alt="Screenshot 2023-12-30 at 16 39 58" src="https://github.com/microsoft/playwright-python/assets/49389276/3d9fb302-d1c8-47a2-951e-fd28f5661729">

Playwright will raise the following error while [executing `_setup_navigation_layer()`](https://github.com/microsoft/playwright-python/blob/f371be968607ed2fa8affc75e6fed19179ccf2e9/playwright/_impl/_frame.py#L153)
```
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/playwright/_impl/_connection.py", line 431, in dispatch object._channel.emit(
File "/usr/local/lib/python3.8/site-packages/pyee/base.py", line 208, in emit handled = self._call_handlers(event, args, kwargs)
File "/usr/local/lib/python3.8/site-packages/pyee/base.py", line 184, in _call_handlers self._emit_run(f, args, kwargs)
File "/usr/local/lib/python3.8/site-packages/pyee/asyncio.py", line 53, in _emit_run self.emit("error", exc)
File "/usr/local/lib/python3.8/site-packages/pyee/base.py", line 211, in emit self._emit_handle_potential_error(event, args[0] if args else None)
File "/usr/local/lib/python3.8/site-packages/pyee/base.py", line 169, in _emit_handle_potential_error raise error
File "/usr/local/lib/python3.8/site-packages/pyee/asyncio.py", line 51, in _emit_run coro: Any = f(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/playwright/_impl/_page.py", line 159, in <lambda> self._channel.on("close", lambda _: self._on_close())
File "/usr/local/lib/python3.8/site-packages/playwright/_impl/_page.py", line 274, in _on_close self.emit(Page.Events.Close, self)
File "/usr/local/lib/python3.8/site-packages/pyee/base.py", line 208, in emit handled = self._call_handlers(event, args, kwargs)
File "/usr/local/lib/python3.8/site-packages/pyee/base.py", line 184, in _call_handlers self._emit_run(f, args, kwargs)
File "/usr/local/lib/python3.8/site-packages/pyee/asyncio.py", line 53, in _emit_run self.emit("error", exc)
File "/usr/local/lib/python3.8/site-packages/pyee/base.py", line 211, in emit self._emit_handle_potential_error(event, args[0] if args else None)
File "/usr/local/lib/python3.8/site-packages/pyee/base.py", line 169, in _emit_handle_potential_error raise error
File "/usr/local/lib/python3.8/site-packages/pyee/asyncio.py", line 51, in _emit_run coro: Any = f(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/playwright/_impl/_waiter.py", line 74, in listener self._reject(error() if callable(error) else error)
File "/usr/local/lib/python3.8/site-packages/playwright/_impl/_frame.py", line 149, in <lambda> lambda: cast(Page, self._page)._close_error_with_reason(),
NameError: name 'Page' is not defined
```

I can prepare fix if it is really needed.


Discussion:

Resolving patch:
diff --git a/playwright/_impl/_frame.py b/playwright/_impl/_frame.py
--- a/playwright/_impl/_frame.py
+++ b/playwright/_impl/_frame.py
@@ -156,7 +156,7 @@ def _setup_navigation_waiter(self, wait_name: str, timeout: float = None) -> Wai
         waiter.reject_on_event(
             self._page,
             "close",
-            lambda: cast(Page, self._page)._close_error_with_reason(),
+            lambda: cast("Page", self._page)._close_error_with_reason(),
         )
         waiter.reject_on_event(
             self._page, "crash", Error("Navigation failed because page crashed!")


Test patch: