async def exposeBinding(self, name: str, binding: FunctionWithSource) -> None: if name in self._bindings: raise Error(f'Function "{name}" has been already registered') if name in self._browser_context._bindings: raise Error( f'Function "{name}" has been already registered in the browser context' ) self._bindings[name] = binding await self._channel.send("exposeBinding", dict(name=name))
async def exposeBinding(self, name: str, binding: Callable) -> None: for page in self._pages: if name in page._bindings: raise Error( f'Function "{name}" has been already registered in one of the pages' ) if name in self._bindings: raise Error(f'Function "{name}" has been already registered') self._bindings[name] = binding await self._channel.send("exposeBinding", dict(name=name))
async def exposeBinding( self, name: str, binding: Callable, handle: bool = None ) -> None: if name in self._bindings: raise Error(f'Function "{name}" has been already registered') if name in self._browser_context._bindings: raise Error( f'Function "{name}" has been already registered in the browser context' ) self._bindings[name] = binding await self._channel.send( "exposeBinding", dict(name=name, needsHandle=handle or False) )
async def waitForEvent( self, event: str, predicate: Callable[[Any], bool] = None, timeout: int = None ) -> Any: if timeout is None: timeout = self._timeout_settings.timeout() wait_helper = WaitHelper(self._loop) wait_helper.reject_on_timeout( timeout, f'Timeout while waiting for event "${event}"' ) if event != Page.Events.Crash: wait_helper.reject_on_event(self, Page.Events.Crash, Error("Page crashed")) if event != Page.Events.Close: wait_helper.reject_on_event(self, Page.Events.Close, Error("Page closed")) return await wait_helper.wait_for_event(self, event, predicate)
async def addInitScript(self, source: str = None, path: str = None) -> None: if path: with open(path, "r") as file: source = file.read() if not isinstance(source, str): raise Error("Either path or source parameter must be specified") await self._channel.send("addInitScript", dict(source=source))
def _setup_navigation_wait_helper(self, timeout: int = None) -> WaitHelper: wait_helper = WaitHelper(self._loop) wait_helper.reject_on_event( self._page, "close", Error("Navigation failed because page was closed!") ) wait_helper.reject_on_event( self._page, "crash", Error("Navigation failed because page crashed!") ) wait_helper.reject_on_event( self._page, "framedetached", Error("Navigating frame was detached!"), lambda frame: frame == self, ) if timeout is None: timeout = self._page._timeout_settings.navigation_timeout() wait_helper.reject_on_timeout(timeout, f"Timeout {timeout}ms exceeded.") return wait_helper
async def waitForEvent(self, event: str, predicate: Callable[[Any], bool] = None, timeout: int = None) -> Any: if timeout is None: timeout = cast(Any, self._parent)._timeout_settings.timeout() wait_helper = WaitHelper(self._loop) wait_helper.reject_on_timeout( timeout, f'Timeout while waiting for event "${event}"') if event != WebSocket.Events.Close: wait_helper.reject_on_event(self, WebSocket.Events.Close, Error("Socket closed")) if event != WebSocket.Events.Error: wait_helper.reject_on_event(self, WebSocket.Events.Error, Error("Socket error")) wait_helper.reject_on_event(self._parent, "close", Error("Page closed")) return await wait_helper.wait_for_event(self, event, predicate)
async def waitForLoadState(self, state: DocumentLoadState = None, timeout: int = None) -> None: if not state: state = "load" if state not in ("load", "domcontentloaded", "networkidle"): raise Error( "state: expected one of (load|domcontentloaded|networkidle)") if state in self._load_states: return wait_helper = self._setup_navigation_wait_helper(timeout) await wait_helper.wait_for_event(self._event_emitter, "loadstate", lambda s: s == state)
async def register( self, name: str, source: str = None, path: str = None, contentScript: bool = None, ) -> None: if not source and not path: raise Error("Either source or path should be specified") if path: with open(path, "r") as file: source = file.read() params: Dict = dict(name=name, source=source) if contentScript: params["contentScript"] = True await self._channel.send("register", params)
def to_impl(self, obj: Any) -> Any: try: if not obj: return obj if isinstance(obj, dict): return { name: self.to_impl(value) for name, value in obj.items() } if isinstance(obj, list): return [self.to_impl(item) for item in obj] if isinstance(obj, ImplWrapper): return obj._impl_obj return obj except RecursionError: raise Error("Maximum argument depth exceeded")
def greenlet_main() -> None: loop = None own_loop = None try: loop = asyncio.get_running_loop() except RuntimeError: loop = asyncio.new_event_loop() own_loop = loop if loop.is_running(): raise Error("Can only run one Playwright at a time.") loop.run_until_complete(self._connection.run_as_sync()) if own_loop: loop.run_until_complete(loop.shutdown_asyncgens()) loop.close()
def serialize_value(value: Any, handles: List[JSHandle], depth: int) -> Any: if isinstance(value, JSHandle): h = len(handles) handles.append(value._channel) return dict(h=h) if depth > 100: raise Error("Maximum argument depth exceeded") if value is None: return dict(v="undefined") if isinstance(value, float): if value == float("inf"): return dict(v="Infinity") if value == float("-inf"): return dict(v="-Infinity") if value == float("-0"): return dict(v="-0") if value == float("-0"): return dict(v="-0") if math.isnan(value): return dict(v="NaN") if isinstance(value, datetime): return dict(d=value.isoformat() + "Z") if isinstance(value, bool): return {"b": value} if isinstance(value, int): return {"n": value} if isinstance(value, float): return {"f": value} if isinstance(value, str): return {"s": value} if isinstance(value, list): result = list( map(lambda a: serialize_value(a, handles, depth + 1), value)) return dict(a=result) if isinstance(value, dict): result = [] # type: ignore for name in value: result.append({ "k": name, "v": serialize_value(value[name], handles, depth + 1) }) return dict(o=result) return dict(v="undefined")
async def waitForNavigation( self, timeout: int = None, waitUntil: DocumentLoadState = "load", url: URLMatch = None, ) -> Optional[Response]: wait_helper = self._setup_navigation_wait_helper(timeout) matcher = URLMatcher(url) if url else None event = await wait_helper.wait_for_event( self._event_emitter, "navigated", lambda event: not matcher or matcher.matches(event["url"]), ) if "newDocument" in event and "request" in event["newDocument"]: request = from_channel(event["newDocument"]["request"]) return await request.response() if "error" in event: raise Error(event["error"]) return None
async def waitForNavigation( self, url: URLMatch = None, waitUntil: DocumentLoadState = None, timeout: int = None, ) -> Optional[Response]: if not waitUntil: waitUntil = "load" if timeout is None: timeout = self._page._timeout_settings.navigation_timeout() deadline = monotonic_time() + timeout wait_helper = self._setup_navigation_wait_helper(timeout) matcher = URLMatcher(url) if url else None def predicate(event: Any) -> bool: # Any failed navigation results in a rejection. if event.get("error"): return True return not matcher or matcher.matches(event["url"]) event = await wait_helper.wait_for_event( self._event_emitter, "navigated", predicate=predicate, ) if "error" in event: raise Error(event["error"]) if waitUntil not in self._load_states: timeout = deadline - monotonic_time() if timeout > 0: await self.waitForLoadState(state=waitUntil, timeout=timeout) if "newDocument" in event and "request" in event["newDocument"]: request = from_channel(event["newDocument"]["request"]) return await request.response() return None
def run_driver() -> Connection: loop = asyncio.get_event_loop() if loop.is_running(): raise Error("Can only run one Playwright at a time.") return loop.run_until_complete(run_driver_async())
async def newPage(self) -> Page: if self._owner_page: raise Error("Please use browser.newContext()") return from_channel(await self._channel.send("newPage"))