Skip to content

[Question]: Why I get the error ValueError: I/O operation on closed pipe #1876

@JCHacking

Description

@JCHacking

I am making a layer that wraps Playwright to have more flexibility to changes, one of the parts is to manage browsers, it consists of the following class:

"""Actions on browsers with Playwright."""
from typing import Optional

from playwright.async_api import Playwright, Browser as PlaywrightBrowser, BrowserContext as PlaywrightBrowserContext, \
    async_playwright

from py_web_gui.browser.data import Browser, BrowserData
from py_web_gui.browser.error import BrowserNotStartedError
from py_web_gui.browser.browser_base import BrowserBase


class BrowserPlaywright(BrowserBase):
    """Actions on browsers with Playwright.

    Attributes:
        __playwright: Playwright Manager
        __browsers: Browsers
        __playwright_browsers: Browser names for playwright
        browser_context: Playwright's BrowserContext
    """
    __playwright: Optional[Playwright] = None
    __browsers: dict[Browser, PlaywrightBrowser] = {}
    __playwright_browsers: dict[Browser, str] = {
        Browser.CHROME: "chromium",
        Browser.FIREFOX: "firefox",
        Browser.EDGE: "webkit"
    }

    def __init__(self, browser_data: BrowserData):
        """Actions on browsers with Playwright.

        Args:
            browser_data: Browser Data
        """
        super().__init__(browser_data)
        self.browser_context: Optional[PlaywrightBrowserContext] = None

    async def init(self) -> None:
        """Start browser."""
        if self.__playwright is None:
            self.__playwright = await async_playwright().start()

        if self.browser_data.browser not in self.__browsers.keys():
            self.__browsers[self.browser_data.browser] = await getattr(self.__playwright, self.__playwright_browsers[self.browser_data.browser]).launch(
                    executable_path=self.browser_data.path,
                    headless=False,
                    slow_mo=self.browser_data.cooldown
                )

        self.browser_context = await self.__browsers[self.browser_data.browser].new_context()

    async def close(self) -> None:
        """Closes browser.

        Raises:
            BrowserNotStartedError: Browser not started
        """
        if self.browser_context is None:
            raise BrowserNotStartedError()

        for page in self.browser_context.pages:
            await page.close()

        await self.browser_context.close()
        self.browser_context = None

        if len(self.__browsers[self.browser_data.browser].contexts) <= 0:
            await self.__browsers[self.browser_data.browser].close()
            del self.__browsers[self.browser_data.browser]

        if len(self.__browsers.keys()) <= 0:
            await self.__playwright.stop()  # type: ignore[func-returns-value]
            self.__playwright = None

Testing to see if the previously created class works well, I tried the following code:

import asyncio

from py_web_gui import BrowserBase, BrowserPlaywright, BrowserData, Browser


async def main():
    browsers: list[BrowserPlaywright] = [
        BrowserPlaywright(
            BrowserData(path=r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe", browser=Browser.CHROME)
        ),
        BrowserPlaywright(
            BrowserData(path=r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe", browser=Browser.CHROME)
        )
    ]

    try:
        for browser in browsers:
            await browser.init()

            if browser.browser_context is not None:
                page = await browser.browser_context.new_page()
                await page.goto("https://www.google.es")

        await asyncio.sleep(5)
    finally:
        for browser in browsers:
            await browser.close()

asyncio.run(main())

I get the following error:

Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x000001C403DCEA20>
Traceback (most recent call last):
  File "C:\Python311\Lib\asyncio\proactor_events.py", line 116, in __del__
    _warn(f"unclosed transport {self!r}", ResourceWarning, source=self)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\asyncio\proactor_events.py", line 80, in __repr__
    info.append(f'fd={self._sock.fileno()}')
                      ^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\asyncio\windows_utils.py", line 102, in fileno
    raise ValueError("I/O operation on closed pipe")
ValueError: I/O operation on closed pipe
Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x000001C403DCEA20>
Traceback (most recent call last):
  File "C:\Python311\Lib\asyncio\proactor_events.py", line 116, in __del__
    _warn(f"unclosed transport {self!r}", ResourceWarning, source=self)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\asyncio\proactor_events.py", line 80, in __repr__
    info.append(f'fd={self._sock.fileno()}')
                      ^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\asyncio\windows_utils.py", line 102, in fileno
    raise ValueError("I/O operation on closed pipe")
ValueError: I/O operation on closed pipe
Exception ignored in: <function BaseSubprocessTransport.__del__ at 0x000001C403DCD300>
Traceback (most recent call last):
  File "C:\Python311\Lib\asyncio\base_subprocess.py", line 125, in __del__
    _warn(f"unclosed transport {self!r}", ResourceWarning, source=self)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\asyncio\base_subprocess.py", line 70, in __repr__
    info.append(f'stdin={stdin.pipe}')
                ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\asyncio\proactor_events.py", line 80, in __repr__
    info.append(f'fd={self._sock.fileno()}')
                      ^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\asyncio\windows_utils.py", line 102, in fileno
    raise ValueError("I/O operation on closed pipe")
ValueError: I/O operation on closed pipe

If there is only one in the array of browsers, it does not happen.

Could someone give me some guidance? I understand that it is something that I close or do not close, but I do not see at any time that I am leaving something aside.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions