Skip to content

[Bug]: AttributeError when registering built-in callables, __slots__, or frozen objects as handlers #3340

Closed

Description

@alok-108

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 attributes
  • page.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

  1. microsoft-playwright-automation commented on Nov 13, 2026

    @microsoft-playwright-automation
  2. microsoft-playwright-automation commented on Nov 13, 2026

    @microsoft-playwright-automation
    Contributor

    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:

    messages = []
    page.on("console", messages.append)
    page.evaluate("console.log('hello')")
    page.remove_listener("console", messages.append)

    The extended test also checks public ConsoleMessage objects, listener removal, and once with set.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:

    • Sync console, exposed-function, route, and sync-API files: 340 passed, 16 skipped, 1 existing upstream xfail.
    • Async listener, console, exposed-function, and route files: 295 passed, 10 skipped, 1 existing upstream xfail.
    • Independent checks in both APIs: built-in handlers, slotted and frozen callables and bound methods, regex/set/method-wrapper route predicates, slotted route handlers, and removal passed on all three browsers. Cache identity and release checks also passed.
    • 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: invoking set.__contains__ raises ValueError during signature inspection. It is not ready to merge.

    Draft PR: #3344

    Triaged on Windows by the Playwright bot - agent run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions