Skip to content

fix(handlers): do not evaluate handler annotations in inspect.signature on Python 3.14 - #3204

Merged
Yury Semikhatsky (yury-s) merged 2 commits into
microsoft:mainfrom
ashrafiucse:fix-42857
Sep 23, 2026
Merged

Yury Semikhatsky (yury-s) merged 2 commits into
microsoft:mainfrom
ashrafiucse:fix-42857

Conversation

@ashrafiucse

Copy link
Copy Markdown
Contributor

Summary

  • On Python 3.14, inspect.signature() evaluates the lazily-computed annotations (PEP 649/749) by default, so event listeners and locator handlers annotated with names that only exist under if TYPE_CHECKING: raised NameError when Playwright inspected the handler signature — even though only the parameter list is used.
  • Add a small signature() compat helper that passes annotation_format=Format.FORWARDREF on Python 3.14+ and is a plain inspect.signature() on older versions, and use it at the two call sites (wrap_handler, LocatorHandler.__call__).
  • Regression tests for both paths (event listener + locator handler) in async and sync suites, gated to 3.14+.

Fixes microsoft/playwright#42857

…re on Python 3.14

Since PEP 649 (Python 3.14), annotations are lazily evaluated and
inspect.signature() resolves them eagerly by default. Event listeners
and locator handlers annotated with names that only exist under
`if TYPE_CHECKING:` therefore raised NameError when the signature was
inspected, even though only the parameter list is needed. Ask for
unresolved forward references instead.

Fixes: microsoft/playwright#42857
@yury-s

Copy link
Copy Markdown
Member

The fix itself looks good. The tests fail the lint job, though: mypy and pyright reject the Unresolvable placeholder because it doesn't match Callable[[ConsoleMessage], None] or Callable[[Locator], Any]. Could you alias the real types under TYPE_CHECKING instead, for example from playwright.async_api import ConsoleMessage as TypeCheckingOnlyConsoleMessage? That keeps the name undefined at runtime, type-checks cleanly, and matches the realistic case from the issue.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since both call sites are in shared _impl code, the sync mirrors don't add coverage. Let's drop the two tests/sync/ additions and keep just the async console and locator-handler tests.

…ions

Replace the Unresolvable placeholder with the real handler types
imported under `if TYPE_CHECKING:` and aliased, e.g.
ConsoleMessage as TypeCheckingOnlyConsoleMessage. The alias stays
undefined at runtime (still exercising PEP 649 lazy annotations)
while mypy and pyright accept the handler signatures.
@ashrafiucse

Copy link
Copy Markdown
Contributor Author

Done — replaced the placeholder with TYPE_CHECKING-only aliases of the real types (ConsoleMessage as TypeCheckingOnlyConsoleMessage, Locator as TypeCheckingOnlyLocator) in all four test files. The aliases stay undefined at runtime, so the tests still reproduce the NameError when the fix is reverted, and mypy and pyright are clean now.

@yury-s
Yury Semikhatsky (yury-s) merged commit 99e29c4 into microsoft:main Sep 23, 2026
35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: The Python version of Playwright is not compatible with PEP-749/PEP-649 annotation semantics

2 participants