Skip to content

[Bug]: 'PlaywrightContextManager' object has no attribute '_playwright' #29379

@Smonkey123

Description

@Smonkey123

Version

1.29.0 and 1.28.0 and 1.41.1

Steps to reproduce

I use this tool embedded into a certain function of my Python program to query and retrieve data from websites. Finally, my Python program is packaged into a folder containing an executable file (exe). I also place the "playwright" and "ms-playwright" (including corresponding versions of browsers) folders into my program folder. This way, I can distribute the program to my colleagues. Everything runs smoothly so far.

I gradually place the program onto SharePoint and utilize OneDrive to synchronize it, ensuring that everyone can conveniently use the program. However, after updating the program once, I encountered an error as indicated in the title. It occurs at line 90 in "playwright/sync_api/_context_manager.py" within the enter function, specifically at "playwright = self._playwright".

To understand the program’s execution flow, I reviewed the code. In my program, I use with sync_playwright() as playwright: run(playwright) where sync_playwright() creates an instance of the PlaywrightContextManager class based on the definition in playwright/sync_api/init.py. This class includes init, enter, start, and exit functions. Upon investigation, it appears that the execution of the enter function is incomplete. To troubleshoot, I added logging to the code. Here is the specific code snippet:

import logging

logging.basicConfig(
    level=logging.DEBUG, 
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'  
)
logger = logging.getLogger(__name__) 



class PlaywrightContextManager:
    def __init__(self) -> None:
        self._playwright: SyncPlaywright
        self._loop: asyncio.AbstractEventLoop
        self._own_loop = False
        self._watcher: Optional[asyncio.AbstractChildWatcher] = None

    def __enter__(self) -> SyncPlaywright:
        try:
            self._loop = asyncio.get_running_loop()
        except RuntimeError:
            self._loop = asyncio.new_event_loop()
            self._own_loop = True
        if self._loop.is_running():
            raise Error(
                """It looks like you are using Playwright Sync API inside the asyncio loop.
Please use the Async API instead."""
            )

        # In Python 3.7, asyncio.Process.wait() hangs because it does not use ThreadedChildWatcher
        # which is used in Python 3.8+. This is unix specific and also takes care about
        # cleaning up zombie processes. See https://bugs.python.org/issue35621
        if (
            sys.version_info[0] == 3
            and sys.version_info[1] == 7
            and sys.platform != "win32"
            and isinstance(asyncio.get_child_watcher(), asyncio.SafeChildWatcher)
        ):
            from ._py37ThreadedChildWatcher import ThreadedChildWatcher  # type: ignore

            self._watcher = ThreadedChildWatcher()
            asyncio.set_child_watcher(self._watcher)  # type: ignore

        # Create a new fiber for the protocol dispatcher. It will be pumping events
        # until the end of times. We will pass control to that fiber every time we
        # block while waiting for a response.
        def greenlet_main() -> None:
            self._loop.run_until_complete(self._connection.run_as_sync())

        dispatcher_fiber = greenlet(greenlet_main)

        # NEW
        logger.debug('Establishing connection...')

        self._connection = Connection(
            dispatcher_fiber,
            create_remote_object,
            PipeTransport(self._loop, compute_driver_executable()),
            self._loop,
        )

        g_self = greenlet.getcurrent()

        def callback_wrapper(channel_owner: ChannelOwner) -> None:
            logger.debug('Callback wrapper called. Creating SyncPlaywright object...')
            playwright_impl = cast(Playwright, channel_owner)
            self._playwright = SyncPlaywright(playwright_impl)
            g_self.switch()

        # NEW
        logger.debug('Starting the dispatcher fiber...')

        # Switch control to the dispatcher, it'll fire an event and pass control to
        # the calling greenlet.
        self._connection.call_on_object_with_known_name("Playwright", callback_wrapper)

        # NEW
        logger.debug('Dispatcher fiber started. Switching back to parent greenlet...')

        dispatcher_fiber.switch()

        # NEW
        if hasattr(self, '_playwright'):
            logger.debug('Playwright has been successfully initialized.')
        else:
            logger.error('Playwright initialization failed: _playwright attribute not found.')

        playwright = self._playwright
        playwright.stop = self.__exit__  # type: ignore
        return playwright

Capture

Expected behavior

This screenshot is of a local program that has not been uploaded to Sharepoint. It runs without any issues, and Playwright functions properly.

Capture1

Actual behavior

The problem I encountered when syncing from Sharepoint to OneDrive is that Playwright is not functioning properly when running the file.
Capture

捕获

Additional context

No response

Environment

System:
    OS: Windows 10
    CPU: Intel(R) Core(TM) i5-10310U CPU @ 1.70GHz   2.21 GHz
Packages:
    Playwright:1.28.0/1.29.0/1.35.0/1.41.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions