-
Notifications
You must be signed in to change notification settings - Fork 1k
Closed
Labels
Description
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.