Repository navigation
Description
Version
main (b36f716, 1.65.1.dev8+gb36f716b5)
Steps to reproduce
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
messages = []
page.on("console", messages.append)
browser.close()Expected behavior
Registering built-in functions/methods (list.append, print, len, re.Pattern.match, set.__contains__), method-wrappers (such as str.__eq__), __slots__ / @dataclass(slots=True) bound methods or callable instances, or @dataclass(frozen=True) callables should work cleanly across event listeners (on, once, remove_listener), expose_function, and route / unroute, receiving public API wrapper objects and supporting removal cleanly.
Actual behavior
ImplToApiMapping.wrap_handler() fails immediately at registration time because it tries to mutate _pw_impl_instance_* attributes onto handler or handler.__self__ via setattr():
Traceback (most recent call last):
File "<string>", line 7, in <module>
page.on('console', messages.append)
~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "playwright/sync_api/_generated.py", line 19326, in on
return super().on(event=event, f=f)
~~~~~~~~~~^^^^^^^^^^^^^^^^^^
File "playwright/_impl/_sync_base.py", line 133, in on
self._impl_obj.on(event, self._wrap_handler(f))
~~~~~~~~~~~~~~~~~~^^^
File "playwright/_impl/_sync_base.py", line 128, in _wrap_handler
return mapping.wrap_handler(handler)
~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
File "playwright/_impl/_impl_to_api_mapping.py", line 159, in wrap_handler
setattr(handler, IMPL_ATTR, wrapper)
~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'builtin_function_or_method' object has no attribute '_pw_impl_instance_' and no __dict__ for setting new attributes
The same failure also occurs for:
page.expose_function("py_log", print)->AttributeError: 'builtin_function_or_method' object has no attribute '_pw_impl_instance_' and no __dict__ for setting new attributespage.route(re.compile(r"https://example\.com/.*").match, ...)->AttributeError: 'builtin_method' object has no attribute '_pw_impl_instance_' and no __dict__ for setting new attributes@dataclass(slots=True)bound method (collector.handle) ->AttributeError: 'SlottedCollector' object has no attribute '_pw_impl_instance_handle' and no __dict__ for setting new attributes@dataclass(slots=True)callable instance (collector) ->AttributeError: 'SlottedCollector' object has no attribute '_pw_impl_instance_' and no __dict__ for setting new attributes
Additional context
Historically, #538 addressed Python MethodType (inspect.ismethod) by attaching _pw_impl_instance_<name> onto handler.__self__, which still assumes either handler or handler.__self__ has a writable __dict__ and leaves built-in functions/bound methods, C method-wrappers, __slots__ objects, and frozen instances broken in both sync and async APIs.
I intend to work on this issue — I have a tested fix (caching wrapped handlers in a WeakValueDictionary keyed without mutating handler or handler.__self__) and sync/async regression tests ready. Happy to submit the PR once triaged/assigned!
Environment
- Operating System: Windows 11 (
Windows-11-10.0.26200-SP0) - Python version: 3.13.1
- Browser: Chromium 158.0.8127.18 (v1254)
- Playwright Python:
main(b36f716)
Activity
microsoft-playwright-automation commentedon Nov 13, 2026
microsoft-playwright-automation commentedon Nov 13, 2026
Hi, I'm the Playwright bot. I reproduced this and prepared a fix.
Reproduced on Windows, Python 3.12.10, main
f68f05ce17d548e6cc21e3cdc592c5b6cb489d20. The handler cache tries to write attributes to user callables. Some native methods also lack signature metadata, so replacing the cache alone does not fix invocation.The proposed fix keeps wrappers in a weak-value cache, preserves handler identity for removal, and calls native handlers without signature metadata with the supplied arguments. It extends the existing sync console test.
Repro and verification
The regression fails at registration on unchanged main with Chromium:
The extended test also checks public
ConsoleMessageobjects, listener removal, andoncewithset.add, which has no inspectable signature.Built the driver from upstream
3b438229c6a2ccdbe2d3572755935892203d83c3. Checked headless Chromium 158.0.8127.18, Firefox 159.0, and WebKit 27.2 on Windows:mypy playwright, serial flake8, the remaining pre-commit hooks, and the test registry check passed. The pinned pre-commit mypy and pyright passed with Linux platform definitions. Default Windows type checks report unavailable POSIX APIs in unchanged code. Full lint generated no source changes, but its flake8 worker pool stalled; the serial run passed.I also checked #3341 at
0576b49d90a8a58a9433c3517370c44e0a26c4ce. Its Chromium listener and exposed-function tests pass, but its route test times out in both APIs: invokingset.__contains__raisesValueErrorduring signature inspection. It is not ready to merge.Draft PR: #3344
Triaged on Windows by the Playwright bot - agent run