def __init__(self, parent: ChannelOwner, type: str, guid: str, initializer: Dict) -> None: super().__init__(parent, type, guid, initializer) self._pages: List[Page] = [] self._routes: List[RouteHandlerEntry] = [] self._bindings: Dict[str, Any] = {} self._pending_wait_for_events: List[PendingWaitEvent] = [] self._timeout_settings = TimeoutSettings(None) self._browser: Optional["Browser"] = None self._owner_page: Optional[Page] = None self._is_closed_or_closing = False self._options: Dict[str, Any] = {} self._channel.on( "bindingCall", lambda params: self._on_binding(from_channel(params["binding"])), ) self._channel.on("close", lambda _: self._on_close()) self._channel.on( "page", lambda params: self._on_page(from_channel(params["page"]))) self._channel.on( "route", lambda params: self._on_route(from_channel(params.get("route")), from_channel(params.get("request"))), )
class BrowserContext(ChannelOwner): Events = SimpleNamespace( Close="close", Page="page", ) def __init__(self, parent: ChannelOwner, type: str, guid: str, initializer: Dict) -> None: super().__init__(parent, type, guid, initializer) self._pages: List[Page] = [] self._routes: List[RouteHandlerEntry] = [] self._bindings: Dict[str, Any] = {} self._pending_wait_for_events: List[PendingWaitEvent] = [] self._timeout_settings = TimeoutSettings(None) self._browser: Optional["Browser"] = None self._owner_page: Optional[Page] = None self._is_closed_or_closing = False self._options: Dict[str, Any] = {} self._channel.on( "bindingCall", lambda params: self._on_binding(from_channel(params["binding"])), ) self._channel.on("close", lambda _: self._on_close()) self._channel.on( "page", lambda params: self._on_page(from_channel(params["page"]))) self._channel.on( "route", lambda params: self._on_route(from_channel(params.get("route")), from_channel(params.get("request"))), ) def _on_page(self, page: Page) -> None: page._set_browser_context(self) self._pages.append(page) self.emit(BrowserContext.Events.Page, page) def _on_route(self, route: Route, request: Request) -> None: for handler_entry in self._routes: if handler_entry.matcher.matches(request.url): handler_entry.handler(route, request) return asyncio.create_task(route.continue_()) def _on_binding(self, binding_call: BindingCall) -> None: func = self._bindings.get(binding_call._initializer["name"]) if func is None: return asyncio.create_task(binding_call.call(func)) def setDefaultNavigationTimeout(self, timeout: int) -> None: self._timeout_settings.set_navigation_timeout(timeout) self._channel.send_no_reply("setDefaultNavigationTimeoutNoReply", dict(timeout=timeout)) def setDefaultTimeout(self, timeout: int) -> None: self._timeout_settings.set_timeout(timeout) self._channel.send_no_reply("setDefaultTimeoutNoReply", dict(timeout=timeout)) @property def pages(self) -> List[Page]: return self._pages.copy() @property def browser(self) -> Optional["Browser"]: return self._browser async def newPage(self) -> Page: if self._owner_page: raise Error("Please use browser.newContext()") return from_channel(await self._channel.send("newPage")) async def cookies(self, urls: Union[str, List[str]] = None) -> List[Cookie]: if urls is None: urls = [] if not isinstance(urls, list): urls = [urls] return await self._channel.send("cookies", dict(urls=urls)) async def addCookies(self, cookies: List[Cookie]) -> None: await self._channel.send("addCookies", dict(cookies=cookies)) async def clearCookies(self) -> None: await self._channel.send("clearCookies") async def grantPermissions(self, permissions: List[str], origin: str = None) -> None: await self._channel.send("grantPermissions", locals_to_params(locals())) async def clearPermissions(self) -> None: await self._channel.send("clearPermissions") async def setGeolocation(self, geolocation: Optional[Geolocation]) -> None: await self._channel.send("setGeolocation", locals_to_params(locals())) async def setExtraHTTPHeaders(self, headers: Dict[str, str]) -> None: await self._channel.send("setExtraHTTPHeaders", dict(headers=serialize_headers(headers))) async def setOffline(self, offline: bool) -> None: await self._channel.send("setOffline", dict(offline=offline)) async def addInitScript(self, source: str = None, path: Union[str, Path] = 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)) async def exposeBinding(self, name: str, binding: Callable, handle: bool = None) -> 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, needsHandle=handle or False)) async def exposeFunction(self, name: str, binding: Callable) -> None: await self.exposeBinding(name, lambda source, *args: binding(*args)) async def route(self, url: URLMatch, handler: RouteHandler) -> None: self._routes.append(RouteHandlerEntry(URLMatcher(url), handler)) if len(self._routes) == 1: await self._channel.send("setNetworkInterceptionEnabled", dict(enabled=True)) async def unroute(self, url: URLMatch, handler: Optional[RouteHandler] = None) -> None: self._routes = list( filter( lambda r: r.matcher.match != url or (handler and r.handler != handler), self._routes, )) if len(self._routes) == 0: await self._channel.send("setNetworkInterceptionEnabled", dict(enabled=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 != BrowserContext.Events.Close: wait_helper.reject_on_event(self, BrowserContext.Events.Close, Error("Context closed")) return await wait_helper.wait_for_event(self, event, predicate) def _on_close(self) -> None: self._is_closed_or_closing = True if self._browser: self._browser._contexts.remove(self) for pending_event in self._pending_wait_for_events: if pending_event.event == BrowserContext.Events.Close: continue pending_event.reject(False, "Context") self.emit(BrowserContext.Events.Close) async def close(self) -> None: if self._is_closed_or_closing: return self._is_closed_or_closing = True try: await self._channel.send("close") except Exception as e: if not is_safe_close_error(e): raise e async def storageState(self) -> StorageState: return await self._channel.send_return_as_dict("storageState") def expect_event( self, event: str, predicate: Callable[[Any], bool] = None, timeout: int = None, ) -> EventContextManagerImpl: return EventContextManagerImpl( self.waitForEvent(event, predicate, timeout)) def expect_page( self, predicate: Callable[[Page], bool] = None, timeout: int = None, ) -> EventContextManagerImpl[Page]: return EventContextManagerImpl( self.waitForEvent("page", predicate, timeout))
def _set_browser_context(self, context: "BrowserContext") -> None: self._browser_context = context self._timeout_settings = TimeoutSettings(context._timeout_settings)
class Page(ChannelOwner): Events = SimpleNamespace( Close="close", Crash="crash", Console="console", Dialog="dialog", Download="download", FileChooser="filechooser", DOMContentLoaded="domcontentloaded", PageError="pageerror", Request="request", Response="response", RequestFailed="requestfailed", RequestFinished="requestfinished", FrameAttached="frameattached", FrameDetached="framedetached", FrameNavigated="framenavigated", Load="load", Popup="popup", WebSocket="websocket", Worker="worker", ) accessibility: Accessibility keyboard: Keyboard mouse: Mouse touchscreen: Touchscreen def __init__(self, parent: ChannelOwner, type: str, guid: str, initializer: Dict) -> None: super().__init__(parent, type, guid, initializer) self.accessibility = Accessibility(self._channel) self.keyboard = Keyboard(self._channel) self.mouse = Mouse(self._channel) self.touchscreen = Touchscreen(self._channel) self._main_frame: Frame = from_channel(initializer["mainFrame"]) self._main_frame._page = self self._frames = [self._main_frame] vs = initializer.get("viewportSize") self._viewport_size: Optional[Tuple[int, int]] = ((vs["width"], vs["height"]) if vs else None) self._is_closed = False self._workers: List["Worker"] = [] self._bindings: Dict[str, Any] = {} self._pending_wait_for_events: List[PendingWaitEvent] = [] self._routes: List[RouteHandlerEntry] = [] self._owned_context: Optional["BrowserContext"] = None self._timeout_settings: TimeoutSettings = TimeoutSettings(None) self._video: Optional[Video] = None self._channel.on( "bindingCall", lambda params: self._on_binding(from_channel(params["binding"])), ) self._channel.on("close", lambda _: self._on_close()) self._channel.on( "console", lambda params: self.emit(Page.Events.Console, from_channel(params["message"])), ) self._channel.on("crash", lambda _: self._on_crash()) self._channel.on( "dialog", lambda params: self.emit(Page.Events.Dialog, from_channel(params["dialog"])), ) self._channel.on("domcontentloaded", lambda _: self.emit(Page.Events.DOMContentLoaded)) self._channel.on( "download", lambda params: self.emit(Page.Events.Download, from_channel(params["download"])), ) self._channel.on( "fileChooser", lambda params: self.emit( Page.Events.FileChooser, FileChooser(self, from_channel(params["element"]), params[ "isMultiple"]), ), ) self._channel.on( "frameAttached", lambda params: self._on_frame_attached( from_channel(params["frame"])), ) self._channel.on( "frameDetached", lambda params: self._on_frame_detached( from_channel(params["frame"])), ) self._channel.on("load", lambda _: self.emit(Page.Events.Load)) self._channel.on( "pageError", lambda params: self.emit(Page.Events.PageError, parse_error(params["error"]["error"])), ) self._channel.on( "popup", lambda params: self.emit(Page.Events.Popup, from_channel(params["page"])), ) self._channel.on( "request", lambda params: self.emit(Page.Events.Request, from_channel(params["request"])), ) self._channel.on( "requestFailed", lambda params: self._on_request_failed( from_channel(params["request"]), params["responseEndTiming"], params["failureText"], ), ) self._channel.on( "requestFinished", lambda params: self._on_request_finished( from_channel(params["request"]), params["responseEndTiming"]), ) self._channel.on( "response", lambda params: self.emit(Page.Events.Response, from_channel(params["response"])), ) self._channel.on( "route", lambda params: self._on_route(from_channel(params["route"]), from_channel(params["request"])), ) self._channel.on( "video", lambda params: cast(Video, self.video)._set_relative_path(params[ "relativePath"]), ) self._channel.on( "webSocket", lambda params: self.emit(Page.Events.WebSocket, from_channel(params["webSocket"])), ) self._channel.on( "worker", lambda params: self._on_worker(from_channel(params["worker"]))) def _set_browser_context(self, context: "BrowserContext") -> None: self._browser_context = context self._timeout_settings = TimeoutSettings(context._timeout_settings) def _on_request_failed( self, request: Request, response_end_timing: float, failure_text: str = None, ) -> None: request._failure_text = failure_text if request._timing: request._timing["responseEnd"] = response_end_timing self.emit(Page.Events.RequestFailed, request) def _on_request_finished(self, request: Request, response_end_timing: float) -> None: if request._timing: request._timing["responseEnd"] = response_end_timing self.emit(Page.Events.RequestFinished, request) def _on_frame_attached(self, frame: Frame) -> None: frame._page = self self._frames.append(frame) self.emit(Page.Events.FrameAttached, frame) def _on_frame_detached(self, frame: Frame) -> None: self._frames.remove(frame) frame._detached = True self.emit(Page.Events.FrameDetached, frame) def _on_route(self, route: Route, request: Request) -> None: for handler_entry in self._routes: if handler_entry.matcher.matches(request.url): result = cast(Any, handler_entry.handler)(route, request) if inspect.iscoroutine(result): asyncio.create_task(result) return self._browser_context._on_route(route, request) def _on_binding(self, binding_call: "BindingCall") -> None: func = self._bindings.get(binding_call._initializer["name"]) if func: asyncio.create_task(binding_call.call(func)) self._browser_context._on_binding(binding_call) def _on_worker(self, worker: "Worker") -> None: self._workers.append(worker) worker._page = self self.emit(Page.Events.Worker, worker) def _on_close(self) -> None: self._is_closed = True self._browser_context._pages.remove(self) self._reject_pending_operations(False) self.emit(Page.Events.Close) def _on_crash(self) -> None: self._reject_pending_operations(True) self.emit(Page.Events.Crash) def _reject_pending_operations(self, is_crash: bool) -> None: for pending_event in self._pending_wait_for_events: pending_event.reject(is_crash, "Page") def _add_event_handler(self, event: str, k: Any, v: Any) -> None: if event == Page.Events.FileChooser and len( self.listeners(event)) == 0: self._channel.send_no_reply("setFileChooserInterceptedNoReply", {"intercepted": True}) super()._add_event_handler(event, k, v) def remove_listener(self, event: str, f: Any) -> None: super().remove_listener(event, f) if event == Page.Events.FileChooser and len( self.listeners(event)) == 0: self._channel.send_no_reply("setFileChooserInterceptedNoReply", {"intercepted": False}) @property def context(self) -> "BrowserContext": return self._browser_context async def opener(self) -> Optional["Page"]: return from_nullable_channel(await self._channel.send("opener")) @property def mainFrame(self) -> Frame: return self._main_frame def frame(self, name: str = None, url: URLMatch = None) -> Optional[Frame]: matcher = URLMatcher(url) if url else None for frame in self._frames: if name and frame.name == name: return frame if url and matcher and matcher.matches(frame.url): return frame return None @property def frames(self) -> List[Frame]: return self._frames.copy() def setDefaultNavigationTimeout(self, timeout: int) -> None: self._timeout_settings.set_navigation_timeout(timeout) self._channel.send_no_reply("setDefaultNavigationTimeoutNoReply", dict(timeout=timeout)) def setDefaultTimeout(self, timeout: int) -> None: self._timeout_settings.set_timeout(timeout) self._channel.send_no_reply("setDefaultTimeoutNoReply", dict(timeout=timeout)) async def querySelector(self, selector: str) -> Optional[ElementHandle]: return await self._main_frame.querySelector(selector) async def querySelectorAll(self, selector: str) -> List[ElementHandle]: return await self._main_frame.querySelectorAll(selector) async def waitForSelector( self, selector: str, timeout: int = None, state: Literal["attached", "detached", "hidden", "visible"] = None, ) -> Optional[ElementHandle]: return await self._main_frame.waitForSelector( **locals_to_params(locals())) async def dispatchEvent(self, selector: str, type: str, eventInit: Dict = None, timeout: int = None) -> None: return await self._main_frame.dispatchEvent( **locals_to_params(locals())) async def evaluate(self, expression: str, arg: Serializable = None, force_expr: bool = None) -> Any: return await self._main_frame.evaluate(expression, arg, force_expr=force_expr) async def evaluateHandle(self, expression: str, arg: Serializable = None, force_expr: bool = None) -> JSHandle: return await self._main_frame.evaluateHandle(expression, arg, force_expr=force_expr) async def evalOnSelector( self, selector: str, expression: str, arg: Serializable = None, force_expr: bool = None, ) -> Any: return await self._main_frame.evalOnSelector(selector, expression, arg, force_expr=force_expr) async def evalOnSelectorAll( self, selector: str, expression: str, arg: Serializable = None, force_expr: bool = None, ) -> Any: return await self._main_frame.evalOnSelectorAll(selector, expression, arg, force_expr=force_expr) async def addScriptTag( self, url: str = None, path: Union[str, Path] = None, content: str = None, type: str = None, ) -> ElementHandle: return await self._main_frame.addScriptTag(**locals_to_params(locals()) ) async def addStyleTag(self, url: str = None, path: Union[str, Path] = None, content: str = None) -> ElementHandle: return await self._main_frame.addStyleTag(**locals_to_params(locals())) async def exposeFunction(self, name: str, binding: Callable) -> None: await self.exposeBinding(name, lambda source, *args: binding(*args)) 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 setExtraHTTPHeaders(self, headers: Dict[str, str]) -> None: await self._channel.send("setExtraHTTPHeaders", dict(headers=serialize_headers(headers))) @property def url(self) -> str: return self._main_frame.url async def content(self) -> str: return await self._main_frame.content() async def setContent( self, html: str, timeout: int = None, waitUntil: DocumentLoadState = None, ) -> None: return await self._main_frame.setContent(**locals_to_params(locals())) async def goto( self, url: str, timeout: int = None, waitUntil: DocumentLoadState = None, referer: str = None, ) -> Optional[Response]: return await self._main_frame.goto(**locals_to_params(locals())) async def reload( self, timeout: int = None, waitUntil: DocumentLoadState = None, ) -> Optional[Response]: return from_nullable_channel(await self._channel.send( "reload", locals_to_params(locals()))) async def waitForLoadState(self, state: DocumentLoadState = None, timeout: int = None) -> None: return await self._main_frame.waitForLoadState( **locals_to_params(locals())) async def waitForNavigation( self, url: URLMatch = None, waitUntil: DocumentLoadState = None, timeout: int = None, ) -> Optional[Response]: return await self._main_frame.waitForNavigation( **locals_to_params(locals())) async def waitForRequest( self, url: URLMatch = None, predicate: Callable[[Request], bool] = None, timeout: int = None, ) -> Request: matcher = URLMatcher(url) if url else None def my_predicate(request: Request) -> bool: if matcher: return matcher.matches(request.url) if predicate: return predicate(request) return True return cast( Request, await self.waitForEvent(Page.Events.Request, predicate=my_predicate, timeout=timeout), ) async def waitForResponse( self, url: URLMatch = None, predicate: Callable[[Response], bool] = None, timeout: int = None, ) -> Response: matcher = URLMatcher(url) if url else None def my_predicate(response: Response) -> bool: if matcher: return matcher.matches(response.url) if predicate: return predicate(response) return True return cast( Response, await self.waitForEvent(Page.Events.Response, predicate=my_predicate, timeout=timeout), ) 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 goBack( self, timeout: int = None, waitUntil: DocumentLoadState = None, ) -> Optional[Response]: return from_nullable_channel(await self._channel.send( "goBack", locals_to_params(locals()))) async def goForward( self, timeout: int = None, waitUntil: DocumentLoadState = None, ) -> Optional[Response]: return from_nullable_channel(await self._channel.send( "goForward", locals_to_params(locals()))) async def emulateMedia( self, media: Literal["print", "screen"] = None, colorScheme: ColorScheme = None, ) -> None: await self._channel.send("emulateMedia", locals_to_params(locals())) async def setViewportSize(self, width: int, height: int) -> None: self._viewport_size = (width, height) await self._channel.send("setViewportSize", dict(viewportSize=locals_to_params(locals()))) def viewportSize(self) -> Optional[Tuple[int, int]]: return self._viewport_size async def bringToFront(self) -> None: await self._channel.send("bringToFront") async def addInitScript(self, source: str = None, path: Union[str, Path] = 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)) async def route(self, url: URLMatch, handler: RouteHandler) -> None: self._routes.append(RouteHandlerEntry(URLMatcher(url), handler)) if len(self._routes) == 1: await self._channel.send("setNetworkInterceptionEnabled", dict(enabled=True)) async def unroute(self, url: URLMatch, handler: Optional[RouteHandler] = None) -> None: self._routes = list( filter( lambda r: r.matcher.match != url or (handler and r.handler != handler), self._routes, )) if len(self._routes) == 0: await self._channel.send("setNetworkInterceptionEnabled", dict(enabled=False)) async def screenshot( self, timeout: int = None, type: Literal["jpeg", "png"] = None, path: Union[str, Path] = None, quality: int = None, omitBackground: bool = None, fullPage: bool = None, clip: FloatRect = None, ) -> bytes: params = locals_to_params(locals()) if "path" in params: del params["path"] encoded_binary = await self._channel.send("screenshot", params) decoded_binary = base64.b64decode(encoded_binary) if path: with open(path, "wb") as fd: fd.write(decoded_binary) return decoded_binary async def title(self) -> str: return await self._main_frame.title() async def close(self, runBeforeUnload: bool = None) -> None: try: await self._channel.send("close", locals_to_params(locals())) if self._owned_context: await self._owned_context.close() except Exception as e: if not is_safe_close_error(e): raise e def isClosed(self) -> bool: return self._is_closed async def click( self, selector: str, modifiers: List[KeyboardModifier] = None, position: Tuple[float, float] = None, delay: int = None, button: MouseButton = None, clickCount: int = None, timeout: int = None, force: bool = None, noWaitAfter: bool = None, ) -> None: return await self._main_frame.click(**locals_to_params(locals())) async def dblclick( self, selector: str, modifiers: List[KeyboardModifier] = None, position: Tuple[float, float] = None, delay: int = None, button: MouseButton = None, timeout: int = None, force: bool = None, noWaitAfter: bool = None, ) -> None: return await self._main_frame.dblclick(**locals_to_params(locals())) async def tap( self, selector: str, modifiers: List[KeyboardModifier] = None, position: Tuple[float, float] = None, timeout: int = None, force: bool = None, noWaitAfter: bool = None, ) -> None: return await self._main_frame.tap(**locals_to_params(locals())) async def fill(self, selector: str, value: str, timeout: int = None, noWaitAfter: bool = None) -> None: return await self._main_frame.fill(**locals_to_params(locals())) async def focus(self, selector: str, timeout: int = None) -> None: return await self._main_frame.focus(**locals_to_params(locals())) async def textContent(self, selector: str, timeout: int = None) -> Optional[str]: return await self._main_frame.textContent(**locals_to_params(locals())) async def innerText(self, selector: str, timeout: int = None) -> str: return await self._main_frame.innerText(**locals_to_params(locals())) async def innerHTML(self, selector: str, timeout: int = None) -> str: return await self._main_frame.innerHTML(**locals_to_params(locals())) async def getAttribute(self, selector: str, name: str, timeout: int = None) -> Optional[str]: return await self._main_frame.getAttribute(**locals_to_params(locals()) ) async def hover( self, selector: str, modifiers: List[KeyboardModifier] = None, position: Tuple[float, float] = None, timeout: int = None, force: bool = None, ) -> None: return await self._main_frame.hover(**locals_to_params(locals())) async def selectOption( self, selector: str, values: ValuesToSelect, timeout: int = None, noWaitAfter: bool = None, ) -> List[str]: params = locals_to_params(locals()) if "values" not in params: params["values"] = None return await self._main_frame.selectOption(**params) async def setInputFiles( self, selector: str, files: Union[str, FilePayload, List[str], List[FilePayload]], timeout: int = None, noWaitAfter: bool = None, ) -> None: return await self._main_frame.setInputFiles( **locals_to_params(locals())) async def type( self, selector: str, text: str, delay: int = None, timeout: int = None, noWaitAfter: bool = None, ) -> None: return await self._main_frame.type(**locals_to_params(locals())) async def press( self, selector: str, key: str, delay: int = None, timeout: int = None, noWaitAfter: bool = None, ) -> None: return await self._main_frame.press(**locals_to_params(locals())) async def check( self, selector: str, timeout: int = None, force: bool = None, noWaitAfter: bool = None, ) -> None: return await self._main_frame.check(**locals_to_params(locals())) async def uncheck( self, selector: str, timeout: int = None, force: bool = None, noWaitAfter: bool = None, ) -> None: return await self._main_frame.uncheck(**locals_to_params(locals())) async def waitForTimeout(self, timeout: int) -> None: await self._main_frame.waitForTimeout(timeout) async def waitForFunction( self, expression: str, arg: Serializable = None, force_expr: bool = None, timeout: int = None, polling: Union[int, Literal["raf"]] = None, ) -> JSHandle: if not is_function_body(expression): force_expr = True return await self._main_frame.waitForFunction( **locals_to_params(locals())) @property def workers(self) -> List["Worker"]: return self._workers.copy() async def pdf( self, scale: int = None, displayHeaderFooter: bool = None, headerTemplate: str = None, footerTemplate: str = None, printBackground: bool = None, landscape: bool = None, pageRanges: str = None, format: str = None, width: Union[str, float] = None, height: Union[str, float] = None, preferCSSPageSize: bool = None, margin: PdfMargins = None, path: Union[str, Path] = None, ) -> bytes: params = locals_to_params(locals()) if "path" in params: del params["path"] encoded_binary = await self._channel.send("pdf", params) decoded_binary = base64.b64decode(encoded_binary) if path: with open(path, "wb") as fd: fd.write(decoded_binary) return decoded_binary @property def video(self, ) -> Optional[Video]: context_options = self._browser_context._options if "recordVideo" not in context_options: return None if not self._video: self._video = Video(self) if "videoRelativePath" in self._initializer: self._video._set_relative_path( self._initializer["videoRelativePath"]) return self._video def expect_event( self, event: str, predicate: Callable[[Any], bool] = None, timeout: int = None, ) -> EventContextManagerImpl: return EventContextManagerImpl( self.waitForEvent(event, predicate, timeout)) def expect_console_message( self, predicate: Callable[[ConsoleMessage], bool] = None, timeout: int = None, ) -> EventContextManagerImpl[ConsoleMessage]: return EventContextManagerImpl( self.waitForEvent("console", predicate, timeout)) def expect_dialog( self, predicate: Callable[[Dialog], bool] = None, timeout: int = None, ) -> EventContextManagerImpl[Dialog]: return EventContextManagerImpl( self.waitForEvent("dialog", predicate, timeout)) def expect_download( self, predicate: Callable[[Download], bool] = None, timeout: int = None, ) -> EventContextManagerImpl[Download]: return EventContextManagerImpl( self.waitForEvent("download", predicate, timeout)) def expect_file_chooser( self, predicate: Callable[[FileChooser], bool] = None, timeout: int = None, ) -> EventContextManagerImpl[FileChooser]: return EventContextManagerImpl( self.waitForEvent("filechooser", predicate, timeout)) def expect_load_state( self, state: DocumentLoadState = None, timeout: int = None, ) -> EventContextManagerImpl[Optional[Response]]: return EventContextManagerImpl(self.waitForLoadState(state, timeout)) def expect_navigation( self, url: URLMatch = None, waitUntil: DocumentLoadState = None, timeout: int = None, ) -> EventContextManagerImpl[Optional[Response]]: return EventContextManagerImpl( self.waitForNavigation(url, waitUntil, timeout)) def expect_popup( self, predicate: Callable[["Page"], bool] = None, timeout: int = None, ) -> EventContextManagerImpl["Page"]: return EventContextManagerImpl( self.waitForEvent("popup", predicate, timeout)) def expect_request( self, url: URLMatch = None, predicate: Callable[[Request], bool] = None, timeout: int = None, ) -> EventContextManagerImpl[Request]: return EventContextManagerImpl( self.waitForRequest(url, predicate, timeout)) def expect_response( self, url: URLMatch = None, predicate: Callable[[Request], bool] = None, timeout: int = None, ) -> EventContextManagerImpl[Response]: return EventContextManagerImpl( self.waitForResponse(url, predicate, timeout)) def expect_worker( self, predicate: Callable[["Worker"], bool] = None, timeout: int = None, ) -> EventContextManagerImpl["Worker"]: return EventContextManagerImpl( self.waitForEvent("worker", predicate, timeout))
def __init__(self, parent: ChannelOwner, type: str, guid: str, initializer: Dict) -> None: super().__init__(parent, type, guid, initializer) self.accessibility = Accessibility(self._channel) self.keyboard = Keyboard(self._channel) self.mouse = Mouse(self._channel) self.touchscreen = Touchscreen(self._channel) self._main_frame: Frame = from_channel(initializer["mainFrame"]) self._main_frame._page = self self._frames = [self._main_frame] vs = initializer.get("viewportSize") self._viewport_size: Optional[Tuple[int, int]] = ((vs["width"], vs["height"]) if vs else None) self._is_closed = False self._workers: List["Worker"] = [] self._bindings: Dict[str, Any] = {} self._pending_wait_for_events: List[PendingWaitEvent] = [] self._routes: List[RouteHandlerEntry] = [] self._owned_context: Optional["BrowserContext"] = None self._timeout_settings: TimeoutSettings = TimeoutSettings(None) self._video: Optional[Video] = None self._channel.on( "bindingCall", lambda params: self._on_binding(from_channel(params["binding"])), ) self._channel.on("close", lambda _: self._on_close()) self._channel.on( "console", lambda params: self.emit(Page.Events.Console, from_channel(params["message"])), ) self._channel.on("crash", lambda _: self._on_crash()) self._channel.on( "dialog", lambda params: self.emit(Page.Events.Dialog, from_channel(params["dialog"])), ) self._channel.on("domcontentloaded", lambda _: self.emit(Page.Events.DOMContentLoaded)) self._channel.on( "download", lambda params: self.emit(Page.Events.Download, from_channel(params["download"])), ) self._channel.on( "fileChooser", lambda params: self.emit( Page.Events.FileChooser, FileChooser(self, from_channel(params["element"]), params[ "isMultiple"]), ), ) self._channel.on( "frameAttached", lambda params: self._on_frame_attached( from_channel(params["frame"])), ) self._channel.on( "frameDetached", lambda params: self._on_frame_detached( from_channel(params["frame"])), ) self._channel.on("load", lambda _: self.emit(Page.Events.Load)) self._channel.on( "pageError", lambda params: self.emit(Page.Events.PageError, parse_error(params["error"]["error"])), ) self._channel.on( "popup", lambda params: self.emit(Page.Events.Popup, from_channel(params["page"])), ) self._channel.on( "request", lambda params: self.emit(Page.Events.Request, from_channel(params["request"])), ) self._channel.on( "requestFailed", lambda params: self._on_request_failed( from_channel(params["request"]), params["responseEndTiming"], params["failureText"], ), ) self._channel.on( "requestFinished", lambda params: self._on_request_finished( from_channel(params["request"]), params["responseEndTiming"]), ) self._channel.on( "response", lambda params: self.emit(Page.Events.Response, from_channel(params["response"])), ) self._channel.on( "route", lambda params: self._on_route(from_channel(params["route"]), from_channel(params["request"])), ) self._channel.on( "video", lambda params: cast(Video, self.video)._set_relative_path(params[ "relativePath"]), ) self._channel.on( "webSocket", lambda params: self.emit(Page.Events.WebSocket, from_channel(params["webSocket"])), ) self._channel.on( "worker", lambda params: self._on_worker(from_channel(params["worker"])))