From aa4b256958778d33c956613ff26121afbcfb89a2 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Mon, 12 Oct 2026 16:58:26 -0700 Subject: [PATCH] chore(codegen): use alphabetical order in the generated API - Removes scripts/codegen/legacy_order.json and the code that applied it. - Classes, members, keyword-only parameters, events and TypedDicts are in alphabetical order; a class comes after the class that it extends or uses. Positional parameters, union members and TypedDict fields keep the docs order. Docstrings are wrapped after member links are rendered. compare_api.py shows no other difference. - The roll skill, ROLLING.md, CONTRIBUTING.md and update_api.sh now ask for a microsoft/playwright checkout used only for rolls, on the exact release- branch, and list the checks that it is on that branch, clean, and up to date with origin. --- .claude/skills/playwright-roll/SKILL.md | 36 +- CLAUDE.md | 3 +- CONTRIBUTING.md | 7 +- ROLLING.md | 2 +- playwright/_impl/_api_structures.py | 196 +- playwright/async_api/_generated.py | 35383 +++++++++++----------- playwright/sync_api/_generated.py | 35305 +++++++++++---------- scripts/codegen/generate_api.js | 257 +- scripts/codegen/legacy_order.json | 328 - scripts/update_api.sh | 11 +- 10 files changed, 35523 insertions(+), 36005 deletions(-) delete mode 100644 scripts/codegen/legacy_order.json diff --git a/.claude/skills/playwright-roll/SKILL.md b/.claude/skills/playwright-roll/SKILL.md index 30a078c08..acb402985 100644 --- a/.claude/skills/playwright-roll/SKILL.md +++ b/.claude/skills/playwright-roll/SKILL.md @@ -39,14 +39,30 @@ The upstream documentation source of truth is `docs/src/api/*.md` in the playwri ### 2. Bump the driver pin, download it, and generate api.json -You need a nearby `microsoft/playwright` checkout for the docs walk and for -codegen. Point `PW_SRC_DIR` at it and check out the release branch for the new -version there (the branch has the release's docs plus any cherry-picks): +The docs walk and codegen read the upstream docs from a `microsoft/playwright` +checkout at `$PW_SRC_DIR`. **Use a separate checkout that exists only for +rolls, on the exact release branch you roll to**: `release-`, the +`major.minor` of the new `DRIVER_VERSION` (the branch has the release's docs +plus any cherry-picks). Never point `PW_SRC_DIR` at a checkout that someone +works in: on `main` or a feature branch the docs differ, and the generator +silently emits that API instead of the release's. ```sh -export PW_SRC_DIR=../playwright -git -C "$PW_SRC_DIR" fetch origin 'release-*:release-*' -git -C "$PW_SRC_DIR" checkout release- # e.g. release-1.62 +export PW_SRC_DIR=../playwright-for-python # the roll checkout, nothing else +# First roll on this machine: clone it (no npm install needed). +git clone https://github.com/microsoft/playwright.git "$PW_SRC_DIR" +# Every roll: move it to the release branch. +git -C "$PW_SRC_DIR" fetch origin +git -C "$PW_SRC_DIR" checkout release- # e.g. release-1.62 +git -C "$PW_SRC_DIR" merge --ff-only origin/release- +``` + +Check the checkout before you generate, and again before you commit: + +```sh +git -C "$PW_SRC_DIR" rev-parse --abbrev-ref HEAD # must print release- +git -C "$PW_SRC_DIR" status --porcelain # must print nothing +git -C "$PW_SRC_DIR" rev-parse HEAD origin/release- # both lines must be equal ``` Then bump the pins and assemble the driver: @@ -73,7 +89,7 @@ the walk. ### 3. Identify the commit range -Use the nearby `microsoft/playwright` checkout at `$PW_SRC_DIR` (from step 2). +Use the roll checkout at `$PW_SRC_DIR` (from step 2). Bring it up to date and ensure release branches/tags are present before walking the range: @@ -221,7 +237,7 @@ Tick the box in `/tmp/roll--commits.md` with one line: `[x] ### 5. Regenerate ```sh -PW_SRC_DIR=../playwright ./scripts/update_api.sh # PW_SRC_DIR already exported in step 2 +./scripts/update_api.sh # uses PW_SRC_DIR from step 2; run the checkout checks there first ``` The script, for `sync` and then `async`: @@ -250,10 +266,10 @@ Failure modes and fixes: | mypy: incompatible argument type in `_generated.py` | The docs type changed, or `_impl/` declares a narrower type. | Match the type in `_impl/`, or record a `typeOverrides` entry for a justified divergence. | | generator: `No Python name for the struct at X.y.z` | A new inline `[Object]` with no `* alias:` in the docs. | Name it: `alias-python` upstream, or `structNamesByPlace` / `structRenames`. | | generator: `The struct X has different fields at A and B` | Two places in the docs share one struct name, but their fields differ. | Give one place its own name in `structNamesByPlace`, or fix the docs. | +| `_generated.py` gains or loses members that the commit walk never mentioned | `PW_SRC_DIR` is not on `release-` (for example on `main` or a feature branch), or is behind `origin/release-`. | Run the checkout checks from step 2, fix the checkout, regenerate. | | generator: `Unknown docs type "T" at X.y` | A docs type the type table in `generate_api.js` (`toPy`) does not know. | Add it to `toPy`. | | generator: `required parameter z follows an optional one` | The docs order params so that Python would need a default before a non-default. | Add a `positional` entry with the Python order. | | generator: `the entry "…" no longer matches anything; remove it` | An upstream change made a rules entry unnecessary (or renamed what it points at). | Delete it, or re-key it to the new docs name. | -| generator: `legacy_order.json: … has no …; remove it` | A member, parameter or TypedDict in the temporary legacy order was removed or renamed upstream. | Delete that name from `scripts/codegen/legacy_order.json`. New members need no entry; they go last. | | `pyright … reportInconsistentOverload` (single-event class) | A class gained its first event, so there is one `Literal[…]` overload + impl, which pyright wants ≥2 of. | The generator already handles this — `emitEvents` adds a second `@typing.overload` with `event: str` when a class has exactly one event. | | `pre-commit` keeps reformatting `_generated.py` on each run | First run after regen always reformats once; rerun until idle. | `pre-commit run --all-files` to settle. | | A kwarg in `_impl/` that the docs don't mention (e.g. legacy name from a doc rename) | Nothing fails: the generator simply never passes it. | If the param is positional with no default, just rename it in `_impl/`. Check `packages/protocol/spec/*.yml` and the server dispatcher — if the wire field renamed too, also update the channel-send dict key. Only use `extraOptions` for genuinely hidden internal kwargs (`default_browser_type`). | @@ -281,6 +297,8 @@ For each PORT, add one async test and a matching sync test. Conventions: ### 8. Final verification +Repeat the checkout checks from step 2: the committed `_generated.py` must come from `release-`. + ```sh pre-commit run --all-files mypy playwright # 2 pre-existing errors in _json_pipe.py and _artifact.py are unrelated diff --git a/CLAUDE.md b/CLAUDE.md index bbbc9269e..d8069dc6a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,13 +12,12 @@ Python bindings for [Playwright](https://playwright.dev). The Python client talk - `playwright/async_api/_generated.py`, `playwright/sync_api/_generated.py`, and the public TypedDicts in `playwright/_impl/_api_structures.py` — **auto-generated** from the upstream API docs. Never edit by hand; rerun `./scripts/update_api.sh` after a roll or after changing `scripts/codegen/`. - `scripts/codegen/generate_api.js` — the generator. A Node.js script that loads the upstream doc parser (`utils/doclint/api_parser.js`) from `$PW_SRC_DIR`, filters the docs for Python, and writes the whole public API: signatures, types, docstrings, event overloads, the calls into `_impl/`, and the TypedDicts. It does not read `_impl/`. - `scripts/codegen/python_rules.js` — the Python facts that the docs do not contain (positional parameters, struct names and `total=`, type overrides, hidden members). Policy: the shipped Python API wins; each entry is a candidate for an upstream docs fix, and the generator fails on entries that no longer match anything. Every entry needs a one-line rationale comment above it. -- `scripts/codegen/legacy_order.json` — **temporary**. The old generator's order of classes, members, keyword-only parameters and union members, and the hand-written order of the TypedDicts. The generator applies it, and more old habits marked `TEMPORARY` in the generator, so that the switch to the docs generator has a small diff. New members go last. If the generator reports an entry that no longer matches, remove the entry. A follow-up change deletes the file and the `TEMPORARY` code. - `scripts/codegen/compare_api.py` — compares two generated files (signatures, annotations, call bodies, docstrings) and lists every difference. Use it to check that a generator change does not change the API. - `tests/async/`, `tests/sync/` — pytest suites. Most new tests are added to the async file with a sync mirror. - `DRIVER_VERSION` — the single source of truth for which Playwright release the driver is assembled from (one line, the `playwright-core` npm version, e.g. `1.61.0`, no `v` prefix). Read by `setup.py`, `scripts/build_driver.py`, and CI. The wheel build downloads `playwright-core` at this version from npm plus the matching Node.js binary and assembles the per-platform bundles — no source build. The version is baked into the staged bundle filenames (`driver/playwright--.zip`), so it doubles as the build cache key. - `NODE_VERSION` — the Node.js version bundled with the driver (one line, e.g. `24.16.0`). Maintained at roll time by `scripts/update_node_version.py` (latest LTS, mirroring upstream's `utils/build/update-playwright-node.mjs`). - `scripts/build_driver.py` — assembles the per-platform driver bundles into `driver/` by downloading the `playwright-core` npm package (`DRIVER_VERSION`) and the official Node.js binaries (`NODE_VERSION`). Fetches `playwright-core` with `npm pack` (needs Node.js/npm on PATH; honours a root `.npmrc`) and the Node.js binaries over plain HTTP; invoked from `setup.py`'s `bdist_wheel` with the target platform's suffix (no arg builds all six). -- The API docs are **not** shipped in the bundle. `scripts/update_api.sh` reads them from a nearby `microsoft/playwright` checkout (`$PW_SRC_DIR`, at the release branch for `DRIVER_VERSION`). Needed only when regenerating the API, never at runtime. +- The API docs are **not** shipped in the bundle. `scripts/update_api.sh` reads them from a separate `microsoft/playwright` checkout (`$PW_SRC_DIR`) on the exact release branch for `DRIVER_VERSION`, never from a checkout on `main` or a feature branch. Needed only when regenerating the API, never at runtime. - `ROLLING.md`, `CONTRIBUTING.md` — human-facing setup and roll docs. ## Setup diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 49cf6f1b7..fc4d39196 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -77,13 +77,14 @@ For more details look at the [CI configuration](./.github/workflows/ci.yml). `update_api.sh` generates `playwright/{async,sync}_api/_generated.py` and the public TypedDicts in `playwright/_impl/_api_structures.py` from the API docs in -a nearby `microsoft/playwright` checkout (at the release branch matching -`DRIVER_VERSION`); point `PW_SRC_DIR` at it. The generator is +a separate `microsoft/playwright` checkout on the exact release branch for +`DRIVER_VERSION` (for example `release-1.64`); point `PW_SRC_DIR` at it. The +generator is `scripts/codegen/generate_api.js`; Python facts that the docs do not contain live in `scripts/codegen/python_rules.js`. ```bash -PW_SRC_DIR=../playwright ./scripts/update_api.sh +PW_SRC_DIR=../playwright-for-python ./scripts/update_api.sh pre-commit run --all-files ``` diff --git a/ROLLING.md b/ROLLING.md index fddddf39f..753a348eb 100644 --- a/ROLLING.md +++ b/ROLLING.md @@ -13,7 +13,7 @@ pip install -e . ``` * change the driver pin in `DRIVER_VERSION` (the `playwright-core` npm version, e.g. `1.61.0`) and refresh `NODE_VERSION`: `python scripts/update_node_version.py` * download the new driver: `python -m build --wheel` (fetches `playwright-core` via `npm pack` + the matching Node.js binary and assembles the bundle; no source build). -* generate API from the docs (needs a nearby `microsoft/playwright` checkout at the release branch for the new version, e.g. `release-1.64`): `PW_SRC_DIR=../playwright ./scripts/update_api.sh` +* generate API from the docs. This needs a separate `microsoft/playwright` checkout used only for rolls, on the exact release branch for the new version (e.g. `release-1.64`), clean and up to date with `origin`: `PW_SRC_DIR=../playwright-for-python ./scripts/update_api.sh` * run `mypy playwright`: every error in `_generated.py` points at an implementation method in `playwright/_impl/` that lacks a new member or option. Implement it there, or record the difference in `scripts/codegen/python_rules.js`. * commit changes & send PR * wait for bots to pass & merge the PR diff --git a/playwright/_impl/_api_structures.py b/playwright/_impl/_api_structures.py index de8488049..5fed451ea 100644 --- a/playwright/_impl/_api_structures.py +++ b/playwright/_impl/_api_structures.py @@ -18,6 +18,21 @@ from typing import Any, Dict, List, Literal, Optional, Sequence, TypedDict, Union +class BrowserBindResult(TypedDict): + endpoint: str + + +class ClientCertificate(TypedDict, total=False): + origin: str + certPath: Optional[Union[str, Path]] + cert: Optional[bytes] + keyPath: Optional[Union[str, Path]] + key: Optional[bytes] + pfxPath: Optional[Union[str, Path]] + pfx: Optional[bytes] + passphrase: Optional[str] + + class Cookie(TypedDict, total=False): name: str value: str @@ -30,28 +45,28 @@ class Cookie(TypedDict, total=False): partitionKey: Optional[str] -class StorageStateCookie(TypedDict, total=False): - name: str - value: str - domain: str - path: str - expires: float - httpOnly: bool - secure: bool - sameSite: Literal["Lax", "None", "Strict"] +class DebuggerLocation(TypedDict): + file: str + line: Optional[int] + column: Optional[int] -class SetCookieParam(TypedDict, total=False): +class DebuggerPausedDetails(TypedDict): + location: DebuggerLocation + title: str + + +class FilePayload(TypedDict): name: str - value: str - url: Optional[str] - domain: Optional[str] - path: Optional[str] - expires: Optional[float] - httpOnly: Optional[bool] - secure: Optional[bool] - sameSite: Optional[Literal["Lax", "None", "Strict"]] - partitionKey: Optional[str] + mimeType: str + buffer: bytes + + +class DropPayload(TypedDict, total=False): + files: Optional[ + Union[str, Path, Sequence[Union[str, Path]], FilePayload, Sequence[FilePayload]] + ] + data: Optional[Dict[str, str]] class FloatRect(TypedDict): @@ -79,6 +94,11 @@ class LocalStorageEntry(TypedDict): value: str +class NameValue(TypedDict): + name: str + value: str + + class OriginState(TypedDict): origin: str localStorage: List[LocalStorageEntry] @@ -103,20 +123,16 @@ class ProxySettings(TypedDict, total=False): password: Optional[str] -class StorageState(TypedDict, total=False): - cookies: List[StorageStateCookie] - origins: List[OriginState] +class RemoteAddr(TypedDict): + ipAddress: str + port: int -class ClientCertificate(TypedDict, total=False): - origin: str - certPath: Optional[Union[str, Path]] - cert: Optional[bytes] - keyPath: Optional[Union[str, Path]] - key: Optional[bytes] - pfxPath: Optional[Union[str, Path]] - pfx: Optional[bytes] - passphrase: Optional[str] +class RequestSizes(TypedDict): + requestBodySize: int + requestHeadersSize: int + responseBodySize: int + responseHeadersSize: int class ResourceTiming(TypedDict): @@ -131,52 +147,22 @@ class ResourceTiming(TypedDict): responseEnd: float -class RequestSizes(TypedDict): - requestBodySize: int - requestHeadersSize: int - responseBodySize: int - responseHeadersSize: int - - -class ViewportSize(TypedDict): - width: int - height: int - - -class SourceLocation(TypedDict): - url: str - line: int - column: int - lineNumber: int - columnNumber: int - - -class WebErrorLocation(TypedDict): - url: str - line: int - column: int - - -class FilePayload(TypedDict): - name: str - mimeType: str - buffer: bytes - - -class DropPayload(TypedDict, total=False): - files: Optional[ - Union[str, Path, Sequence[Union[str, Path]], FilePayload, Sequence[FilePayload]] - ] - data: Optional[Dict[str, str]] +class ScreencastActionStyle(TypedDict, total=False): + point: Optional[str] + highlight: Optional[str] + title: Optional[str] -class RemoteAddr(TypedDict): - ipAddress: str - port: int +class ScreencastFrame(TypedDict): + data: bytes + timestamp: float + viewportWidth: int + viewportHeight: int -class BrowserBindResult(TypedDict): - endpoint: str +class ScreencastSize(TypedDict): + width: int + height: int class SecurityDetails(TypedDict): @@ -187,39 +173,54 @@ class SecurityDetails(TypedDict): validTo: Optional[float] -class NameValue(TypedDict): +class SetCookieParam(TypedDict, total=False): name: str value: str + url: Optional[str] + domain: Optional[str] + path: Optional[str] + expires: Optional[float] + httpOnly: Optional[bool] + secure: Optional[bool] + sameSite: Optional[Literal["Lax", "None", "Strict"]] + partitionKey: Optional[str] -class TracingGroupLocation(TypedDict): - file: str - line: Optional[int] - column: Optional[int] +class SourceLocation(TypedDict): + url: str + line: int + column: int + lineNumber: int + columnNumber: int -class DebuggerLocation(TypedDict): +class StorageStateCookie(TypedDict, total=False): + name: str + value: str + domain: str + path: str + expires: float + httpOnly: bool + secure: bool + sameSite: Literal["Lax", "None", "Strict"] + + +class StorageState(TypedDict, total=False): + cookies: List[StorageStateCookie] + origins: List[OriginState] + + +class TracingGroupLocation(TypedDict): file: str line: Optional[int] column: Optional[int] -class DebuggerPausedDetails(TypedDict): - location: DebuggerLocation - title: str - - -class ScreencastSize(TypedDict): +class ViewportSize(TypedDict): width: int height: int -class ScreencastActionStyle(TypedDict, total=False): - point: Optional[str] - highlight: Optional[str] - title: Optional[str] - - class VirtualCredential(TypedDict): id: str rpId: str @@ -229,6 +230,12 @@ class VirtualCredential(TypedDict): signCount: int +class WebErrorLocation(TypedDict): + url: str + line: int + column: int + + class WebMCPToolAnnotations(TypedDict, total=False): readOnly: Optional[bool] untrustedContent: Optional[bool] @@ -240,10 +247,3 @@ class WebMCPTool(TypedDict, total=False): description: str inputSchema: Optional[Any] annotations: Optional[WebMCPToolAnnotations] - - -class ScreencastFrame(TypedDict): - data: bytes - timestamp: float - viewportWidth: int - viewportHeight: int diff --git a/playwright/async_api/_generated.py b/playwright/async_api/_generated.py index 08676ec30..f1c3b2576 100644 --- a/playwright/async_api/_generated.py +++ b/playwright/async_api/_generated.py @@ -103,522 +103,1037 @@ from playwright._impl._webmcp import WebMCP as WebMCPImpl -class Request(AsyncBase): - _impl_obj: RequestImpl - - @property - def url(self) -> str: - """Request.url - - URL of the request. - - Returns - ------- - str - """ - return mapping.from_maybe_impl(self._impl_obj.url) - - @property - def resource_type(self) -> str: - """Request.resource_type - - Contains the request's resource type as it was perceived by the rendering engine. ResourceType will be one of the - following: `document`, `stylesheet`, `image`, `media`, `font`, `script`, `texttrack`, `xhr`, `fetch`, - `eventsource`, `websocket`, `manifest`, `beacon`, `ping`, `cspreport`, `other`. +class APIRequest(AsyncBase): + _impl_obj: APIRequestImpl - Returns - ------- - str - """ - return mapping.from_maybe_impl(self._impl_obj.resource_type) + async def new_context( + self, + *, + base_url: typing.Optional[str] = None, + client_certificates: typing.Optional[typing.Sequence[ClientCertificate]] = None, + extra_http_headers: typing.Optional[typing.Dict[str, str]] = None, + fail_on_status_code: typing.Optional[bool] = None, + http_credentials: typing.Optional[ + typing.Union[HttpCredentials, typing.Sequence[HttpCredentials]] + ] = None, + ignore_https_errors: typing.Optional[bool] = None, + max_redirects: typing.Optional[int] = None, + proxy: typing.Optional[ProxySettings] = None, + storage_state: typing.Optional[ + typing.Union[str, pathlib.Path, StorageState] + ] = None, + timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, + user_agent: typing.Optional[str] = None, + ) -> "APIRequestContext": + """APIRequest.new_context - @property - def service_worker(self) -> typing.Optional["Worker"]: - """Request.service_worker + Creates new instances of `APIRequestContext`. - The Service `Worker` that is performing the request. + Parameters + ---------- + base_url : Union[str, None] + Methods like `api_request_context.get()` take the base URL into consideration by using the + [`URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor for building the corresponding URL. + Examples: + - baseURL: `http://localhost:3000` and sending request to `/bar.html` results in `http://localhost:3000/bar.html` + - baseURL: `http://localhost:3000/foo/` and sending request to `./bar.html` results in + `http://localhost:3000/foo/bar.html` + - baseURL: `http://localhost:3000/foo` (without trailing slash) and navigating to `./bar.html` results in + `http://localhost:3000/bar.html` + client_certificates : Union[Sequence[{origin: str, certPath: Union[pathlib.Path, str, None], cert: Union[bytes, None], keyPath: Union[pathlib.Path, str, None], key: Union[bytes, None], pfxPath: Union[pathlib.Path, str, None], pfx: Union[bytes, None], passphrase: Union[str, None]}], None] + TLS Client Authentication allows the server to request a client certificate and verify it. - **Details** + **Details** - This method is Chromium only. It's safe to call when using other browsers, but it will always be `null`. + An array of client certificates to be used. Each certificate object must have either both `certPath` and `keyPath`, + a single `pfxPath`, or their corresponding direct value equivalents (`cert` and `key`, or `pfx`). Optionally, + `passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided + with an exact match to the request origin that the certificate is valid for. - Requests originated in a Service Worker do not have a `request.frame` available. + Client certificate authentication is only active when at least one client certificate is provided. If you want to + reject all client certificates sent by the server, you need to provide a client certificate with an `origin` that + does not match any of the domains you plan to visit. - Returns - ------- - Union[Worker, None] - """ - return mapping.from_impl_nullable(self._impl_obj.service_worker) + **NOTE** When using WebKit on macOS, accessing `localhost` will not pick up client certificates. You can make it + work by replacing `localhost` with `local.playwright`. - @property - def method(self) -> str: - """Request.method + extra_http_headers : Union[Dict[str, str], None] + An object containing additional HTTP headers to be sent with every request. Defaults to none. + fail_on_status_code : Union[bool, None] + Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + codes. + http_credentials : Union[Sequence[{username: str, password: str, origin: Union[str, None], send: Union["always", "unauthorized", None]}], {username: str, password: str, origin: Union[str, None], send: Union["always", "unauthorized", None]}, None] + Credentials for [HTTP authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication). If no + origin is specified, the username and password are sent to any servers upon unauthorized responses. - Request's method (GET, POST, etc.) + Pass an array to use different credentials for different origins. The first entry that matches the request origin + is used, and entries with no origin match any request. + ignore_https_errors : Union[bool, None] + Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + max_redirects : Union[int, None] + Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + exceeded. Defaults to `20`. Pass `0` to not follow redirects. This can be overwritten for each request + individually. + proxy : Union[{server: str, bypass: Union[str, None], username: Union[str, None], password: Union[str, None]}, None] + Network proxy settings. + storage_state : Union[pathlib.Path, str, {cookies: Sequence[{name: str, value: str, domain: str, path: str, expires: float, httpOnly: bool, secure: bool, sameSite: Union["Lax", "None", "Strict"]}], origins: Sequence[{origin: str, localStorage: Sequence[{name: str, value: str}]}]}, None] + Populates context with given storage state. This option can be used to initialize context with logged-in + information obtained via `browser_context.storage_state()` or `api_request_context.storage_state()`. Either a path + to the file with saved storage, or the value returned by one of `browser_context.storage_state()` or + `api_request_context.storage_state()` methods. + timeout : Union[float, None] + Maximum time in milliseconds to wait for the response. Defaults to `30000` (30 seconds). Pass `0` to disable + timeout. + user_agent : Union[str, None] + Specific user agent to use in this context. Returns ------- - str + APIRequestContext """ - return mapping.from_maybe_impl(self._impl_obj.method) - @property - def post_data(self) -> typing.Optional[str]: - """Request.post_data + return mapping.from_impl( + await self._impl_obj.new_context( + baseURL=base_url, + clientCertificates=mapping.to_impl(client_certificates), + extraHTTPHeaders=mapping.to_impl(extra_http_headers), + failOnStatusCode=fail_on_status_code, + httpCredentials=mapping.to_impl(http_credentials), + ignoreHTTPSErrors=ignore_https_errors, + maxRedirects=max_redirects, + proxy=proxy, + storageState=storage_state, + timeout=to_milliseconds(timeout), + userAgent=user_agent, + ) + ) - Request's post body, if any. - Returns - ------- - Union[str, None] - """ - return mapping.from_maybe_impl(self._impl_obj.post_data) +mapping.register(APIRequestImpl, APIRequest) - @property - def post_data_json(self) -> typing.Optional[typing.Any]: - """Request.post_data_json - Returns parsed request's body for `form-urlencoded` and JSON as a fallback if any. +class APIRequestContext(AsyncBase): + _impl_obj: APIRequestContextImpl - When the response is `application/x-www-form-urlencoded` then a key/value object of the values will be returned. - Otherwise it will be parsed as JSON. + async def add_cookies(self, cookies: typing.Sequence[SetCookieParam]) -> None: + """APIRequestContext.add_cookies - Returns - ------- - Union[Any, None] - """ - return mapping.from_maybe_impl(self._impl_obj.post_data_json) + Adds cookies into this request context. They will be sent with matching subsequent requests. For + `browser_context.request` and `page.request`, this is equivalent to calling `browser_context.add_cookies()` on the + corresponding browser context. - @property - def post_data_buffer(self) -> typing.Optional[bytes]: - """Request.post_data_buffer + **Usage** - Request's post body in a binary form, if any. + ```py + await request.add_cookies([cookie_object1, cookie_object2]) + ``` - Returns - ------- - Union[bytes, None] + Parameters + ---------- + cookies : Sequence[{name: str, value: str, url: Union[str, None], domain: Union[str, None], path: Union[str, None], expires: Union[float, None], httpOnly: Union[bool, None], secure: Union[bool, None], sameSite: Union["Lax", "None", "Strict", None], partitionKey: Union[str, None]}] """ - return mapping.from_maybe_impl(self._impl_obj.post_data_buffer) - - @property - def existing_response(self) -> typing.Optional["Response"]: - """Request.existing_response - - Returns the `Response` object if the response has already been received, `null` otherwise. - - Unlike `request.response()`, this method does not wait for the response to arrive. It returns immediately - with the response object if the response has been received, or `null` if the response has not been received yet. - Returns - ------- - Union[Response, None] - """ - return mapping.from_impl_nullable(self._impl_obj.existing_response) + await self._impl_obj.add_cookies(cookies=mapping.to_impl(cookies)) - @property - def frame(self) -> "Frame": - """Request.frame + async def clear_cookies( + self, + *, + domain: typing.Optional[typing.Union[str, typing.Pattern[str]]] = None, + name: typing.Optional[typing.Union[str, typing.Pattern[str]]] = None, + path: typing.Optional[typing.Union[str, typing.Pattern[str]]] = None, + ) -> None: + """APIRequestContext.clear_cookies - Returns the `Frame` that initiated this request. + Removes cookies from this request context. Accepts optional filter. For `browser_context.request` and + `page.request`, this is equivalent to calling `browser_context.clear_cookies()` on the corresponding browser + context. **Usage** ```py - frame_url = request.frame.url + await request.clear_cookies() + await request.clear_cookies(name=\"session-id\") + await request.clear_cookies(domain=\"my-origin.com\") + await request.clear_cookies(path=\"/api/v1\") + await request.clear_cookies(name=\"session-id\", domain=\"my-origin.com\") ``` - **Details** - - Note that in some cases the frame is not available, and this method will throw. - - When request originates in the Service Worker. You can use `request.serviceWorker()` to check that. - - When navigation request is issued before the corresponding frame is created. You can use - `request.is_navigation_request()` to check that. - - Here is an example that handles all the cases: - - Returns - ------- - Frame + Parameters + ---------- + domain : Union[Pattern[str], str, None] + Only removes cookies with the given domain. + name : Union[Pattern[str], str, None] + Only removes cookies with the given name. + path : Union[Pattern[str], str, None] + Only removes cookies with the given path. """ - return mapping.from_impl(self._impl_obj.frame) - @property - def redirected_from(self) -> typing.Optional["Request"]: - """Request.redirected_from + await self._impl_obj.clear_cookies(domain=domain, name=name, path=path) - Request that was redirected by the server to this one, if any. + async def cookies( + self, urls: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None + ) -> typing.List[Cookie]: + """APIRequestContext.cookies - When the server responds with a redirect, Playwright creates a new `Request` object. The two requests are connected - by `redirectedFrom()` and `redirectedTo()` methods. When multiple server redirects has happened, it is possible to - construct the whole redirect chain by repeatedly calling `redirectedFrom()`. + If no URLs are specified, this method returns all cookies. If URLs are specified, only cookies that affect those + URLs are returned. For `browser_context.request` and `page.request`, this is equivalent to calling + `browser_context.cookies()` on the corresponding browser context. - **Usage** + Parameters + ---------- + urls : Union[Sequence[str], str, None] + Optional list of URLs. - For example, if the website `http://example.com` redirects to `https://example.com`: + Returns + ------- + List[{name: str, value: str, domain: str, path: str, expires: float, httpOnly: bool, secure: bool, sameSite: Union["Lax", "None", "Strict"], partitionKey: Union[str, None]}] + """ - ```py - response = await page.goto(\"http://example.com\") - print(response.request.redirected_from.url) # \"http://example.com\" - ``` + return mapping.from_impl_list( + await self._impl_obj.cookies(urls=mapping.to_impl(urls)) + ) - If the website `https://google.com` has no redirects: + async def delete( + self, + url: str, + *, + data: typing.Optional[typing.Union[str, bytes, typing.Any]] = None, + fail_on_status_code: typing.Optional[bool] = None, + form: typing.Optional[ + typing.Union[typing.Dict[str, typing.Union[str, float, bool]], "FormData"] + ] = None, + headers: typing.Optional[typing.Dict[str, str]] = None, + ignore_https_errors: typing.Optional[bool] = None, + max_redirects: typing.Optional[int] = None, + max_retries: typing.Optional[int] = None, + multipart: typing.Optional[ + typing.Union[ + typing.Dict[str, typing.Union[str, float, bool, bytes, FilePayload]], + "FormData", + ] + ] = None, + params: typing.Optional[ + typing.Union[typing.Dict[str, typing.Union[str, float, bool]], str] + ] = None, + timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, + ) -> "APIResponse": + """APIRequestContext.delete - ```py - response = await page.goto(\"https://google.com\") - print(response.request.redirected_from) # None - ``` + Sends HTTP(S) [DELETE](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/DELETE) request and returns its + response. The method will populate request cookies from the context and update context cookies from the response. + The method will automatically follow redirects. + + Parameters + ---------- + url : str + Target URL. + data : Union[Any, bytes, str, None] + Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string + and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` + header will be set to `application/octet-stream` if not explicitly set. + fail_on_status_code : Union[bool, None] + Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + codes. + form : Union[Dict[str, Union[bool, float, str]], FormData, None] + Provides an object that will be serialized as html form using `application/x-www-form-urlencoded` encoding and sent + as this request body. If this parameter is specified `content-type` header will be set to + `application/x-www-form-urlencoded` unless explicitly provided. Use `FormData` to send multiple values for the same + field. + headers : Union[Dict[str, str], None] + Allows to set HTTP headers. These headers will apply to the fetched request as well as any redirects initiated by + it. + ignore_https_errors : Union[bool, None] + Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + max_redirects : Union[int, None] + Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + exceeded. Defaults to `20`. Pass `0` to not follow redirects. + max_retries : Union[int, None] + Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not + retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries. + multipart : Union[Dict[str, Union[bool, bytes, float, str, {name: str, mimeType: str, buffer: bytes}]], FormData, None] + Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this + request body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless + explicitly provided. File values can be passed as file-like object containing file name, mime-type and its content. + Use `FormData` to send multiple files in the same field. + params : Union[Dict[str, Union[bool, float, str]], str, None] + Query parameters to be sent with the URL. + timeout : Union[float, None] + Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. Returns ------- - Union[Request, None] + APIResponse """ - return mapping.from_impl_nullable(self._impl_obj.redirected_from) - - @property - def redirected_to(self) -> typing.Optional["Request"]: - """Request.redirected_to - - New request issued by the browser if the server responded with redirect. - **Usage** + return mapping.from_impl( + await self._impl_obj.delete( + url=url, + data=mapping.to_impl(data), + failOnStatusCode=fail_on_status_code, + form=mapping.to_impl(form), + headers=mapping.to_impl(headers), + ignoreHTTPSErrors=ignore_https_errors, + maxRedirects=max_redirects, + maxRetries=max_retries, + multipart=mapping.to_impl(multipart), + params=mapping.to_impl(params), + timeout=to_milliseconds(timeout), + ) + ) - This method is the opposite of `request.redirected_from`: + async def dispose(self, *, reason: typing.Optional[str] = None) -> None: + """APIRequestContext.dispose - ```py - assert request.redirected_from.redirected_to == request - ``` + All responses returned by `api_request_context.get()` and similar methods are stored in the memory, so that you can + later call `api_response.body()`.This method discards all its resources, calling any method on disposed + `APIRequestContext` will throw an exception. - Returns - ------- - Union[Request, None] + Parameters + ---------- + reason : Union[str, None] + The reason to be reported to the operations interrupted by the context disposal. """ - return mapping.from_impl_nullable(self._impl_obj.redirected_to) - @property - def failure(self) -> typing.Optional[str]: - """Request.failure + await self._impl_obj.dispose(reason=reason) - The method returns `null` unless this request has failed, as reported by `requestfailed` event. + async def fetch( + self, + url_or_request: typing.Union[str, "Request"], + *, + data: typing.Optional[typing.Union[str, bytes, typing.Any]] = None, + fail_on_status_code: typing.Optional[bool] = None, + form: typing.Optional[ + typing.Union[typing.Dict[str, typing.Union[str, float, bool]], "FormData"] + ] = None, + headers: typing.Optional[typing.Dict[str, str]] = None, + ignore_https_errors: typing.Optional[bool] = None, + max_redirects: typing.Optional[int] = None, + max_retries: typing.Optional[int] = None, + method: typing.Optional[str] = None, + multipart: typing.Optional[ + typing.Union[ + typing.Dict[str, typing.Union[str, float, bool, bytes, FilePayload]], + "FormData", + ] + ] = None, + params: typing.Optional[ + typing.Union[typing.Dict[str, typing.Union[str, float, bool]], str] + ] = None, + timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, + ) -> "APIResponse": + """APIRequestContext.fetch + + Sends HTTP(S) request and returns its response. The method will populate request cookies from the context and + update context cookies from the response. The method will automatically follow redirects. **Usage** - Example of logging of all the failed requests: + JSON objects can be passed directly to the request: - ```py - page.on(\"requestfailed\", lambda request: print(request.url + \" \" + request.failure)) + ```python + data = { + \"title\": \"Book Title\", + \"body\": \"John Doe\", + } + api_request_context.fetch(\"https://example.com/api/createBook\", method=\"post\", data=data) ``` - Returns - ------- - Union[str, None] - """ - return mapping.from_maybe_impl(self._impl_obj.failure) - - @property - def timing(self) -> ResourceTiming: - """Request.timing - - Returns resource timing information for given request. Most of the timing values become available upon the - response, `responseEnd` becomes available when request finishes. Find more information at - [Resource Timing API](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming). - - **Usage** + The common way to send file(s) in the body of a request is to upload them as form fields with `multipart/form-data` + encoding, by specifiying the `multipart` parameter: - ```py - async with page.expect_event(\"requestfinished\") as request_info: - await page.goto(\"http://example.com\") - request = await request_info.value - print(request.timing) + ```python + api_request_context.fetch( + \"https://example.com/api/uploadScript\", method=\"post\", + multipart={ + \"fileField\": { + \"name\": \"f.js\", + \"mimeType\": \"text/javascript\", + \"buffer\": b\"console.log(2022);\", + }, + }) ``` - Returns - ------- - {startTime: float, domainLookupStart: float, domainLookupEnd: float, connectStart: float, secureConnectionStart: float, connectEnd: float, requestStart: float, responseStart: float, responseEnd: float} - """ - return mapping.from_impl(self._impl_obj.timing) - - @property - def headers(self) -> typing.Dict[str, str]: - """Request.headers - - An object with the request HTTP headers. The header names are lower-cased. Note that this method does not return - security-related headers, including cookie-related ones. You can use `request.all_headers()` for complete - list of headers that include `cookie` information. + Parameters + ---------- + url_or_request : Union[Request, str] + Target URL or Request to get all parameters from. + data : Union[Any, bytes, str, None] + Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string + and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` + header will be set to `application/octet-stream` if not explicitly set. + fail_on_status_code : Union[bool, None] + Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + codes. + form : Union[Dict[str, Union[bool, float, str]], FormData, None] + Provides an object that will be serialized as html form using `application/x-www-form-urlencoded` encoding and sent + as this request body. If this parameter is specified `content-type` header will be set to + `application/x-www-form-urlencoded` unless explicitly provided. Use `FormData` to send multiple values for the same + field. + headers : Union[Dict[str, str], None] + Allows to set HTTP headers. These headers will apply to the fetched request as well as any redirects initiated by + it. + ignore_https_errors : Union[bool, None] + Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + max_redirects : Union[int, None] + Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + exceeded. Defaults to `20`. Pass `0` to not follow redirects. + max_retries : Union[int, None] + Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not + retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries. + method : Union[str, None] + If set changes the fetch method (e.g. [PUT](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT) or + [POST](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST)). If not specified, GET method is used. + multipart : Union[Dict[str, Union[bool, bytes, float, str, {name: str, mimeType: str, buffer: bytes}]], FormData, None] + Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this + request body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless + explicitly provided. File values can be passed as file-like object containing file name, mime-type and its content. + Use `FormData` to send multiple files in the same field. + params : Union[Dict[str, Union[bool, float, str]], str, None] + Query parameters to be sent with the URL. + timeout : Union[float, None] + Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. Returns ------- - Dict[str, str] + APIResponse """ - return mapping.from_maybe_impl(self._impl_obj.headers) - - async def sizes(self) -> RequestSizes: - """Request.sizes - Returns resource size information for given request. + return mapping.from_impl( + await self._impl_obj.fetch( + urlOrRequest=mapping.to_impl(url_or_request), + data=mapping.to_impl(data), + failOnStatusCode=fail_on_status_code, + form=mapping.to_impl(form), + headers=mapping.to_impl(headers), + ignoreHTTPSErrors=ignore_https_errors, + maxRedirects=max_redirects, + maxRetries=max_retries, + method=method, + multipart=mapping.to_impl(multipart), + params=mapping.to_impl(params), + timeout=to_milliseconds(timeout), + ) + ) - Returns - ------- - {requestBodySize: int, requestHeadersSize: int, responseBodySize: int, responseHeadersSize: int} - """ - - return mapping.from_impl(await self._impl_obj.sizes()) - - async def response(self) -> typing.Optional["Response"]: - """Request.response - - Returns the matching `Response` object, or `null` if the response was not received due to error. - - Returns - ------- - Union[Response, None] - """ - - return mapping.from_impl_nullable(await self._impl_obj.response()) - - def is_navigation_request(self) -> bool: - """Request.is_navigation_request - - Whether this request is driving frame's navigation. - - Some navigation requests are issued before the corresponding frame is created, and therefore do not have - `request.frame` available. - - Returns - ------- - bool - """ - - return mapping.from_maybe_impl(self._impl_obj.is_navigation_request()) - - async def all_headers(self) -> typing.Dict[str, str]: - """Request.all_headers + async def get( + self, + url: str, + *, + data: typing.Optional[typing.Union[str, bytes, typing.Any]] = None, + fail_on_status_code: typing.Optional[bool] = None, + form: typing.Optional[ + typing.Union[typing.Dict[str, typing.Union[str, float, bool]], "FormData"] + ] = None, + headers: typing.Optional[typing.Dict[str, str]] = None, + ignore_https_errors: typing.Optional[bool] = None, + max_redirects: typing.Optional[int] = None, + max_retries: typing.Optional[int] = None, + multipart: typing.Optional[ + typing.Union[ + typing.Dict[str, typing.Union[str, float, bool, bytes, FilePayload]], + "FormData", + ] + ] = None, + params: typing.Optional[ + typing.Union[typing.Dict[str, typing.Union[str, float, bool]], str] + ] = None, + timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, + ) -> "APIResponse": + """APIRequestContext.get - An object with all the request HTTP headers associated with this request. The header names are lower-cased. + Sends HTTP(S) [GET](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET) request and returns its + response. The method will populate request cookies from the context and update context cookies from the response. + The method will automatically follow redirects. - Returns - ------- - Dict[str, str] - """ + **Usage** - return mapping.from_maybe_impl(await self._impl_obj.all_headers()) + Request parameters can be configured with `params` option, they will be serialized into the URL search parameters: - async def headers_array(self) -> typing.List[NameValue]: - """Request.headers_array + ```python + query_params = { + \"isbn\": \"1234\", + \"page\": \"23\" + } + api_request_context.get(\"https://example.com/api/getText\", params=query_params) + ``` - An array with all the request HTTP headers associated with this request. Unlike `request.all_headers()`, - header names are NOT lower-cased. Headers with multiple entries, such as `Set-Cookie`, appear in the array multiple - times. + Parameters + ---------- + url : str + Target URL. + data : Union[Any, bytes, str, None] + Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string + and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` + header will be set to `application/octet-stream` if not explicitly set. + fail_on_status_code : Union[bool, None] + Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + codes. + form : Union[Dict[str, Union[bool, float, str]], FormData, None] + Provides an object that will be serialized as html form using `application/x-www-form-urlencoded` encoding and sent + as this request body. If this parameter is specified `content-type` header will be set to + `application/x-www-form-urlencoded` unless explicitly provided. Use `FormData` to send multiple values for the same + field. + headers : Union[Dict[str, str], None] + Allows to set HTTP headers. These headers will apply to the fetched request as well as any redirects initiated by + it. + ignore_https_errors : Union[bool, None] + Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + max_redirects : Union[int, None] + Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + exceeded. Defaults to `20`. Pass `0` to not follow redirects. + max_retries : Union[int, None] + Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not + retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries. + multipart : Union[Dict[str, Union[bool, bytes, float, str, {name: str, mimeType: str, buffer: bytes}]], FormData, None] + Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this + request body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless + explicitly provided. File values can be passed as file-like object containing file name, mime-type and its content. + Use `FormData` to send multiple files in the same field. + params : Union[Dict[str, Union[bool, float, str]], str, None] + Query parameters to be sent with the URL. + timeout : Union[float, None] + Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. Returns ------- - List[{name: str, value: str}] + APIResponse """ - return mapping.from_impl_list(await self._impl_obj.headers_array()) + return mapping.from_impl( + await self._impl_obj.get( + url=url, + data=mapping.to_impl(data), + failOnStatusCode=fail_on_status_code, + form=mapping.to_impl(form), + headers=mapping.to_impl(headers), + ignoreHTTPSErrors=ignore_https_errors, + maxRedirects=max_redirects, + maxRetries=max_retries, + multipart=mapping.to_impl(multipart), + params=mapping.to_impl(params), + timeout=to_milliseconds(timeout), + ) + ) - async def header_value(self, name: str) -> typing.Optional[str]: - """Request.header_value + async def head( + self, + url: str, + *, + data: typing.Optional[typing.Union[str, bytes, typing.Any]] = None, + fail_on_status_code: typing.Optional[bool] = None, + form: typing.Optional[ + typing.Union[typing.Dict[str, typing.Union[str, float, bool]], "FormData"] + ] = None, + headers: typing.Optional[typing.Dict[str, str]] = None, + ignore_https_errors: typing.Optional[bool] = None, + max_redirects: typing.Optional[int] = None, + max_retries: typing.Optional[int] = None, + multipart: typing.Optional[ + typing.Union[ + typing.Dict[str, typing.Union[str, float, bool, bytes, FilePayload]], + "FormData", + ] + ] = None, + params: typing.Optional[ + typing.Union[typing.Dict[str, typing.Union[str, float, bool]], str] + ] = None, + timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, + ) -> "APIResponse": + """APIRequestContext.head - Returns the value of the header matching the name. The name is case-insensitive. + Sends HTTP(S) [HEAD](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD) request and returns its + response. The method will populate request cookies from the context and update context cookies from the response. + The method will automatically follow redirects. Parameters ---------- - name : str - Name of the header. + url : str + Target URL. + data : Union[Any, bytes, str, None] + Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string + and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` + header will be set to `application/octet-stream` if not explicitly set. + fail_on_status_code : Union[bool, None] + Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + codes. + form : Union[Dict[str, Union[bool, float, str]], FormData, None] + Provides an object that will be serialized as html form using `application/x-www-form-urlencoded` encoding and sent + as this request body. If this parameter is specified `content-type` header will be set to + `application/x-www-form-urlencoded` unless explicitly provided. Use `FormData` to send multiple values for the same + field. + headers : Union[Dict[str, str], None] + Allows to set HTTP headers. These headers will apply to the fetched request as well as any redirects initiated by + it. + ignore_https_errors : Union[bool, None] + Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + max_redirects : Union[int, None] + Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + exceeded. Defaults to `20`. Pass `0` to not follow redirects. + max_retries : Union[int, None] + Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not + retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries. + multipart : Union[Dict[str, Union[bool, bytes, float, str, {name: str, mimeType: str, buffer: bytes}]], FormData, None] + Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this + request body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless + explicitly provided. File values can be passed as file-like object containing file name, mime-type and its content. + Use `FormData` to send multiple files in the same field. + params : Union[Dict[str, Union[bool, float, str]], str, None] + Query parameters to be sent with the URL. + timeout : Union[float, None] + Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. Returns ------- - Union[str, None] + APIResponse """ - return mapping.from_maybe_impl(await self._impl_obj.header_value(name=name)) - - -mapping.register(RequestImpl, Request) - - -class Response(AsyncBase): - _impl_obj: ResponseImpl - - @property - def url(self) -> str: - """Response.url + return mapping.from_impl( + await self._impl_obj.head( + url=url, + data=mapping.to_impl(data), + failOnStatusCode=fail_on_status_code, + form=mapping.to_impl(form), + headers=mapping.to_impl(headers), + ignoreHTTPSErrors=ignore_https_errors, + maxRedirects=max_redirects, + maxRetries=max_retries, + multipart=mapping.to_impl(multipart), + params=mapping.to_impl(params), + timeout=to_milliseconds(timeout), + ) + ) - Contains the URL of the response. + async def patch( + self, + url: str, + *, + data: typing.Optional[typing.Union[str, bytes, typing.Any]] = None, + fail_on_status_code: typing.Optional[bool] = None, + form: typing.Optional[ + typing.Union[typing.Dict[str, typing.Union[str, float, bool]], "FormData"] + ] = None, + headers: typing.Optional[typing.Dict[str, str]] = None, + ignore_https_errors: typing.Optional[bool] = None, + max_redirects: typing.Optional[int] = None, + max_retries: typing.Optional[int] = None, + multipart: typing.Optional[ + typing.Union[ + typing.Dict[str, typing.Union[str, float, bool, bytes, FilePayload]], + "FormData", + ] + ] = None, + params: typing.Optional[ + typing.Union[typing.Dict[str, typing.Union[str, float, bool]], str] + ] = None, + timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, + ) -> "APIResponse": + """APIRequestContext.patch - Returns - ------- - str - """ - return mapping.from_maybe_impl(self._impl_obj.url) + Sends HTTP(S) [PATCH](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) request and returns its + response. The method will populate request cookies from the context and update context cookies from the response. + The method will automatically follow redirects. - @property - def ok(self) -> bool: - """Response.ok - - Contains a boolean stating whether the response was successful (status in the range 200-299) or not. - - Returns - ------- - bool - """ - return mapping.from_maybe_impl(self._impl_obj.ok) - - @property - def status(self) -> int: - """Response.status - - Contains the status code of the response (e.g., 200 for a success). + Parameters + ---------- + url : str + Target URL. + data : Union[Any, bytes, str, None] + Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string + and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` + header will be set to `application/octet-stream` if not explicitly set. + fail_on_status_code : Union[bool, None] + Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + codes. + form : Union[Dict[str, Union[bool, float, str]], FormData, None] + Provides an object that will be serialized as html form using `application/x-www-form-urlencoded` encoding and sent + as this request body. If this parameter is specified `content-type` header will be set to + `application/x-www-form-urlencoded` unless explicitly provided. Use `FormData` to send multiple values for the same + field. + headers : Union[Dict[str, str], None] + Allows to set HTTP headers. These headers will apply to the fetched request as well as any redirects initiated by + it. + ignore_https_errors : Union[bool, None] + Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + max_redirects : Union[int, None] + Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + exceeded. Defaults to `20`. Pass `0` to not follow redirects. + max_retries : Union[int, None] + Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not + retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries. + multipart : Union[Dict[str, Union[bool, bytes, float, str, {name: str, mimeType: str, buffer: bytes}]], FormData, None] + Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this + request body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless + explicitly provided. File values can be passed as file-like object containing file name, mime-type and its content. + Use `FormData` to send multiple files in the same field. + params : Union[Dict[str, Union[bool, float, str]], str, None] + Query parameters to be sent with the URL. + timeout : Union[float, None] + Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. Returns ------- - int + APIResponse """ - return mapping.from_maybe_impl(self._impl_obj.status) - @property - def status_text(self) -> str: - """Response.status_text + return mapping.from_impl( + await self._impl_obj.patch( + url=url, + data=mapping.to_impl(data), + failOnStatusCode=fail_on_status_code, + form=mapping.to_impl(form), + headers=mapping.to_impl(headers), + ignoreHTTPSErrors=ignore_https_errors, + maxRedirects=max_redirects, + maxRetries=max_retries, + multipart=mapping.to_impl(multipart), + params=mapping.to_impl(params), + timeout=to_milliseconds(timeout), + ) + ) - Contains the status text of the response (e.g. usually an \"OK\" for a success). + async def post( + self, + url: str, + *, + data: typing.Optional[typing.Union[str, bytes, typing.Any]] = None, + fail_on_status_code: typing.Optional[bool] = None, + form: typing.Optional[ + typing.Union[typing.Dict[str, typing.Union[str, float, bool]], "FormData"] + ] = None, + headers: typing.Optional[typing.Dict[str, str]] = None, + ignore_https_errors: typing.Optional[bool] = None, + max_redirects: typing.Optional[int] = None, + max_retries: typing.Optional[int] = None, + multipart: typing.Optional[ + typing.Union[ + typing.Dict[str, typing.Union[str, float, bool, bytes, FilePayload]], + "FormData", + ] + ] = None, + params: typing.Optional[ + typing.Union[typing.Dict[str, typing.Union[str, float, bool]], str] + ] = None, + timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, + ) -> "APIResponse": + """APIRequestContext.post - Returns - ------- - str - """ - return mapping.from_maybe_impl(self._impl_obj.status_text) + Sends HTTP(S) [POST](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST) request and returns its + response. The method will populate request cookies from the context and update context cookies from the response. + The method will automatically follow redirects. - @property - def headers(self) -> typing.Dict[str, str]: - """Response.headers + **Usage** - An object with the response HTTP headers. The header names are lower-cased. Note that this method does not return - security-related headers, including cookie-related ones. You can use `response.all_headers()` for complete - list of headers that include `cookie` information. + JSON objects can be passed directly to the request: - Returns - ------- - Dict[str, str] - """ - return mapping.from_maybe_impl(self._impl_obj.headers) + ```python + data = { + \"title\": \"Book Title\", + \"body\": \"John Doe\", + } + api_request_context.post(\"https://example.com/api/createBook\", data=data) + ``` - @property - def from_service_worker(self) -> bool: - """Response.from_service_worker + To send form data to the server use `form` option. Its value will be encoded into the request body with + `application/x-www-form-urlencoded` encoding (see below how to use `multipart/form-data` form encoding to send + files): - Indicates whether this Response was fulfilled by a Service Worker's Fetch Handler (i.e. via - [FetchEvent.respondWith](https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent/respondWith)). + ```python + formData = { + \"title\": \"Book Title\", + \"body\": \"John Doe\", + } + api_request_context.post(\"https://example.com/api/findBook\", form=formData) + ``` - Returns - ------- - bool - """ - return mapping.from_maybe_impl(self._impl_obj.from_service_worker) + The common way to send file(s) in the body of a request is to upload them as form fields with `multipart/form-data` + encoding. Use `FormData` to construct request body and pass it to the request as `multipart` parameter: - @property - def request(self) -> "Request": - """Response.request + ```python + api_request_context.post( + \"https://example.com/api/uploadScript'\", + multipart={ + \"fileField\": { + \"name\": \"f.js\", + \"mimeType\": \"text/javascript\", + \"buffer\": b\"console.log(2022);\", + }, + }) + ``` - Returns the matching `Request` object. + Parameters + ---------- + url : str + Target URL. + data : Union[Any, bytes, str, None] + Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string + and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` + header will be set to `application/octet-stream` if not explicitly set. + fail_on_status_code : Union[bool, None] + Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + codes. + form : Union[Dict[str, Union[bool, float, str]], FormData, None] + Provides an object that will be serialized as html form using `application/x-www-form-urlencoded` encoding and sent + as this request body. If this parameter is specified `content-type` header will be set to + `application/x-www-form-urlencoded` unless explicitly provided. Use `FormData` to send multiple values for the same + field. + headers : Union[Dict[str, str], None] + Allows to set HTTP headers. These headers will apply to the fetched request as well as any redirects initiated by + it. + ignore_https_errors : Union[bool, None] + Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + max_redirects : Union[int, None] + Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + exceeded. Defaults to `20`. Pass `0` to not follow redirects. + max_retries : Union[int, None] + Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not + retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries. + multipart : Union[Dict[str, Union[bool, bytes, float, str, {name: str, mimeType: str, buffer: bytes}]], FormData, None] + Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this + request body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless + explicitly provided. File values can be passed as file-like object containing file name, mime-type and its content. + Use `FormData` to send multiple files in the same field. + params : Union[Dict[str, Union[bool, float, str]], str, None] + Query parameters to be sent with the URL. + timeout : Union[float, None] + Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. Returns ------- - Request + APIResponse """ - return mapping.from_impl(self._impl_obj.request) - @property - def frame(self) -> "Frame": - """Response.frame - - Returns the `Frame` that initiated this response. - - Returns - ------- - Frame - """ - return mapping.from_impl(self._impl_obj.frame) + return mapping.from_impl( + await self._impl_obj.post( + url=url, + data=mapping.to_impl(data), + failOnStatusCode=fail_on_status_code, + form=mapping.to_impl(form), + headers=mapping.to_impl(headers), + ignoreHTTPSErrors=ignore_https_errors, + maxRedirects=max_redirects, + maxRetries=max_retries, + multipart=mapping.to_impl(multipart), + params=mapping.to_impl(params), + timeout=to_milliseconds(timeout), + ) + ) - async def all_headers(self) -> typing.Dict[str, str]: - """Response.all_headers + async def put( + self, + url: str, + *, + data: typing.Optional[typing.Union[str, bytes, typing.Any]] = None, + fail_on_status_code: typing.Optional[bool] = None, + form: typing.Optional[ + typing.Union[typing.Dict[str, typing.Union[str, float, bool]], "FormData"] + ] = None, + headers: typing.Optional[typing.Dict[str, str]] = None, + ignore_https_errors: typing.Optional[bool] = None, + max_redirects: typing.Optional[int] = None, + max_retries: typing.Optional[int] = None, + multipart: typing.Optional[ + typing.Union[ + typing.Dict[str, typing.Union[str, float, bool, bytes, FilePayload]], + "FormData", + ] + ] = None, + params: typing.Optional[ + typing.Union[typing.Dict[str, typing.Union[str, float, bool]], str] + ] = None, + timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, + ) -> "APIResponse": + """APIRequestContext.put - An object with all the response HTTP headers associated with this response. + Sends HTTP(S) [PUT](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT) request and returns its + response. The method will populate request cookies from the context and update context cookies from the response. + The method will automatically follow redirects. - Returns + Parameters + ---------- + url : str + Target URL. + data : Union[Any, bytes, str, None] + Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string + and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` + header will be set to `application/octet-stream` if not explicitly set. + fail_on_status_code : Union[bool, None] + Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + codes. + form : Union[Dict[str, Union[bool, float, str]], FormData, None] + Provides an object that will be serialized as html form using `application/x-www-form-urlencoded` encoding and sent + as this request body. If this parameter is specified `content-type` header will be set to + `application/x-www-form-urlencoded` unless explicitly provided. Use `FormData` to send multiple values for the same + field. + headers : Union[Dict[str, str], None] + Allows to set HTTP headers. These headers will apply to the fetched request as well as any redirects initiated by + it. + ignore_https_errors : Union[bool, None] + Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + max_redirects : Union[int, None] + Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + exceeded. Defaults to `20`. Pass `0` to not follow redirects. + max_retries : Union[int, None] + Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not + retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries. + multipart : Union[Dict[str, Union[bool, bytes, float, str, {name: str, mimeType: str, buffer: bytes}]], FormData, None] + Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this + request body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless + explicitly provided. File values can be passed as file-like object containing file name, mime-type and its content. + Use `FormData` to send multiple files in the same field. + params : Union[Dict[str, Union[bool, float, str]], str, None] + Query parameters to be sent with the URL. + timeout : Union[float, None] + Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. + + Returns ------- - Dict[str, str] + APIResponse """ - return mapping.from_maybe_impl(await self._impl_obj.all_headers()) + return mapping.from_impl( + await self._impl_obj.put( + url=url, + data=mapping.to_impl(data), + failOnStatusCode=fail_on_status_code, + form=mapping.to_impl(form), + headers=mapping.to_impl(headers), + ignoreHTTPSErrors=ignore_https_errors, + maxRedirects=max_redirects, + maxRetries=max_retries, + multipart=mapping.to_impl(multipart), + params=mapping.to_impl(params), + timeout=to_milliseconds(timeout), + ) + ) - async def headers_array(self) -> typing.List[NameValue]: - """Response.headers_array + async def storage_state( + self, + *, + indexed_db: typing.Optional[bool] = None, + opfs: typing.Optional[bool] = None, + path: typing.Optional[typing.Union[str, pathlib.Path]] = None, + ) -> StorageState: + """APIRequestContext.storage_state + + Returns storage state for this request context, contains current cookies and local storage snapshot if it was + passed to the constructor. - An array with all the response HTTP headers associated with this response. Unlike `response.all_headers()`, - header names are NOT lower-cased. Headers with multiple entries, such as `Set-Cookie`, appear in the array multiple - times. Some browser network stacks combine multiple field values before reporting them, so separate entries are not - always available. + Parameters + ---------- + indexed_db : Union[bool, None] + Set to `true` to include IndexedDB in the storage state snapshot. + opfs : Union[bool, None] + Set to `true` to include the origin private file system in the storage state snapshot. + path : Union[pathlib.Path, str, None] + The file path to save the storage state to. If `path` is a relative path, then it is resolved relative to current + working directory. If no path is provided, storage state is still returned, but won't be saved to the disk. Returns ------- - List[{name: str, value: str}] + {cookies: List[{name: str, value: str, domain: str, path: str, expires: float, httpOnly: bool, secure: bool, sameSite: Union["Lax", "None", "Strict"]}], origins: List[{origin: str, localStorage: List[{name: str, value: str}]}]} """ - return mapping.from_impl_list(await self._impl_obj.headers_array()) + return mapping.from_impl( + await self._impl_obj.storage_state( + indexedDB=indexed_db, opfs=opfs, path=path + ) + ) - async def header_value(self, name: str) -> typing.Optional[str]: - """Response.header_value + @property + def tracing(self) -> "Tracing": + """APIRequestContext.tracing - Returns the value of the header matching the name. The name is case-insensitive. If multiple headers have the same - name (except `set-cookie`), they are returned as a list separated by `, `. For `set-cookie`, the `\\n` separator is - used. If no headers are found, `null` is returned. + Tracing recorder for requests made through this API request context. - Parameters - ---------- - name : str - Name of the header. + Returns + ------- + Tracing + """ + return mapping.from_impl(self._impl_obj.tracing) + + +mapping.register(APIRequestContextImpl, APIRequestContext) + + +class APIResponse(AsyncBase): + _impl_obj: APIResponseImpl + + async def body(self) -> bytes: + """APIResponse.body + + Returns the buffer with response body. Returns ------- - Union[str, None] + bytes """ - return mapping.from_maybe_impl(await self._impl_obj.header_value(name=name)) + return mapping.from_maybe_impl(await self._impl_obj.body()) - async def header_values(self, name: str) -> typing.List[str]: - """Response.header_values + async def dispose(self) -> None: + """APIResponse.dispose - Returns all values of the headers matching the name, for example `set-cookie`. The name is case-insensitive. + Disposes the body of this response. If not called then the body will stay in memory until the context closes. + """ - Parameters - ---------- - name : str - Name of the header. + await self._impl_obj.dispose() + + @property + def headers(self) -> typing.Dict[str, str]: + """APIResponse.headers + + An object with all the response HTTP headers associated with this response. Returns ------- - List[str] + Dict[str, str] """ + return mapping.from_maybe_impl(self._impl_obj.headers) - return mapping.from_maybe_impl(await self._impl_obj.header_values(name=name)) + @property + def headers_array(self) -> typing.List[NameValue]: + """APIResponse.headers_array - async def server_addr(self) -> typing.Optional[RemoteAddr]: - """Response.server_addr + An array with all the response HTTP headers associated with this response. Header names are not lower-cased. + Headers with multiple entries, such as `Set-Cookie`, appear in the array multiple times. - Returns the IP address and port of the server. + Returns + ------- + List[{name: str, value: str}] + """ + return mapping.from_impl_list(self._impl_obj.headers_array) + + async def json(self) -> typing.Any: + """APIResponse.json + + Returns the JSON representation of response body. + + This method will throw if the response body is not parsable via `JSON.parse`. Returns ------- - Union[{ipAddress: str, port: int}, None] + Any """ - return mapping.from_impl_nullable(await self._impl_obj.server_addr()) + return mapping.from_maybe_impl(await self._impl_obj.json()) + + @property + def ok(self) -> bool: + """APIResponse.ok + + Contains a boolean stating whether the response was successful (status in the range 200-299) or not. + + Returns + ------- + bool + """ + return mapping.from_maybe_impl(self._impl_obj.ok) async def security_details(self) -> typing.Optional[SecurityDetails]: - """Response.security_details + """APIResponse.security_details - Returns SSL and other security information. + Returns SSL and other security information. Resolves to `null` for non-HTTPS responses. For redirected requests, + returns the information for the last request in the redirect chain. Returns ------- @@ -627,40 +1142,45 @@ async def security_details(self) -> typing.Optional[SecurityDetails]: return mapping.from_impl_nullable(await self._impl_obj.security_details()) - async def http_version(self) -> str: - """Response.http_version + async def server_addr(self) -> typing.Optional[RemoteAddr]: + """APIResponse.server_addr - Returns the http version used by the response. + Returns the IP address and port of the server. Resolves to `null` if the server address is not available. For + redirected requests, returns the information for the last request in the redirect chain. Returns ------- - str + Union[{ipAddress: str, port: int}, None] """ - return mapping.from_maybe_impl(await self._impl_obj.http_version()) + return mapping.from_impl_nullable(await self._impl_obj.server_addr()) - async def finished(self) -> None: - """Response.finished + @property + def status(self) -> int: + """APIResponse.status - Waits for this response to finish, returns always `null`. - """ + Contains the status code of the response (e.g., 200 for a success). - await self._impl_obj.finished() + Returns + ------- + int + """ + return mapping.from_maybe_impl(self._impl_obj.status) - async def body(self) -> bytes: - """Response.body + @property + def status_text(self) -> str: + """APIResponse.status_text - Returns the buffer with response body. + Contains the status text of the response (e.g. usually an \"OK\" for a success). Returns ------- - bytes + str """ - - return mapping.from_maybe_impl(await self._impl_obj.body()) + return mapping.from_maybe_impl(self._impl_obj.status_text) async def text(self) -> str: - """Response.text + """APIResponse.text Returns the text representation of response body. @@ -671,5205 +1191,5009 @@ async def text(self) -> str: return mapping.from_maybe_impl(await self._impl_obj.text()) - async def json(self) -> typing.Any: - """Response.json - - Returns the JSON representation of response body. + @property + def timing(self) -> ResourceTiming: + """APIResponse.timing - This method will throw if the response body is not parsable via `JSON.parse`. + Returns resource timing information for given response. For redirected requests, returns the information for the + last request in the redirect chain. When the response is served [from the HAR file](https://playwright.dev/python/docs/mock#replaying-from-har), + timing information is not available and all the values are -1. Find more information at + [Resource Timing API](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming). Returns ------- - Any + {startTime: float, domainLookupStart: float, domainLookupEnd: float, connectStart: float, secureConnectionStart: float, connectEnd: float, requestStart: float, responseStart: float, responseEnd: float} """ - - return mapping.from_maybe_impl(await self._impl_obj.json()) - - -mapping.register(ResponseImpl, Response) - - -class Route(AsyncBase): - _impl_obj: RouteImpl + return mapping.from_impl(self._impl_obj.timing) @property - def request(self) -> "Request": - """Route.request + def url(self) -> str: + """APIResponse.url - A request to be routed. + Contains the URL of the response. Returns ------- - Request + str """ - return mapping.from_impl(self._impl_obj.request) + return mapping.from_maybe_impl(self._impl_obj.url) - async def abort(self, error_code: typing.Optional[str] = None) -> None: - """Route.abort - Aborts the route's request. +mapping.register(APIResponseImpl, APIResponse) - Parameters - ---------- - error_code : Union[str, None] - Optional error code. Defaults to `failed`, could be one of the following: - - `'aborted'` - An operation was aborted (due to user action) - - `'accessdenied'` - Permission to access a resource, other than the network, was denied - - `'addressunreachable'` - The IP address is unreachable. This usually means that there is no route to the - specified host or network. - - `'blockedbyclient'` - The client chose to block the request. - - `'blockedbyresponse'` - The request failed because the response was delivered along with requirements which are - not met ('X-Frame-Options' and 'Content-Security-Policy' ancestor checks, for instance). - - `'connectionaborted'` - A connection timed out as a result of not receiving an ACK for data sent. - - `'connectionclosed'` - A connection was closed (corresponding to a TCP FIN). - - `'connectionfailed'` - A connection attempt failed. - - `'connectionrefused'` - A connection attempt was refused. - - `'connectionreset'` - A connection was reset (corresponding to a TCP RST). - - `'internetdisconnected'` - The Internet connection has been lost. - - `'namenotresolved'` - The host name could not be resolved. - - `'timedout'` - An operation timed out. - - `'failed'` - A generic failure occurred. - """ - await self._impl_obj.abort(errorCode=error_code) +class APIResponseAssertions(AsyncBase): + _impl_obj: APIResponseAssertionsImpl - async def fulfill( - self, - *, - status: typing.Optional[int] = None, - headers: typing.Optional[typing.Dict[str, str]] = None, - body: typing.Optional[typing.Union[str, bytes]] = None, - json: typing.Optional[typing.Any] = None, - path: typing.Optional[typing.Union[pathlib.Path, str]] = None, - content_type: typing.Optional[str] = None, - response: typing.Optional["APIResponse"] = None, - ) -> None: - """Route.fulfill + async def not_to_be_ok(self) -> None: + """APIResponseAssertions.not_to_be_ok - Fulfills route's request with given response. + The opposite of `api_response_assertions.to_be_ok()`. + """ + __tracebackhide__ = True - **Usage** + await self._impl_obj.not_to_be_ok() - An example of fulfilling all requests with 404 responses: + async def to_be_ok(self) -> None: + """APIResponseAssertions.to_be_ok - ```py - await page.route(\"**/*\", lambda route: route.fulfill( - status=404, - content_type=\"text/plain\", - body=\"not found!\")) - ``` + Ensures the response status code is within `200..299` range. - An example of serving static file: + **Usage** ```py - await page.route(\"**/xhr_endpoint\", lambda route: route.fulfill(path=\"mock_data.json\")) - ``` + from playwright.async_api import expect - Parameters - ---------- - status : Union[int, None] - Response status code, defaults to `200`. - headers : Union[Dict[str, str], None] - Response headers. Header values will be converted to a string. - body : Union[bytes, str, None] - Response body. - json : Union[Any, None] - JSON response. This method will set the content type to `application/json` if not set. - path : Union[pathlib.Path, str, None] - File path to respond with. The content type will be inferred from file extension. If `path` is a relative path, - then it is resolved relative to the current working directory. - content_type : Union[str, None] - If set, equals to setting `Content-Type` response header. - response : Union[APIResponse, None] - `APIResponse` to fulfill route's request with. Individual fields of the response (such as headers) can be - overridden using fulfill options. + # ... + await expect(response).to_be_ok() + ``` """ + __tracebackhide__ = True - await self._impl_obj.fulfill( - status=status, - headers=mapping.to_impl(headers), - body=body, - json=mapping.to_impl(json), - path=path, - contentType=content_type, - response=response._impl_obj if response else None, - ) - - async def fetch( - self, - *, - url: typing.Optional[str] = None, - method: typing.Optional[str] = None, - headers: typing.Optional[typing.Dict[str, str]] = None, - post_data: typing.Optional[typing.Union[typing.Any, str, bytes]] = None, - max_redirects: typing.Optional[int] = None, - max_retries: typing.Optional[int] = None, - timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, - ) -> "APIResponse": - """Route.fetch + await self._impl_obj.to_be_ok() - Performs the request and fetches result without fulfilling it, so that the response could be modified and then - fulfilled. - **Usage** +mapping.register(APIResponseAssertionsImpl, APIResponseAssertions) - ```py - async def handle(route): - response = await route.fetch() - json = await response.json() - json[\"message\"][\"big_red_dog\"] = [] - await route.fulfill(response=response, json=json) - await page.route(\"https://dog.ceo/api/breeds/list/all\", handle) - ``` +class Browser(AsyncContextManager): + _impl_obj: BrowserImpl - **Details** + async def bind( + self, + title: str, + *, + host: typing.Optional[str] = None, + port: typing.Optional[int] = None, + workspace_dir: typing.Optional[str] = None, + ) -> BrowserBindResult: + """Browser.bind - Note that `headers` option will apply to the fetched request as well as any redirects initiated by it. If you want - to only apply `headers` to the original request, but not to redirects, look into `route.continue_()` - instead. + Binds the browser to a named pipe or web socket, making it available for other clients to connect to. Parameters ---------- - url : Union[str, None] - If set changes the request URL. New URL must have same protocol as original one. - method : Union[str, None] - If set changes the request method (e.g. GET or POST). - headers : Union[Dict[str, str], None] - If set changes the request HTTP headers. Header values will be converted to a string. - post_data : Union[Any, bytes, str, None] - Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string - and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` - header will be set to `application/octet-stream` if not explicitly set. - max_redirects : Union[int, None] - Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is - exceeded. Defaults to `20`. Pass `0` to not follow redirects. - max_retries : Union[int, None] - Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not - retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries. - timeout : Union[float, None] - Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. + title : str + Title of the browser server, used for identification. + host : Union[str, None] + Host to bind the web socket server to. When specified, a web socket server is created instead of a named pipe. + port : Union[int, None] + Port to bind the web socket server to. When specified, a web socket server is created instead of a named pipe. Use + `0` to let the OS pick an available port. + workspace_dir : Union[str, None] + Working directory associated with this browser server. Returns ------- - APIResponse + {endpoint: str} """ return mapping.from_impl( - await self._impl_obj.fetch( - url=url, - method=method, - headers=mapping.to_impl(headers), - postData=mapping.to_impl(post_data), - maxRedirects=max_redirects, - maxRetries=max_retries, - timeout=to_milliseconds(timeout), + await self._impl_obj.bind( + title=title, host=host, port=port, workspaceDir=workspace_dir ) ) - async def fallback( - self, - *, - url: typing.Optional[str] = None, - method: typing.Optional[str] = None, - headers: typing.Optional[typing.Dict[str, str]] = None, - post_data: typing.Optional[typing.Union[typing.Any, str, bytes]] = None, - ) -> None: - """Route.fallback + @property + def browser_type(self) -> "BrowserType": + """Browser.browser_type - Continues route's request with optional overrides. The method is similar to `route.continue_()` with the - difference that other matching handlers will be invoked before sending the request. + Get the browser type (chromium, firefox or webkit) that the browser belongs to. - **Usage** + Returns + ------- + BrowserType + """ + return mapping.from_impl(self._impl_obj.browser_type) - When several routes match the given pattern, they run in the order opposite to their registration. That way the - last registered route can always override all the previous ones. In the example below, request will be handled by - the bottom-most handler first, then it'll fall back to the previous one and in the end will be aborted by the first - registered route. + async def close(self, *, reason: typing.Optional[str] = None) -> None: + """Browser.close - ```py - await page.route(\"**/*\", lambda route: route.abort()) # Runs last. - await page.route(\"**/*\", lambda route: route.fallback()) # Runs second. - await page.route(\"**/*\", lambda route: route.fallback()) # Runs first. - ``` + In case this browser is obtained using `browser_type.launch()`, closes the browser and all of its pages (if any + were opened). - Registering multiple routes is useful when you want separate handlers to handle different kinds of requests, for - example API calls vs page resources or GET requests vs POST requests as in the example below. + In case this browser is connected to, clears all created contexts belonging to this browser and disconnects from + the browser server. - ```py - # Handle GET requests. - async def handle_get(route): - if route.request.method != \"GET\": - await route.fallback() - return - # Handling GET only. - # ... + **NOTE** This is similar to force-quitting the browser. To close pages gracefully and ensure you receive page close + events, call `browser_context.close()` on any `BrowserContext` instances you explicitly created earlier using + `browser.new_context()` **before** calling `browser.close()`. - # Handle POST requests. - async def handle_post(route): - if route.request.method != \"POST\": - await route.fallback() - return - # Handling POST only. - # ... + The `Browser` object itself is considered to be disposed and cannot be used anymore. - await page.route(\"**/*\", handle_get) - await page.route(\"**/*\", handle_post) - ``` + Parameters + ---------- + reason : Union[str, None] + The reason to be reported to the operations interrupted by the browser closure. + """ - One can also modify request while falling back to the subsequent handler, that way intermediate route handler can - modify url, method, headers and postData of the request. + await self._impl_obj.close(reason=reason) - ```py - async def handle(route, request): - # override headers - headers = { - **request.headers, - \"foo\": \"foo-value\", # set \"foo\" header - \"bar\": None # remove \"bar\" header - } - await route.fallback(headers=headers) + @property + def contexts(self) -> typing.List["BrowserContext"]: + """Browser.contexts - await page.route(\"**/*\", handle) - ``` + Returns an array of all open browser contexts. In a newly created browser, this will return zero browser contexts. - Use `route.continue_()` to immediately send the request to the network, other matching handlers won't be - invoked in that case. - - Parameters - ---------- - url : Union[str, None] - If set changes the request URL. New URL must have same protocol as original one. Changing the URL won't affect the - route matching, all the routes are matched using the original request URL. - method : Union[str, None] - If set changes the request method (e.g. GET or POST). - headers : Union[Dict[str, str], None] - If set changes the request HTTP headers. Header values will be converted to a string. - post_data : Union[Any, bytes, str, None] - If set changes the post data of request. - """ - - await self._impl_obj.fallback( - url=url, - method=method, - headers=mapping.to_impl(headers), - postData=mapping.to_impl(post_data), - ) - - async def continue_( - self, - *, - url: typing.Optional[str] = None, - method: typing.Optional[str] = None, - headers: typing.Optional[typing.Dict[str, str]] = None, - post_data: typing.Optional[typing.Union[typing.Any, str, bytes]] = None, - ) -> None: - """Route.continue_ - - Sends route's request to the network with optional overrides. - - **Usage** + **Usage** ```py - async def handle(route, request): - # override headers - headers = { - **request.headers, - \"foo\": \"foo-value\", # set \"foo\" header - \"bar\": None # remove \"bar\" header - } - await route.continue_(headers=headers) - - await page.route(\"**/*\", handle) + browser = await pw.webkit.launch() + print(len(browser.contexts)) # prints `0` + context = await browser.new_context() + print(len(browser.contexts)) # prints `1` ``` - **Details** - - The `headers` option applies to both the routed request and any redirects it initiates. However, `url`, `method`, - and `post_data` only apply to the original request and are not carried over to redirected requests. - - `route.continue_()` will immediately send the request to the network, other matching handlers won't be - invoked. Use `route.fallback()` If you want next matching handler in the chain to be invoked. + Returns + ------- + List[BrowserContext] + """ + return mapping.from_impl_list(self._impl_obj.contexts) - **NOTE** Some request headers are **forbidden** and cannot be overridden (for example, `Cookie`, `Host`, - `Content-Length` and others, see - [this MDN page](https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_request_header) for full list). If an - override is provided for a forbidden header, it will be ignored and the original request header will be used. + def is_connected(self) -> bool: + """Browser.is_connected - To set custom cookies, use `browser_context.add_cookies()`. + Indicates that the browser is connected. - Parameters - ---------- - url : Union[str, None] - If set changes the request URL. New URL must have same protocol as original one. - method : Union[str, None] - If set changes the request method (e.g. GET or POST). - headers : Union[Dict[str, str], None] - If set changes the request HTTP headers. Header values will be converted to a string. - post_data : Union[Any, bytes, str, None] - If set changes the post data of request. + Returns + ------- + bool """ - await self._impl_obj.continue_( - url=url, - method=method, - headers=mapping.to_impl(headers), - postData=mapping.to_impl(post_data), - ) - - -mapping.register(RouteImpl, Route) + return mapping.from_maybe_impl(self._impl_obj.is_connected()) + async def new_browser_cdp_session(self) -> "CDPSession": + """Browser.new_browser_cdp_session -class WebSocket(AsyncBase): - _impl_obj: WebSocketImpl + **NOTE** CDP Sessions are only supported on Chromium-based browsers. - @typing.overload - def on( - self, - event: Literal["close"], - f: typing.Callable[["WebSocket"], "typing.Union[typing.Awaitable[None], None]"], - ) -> None: - """ - Fired when the websocket closes.""" + Returns the newly created browser session. - @typing.overload - def on( - self, - event: Literal["framereceived"], - f: typing.Callable[ - ["typing.Union[bytes, str]"], "typing.Union[typing.Awaitable[None], None]" - ], - ) -> None: + Returns + ------- + CDPSession """ - Fired when the websocket receives a frame.""" - @typing.overload - def on( - self, - event: Literal["framesent"], - f: typing.Callable[ - ["typing.Union[bytes, str]"], "typing.Union[typing.Awaitable[None], None]" - ], - ) -> None: - """ - Fired when the websocket sends a frame.""" + return mapping.from_impl(await self._impl_obj.new_browser_cdp_session()) - @typing.overload - def on( + async def new_context( self, - event: Literal["socketerror"], - f: typing.Callable[["str"], "typing.Union[typing.Awaitable[None], None]"], - ) -> None: - """ - Fired when the websocket has an error.""" + *, + accept_downloads: typing.Optional[bool] = None, + base_url: typing.Optional[str] = None, + bypass_csp: typing.Optional[bool] = None, + client_certificates: typing.Optional[typing.Sequence[ClientCertificate]] = None, + color_scheme: typing.Optional[ + Literal["dark", "light", "no-preference", "null"] + ] = None, + contrast: typing.Optional[Literal["more", "no-preference", "null"]] = None, + default_browser_type: typing.Optional[str] = None, + device_scale_factor: typing.Optional[float] = None, + extra_http_headers: typing.Optional[typing.Dict[str, str]] = None, + forced_colors: typing.Optional[Literal["active", "none", "null"]] = None, + geolocation: typing.Optional[Geolocation] = None, + has_touch: typing.Optional[bool] = None, + http_credentials: typing.Optional[ + typing.Union[HttpCredentials, typing.Sequence[HttpCredentials]] + ] = None, + ignore_https_errors: typing.Optional[bool] = None, + is_mobile: typing.Optional[bool] = None, + java_script_enabled: typing.Optional[bool] = None, + locale: typing.Optional[str] = None, + no_viewport: typing.Optional[bool] = None, + offline: typing.Optional[bool] = None, + permissions: typing.Optional[typing.Sequence[str]] = None, + proxy: typing.Optional[ProxySettings] = None, + record_har_content: typing.Optional[Literal["attach", "embed", "omit"]] = None, + record_har_mode: typing.Optional[Literal["full", "minimal"]] = None, + record_har_omit_content: typing.Optional[bool] = None, + record_har_path: typing.Optional[typing.Union[str, pathlib.Path]] = None, + record_har_url_filter: typing.Optional[ + typing.Union[str, typing.Pattern[str]] + ] = None, + record_video_dir: typing.Optional[typing.Union[str, pathlib.Path]] = None, + record_video_fps: typing.Optional[int] = None, + record_video_size: typing.Optional[ViewportSize] = None, + reduced_motion: typing.Optional[ + Literal["no-preference", "null", "reduce"] + ] = None, + screen: typing.Optional[ViewportSize] = None, + service_workers: typing.Optional[Literal["allow", "block"]] = None, + storage_state: typing.Optional[ + typing.Union[str, pathlib.Path, StorageState] + ] = None, + strict_selectors: typing.Optional[bool] = None, + timezone_id: typing.Optional[str] = None, + user_agent: typing.Optional[str] = None, + viewport: typing.Optional[ViewportSize] = None, + ) -> "BrowserContext": + """Browser.new_context - def on( - self, - event: str, - f: typing.Callable[..., typing.Union[typing.Awaitable[None], None]], - ) -> None: - return super().on(event=event, f=f) + Creates a new browser context. It won't share cookies/cache with other browser contexts. - @typing.overload - def once( - self, - event: Literal["close"], - f: typing.Callable[["WebSocket"], "typing.Union[typing.Awaitable[None], None]"], - ) -> None: - """ - Fired when the websocket closes.""" + **NOTE** If directly using this method to create `BrowserContext`s, it is best practice to explicitly close the + returned context via `browser_context.close()` when your code is done with the `BrowserContext`, and before calling + `browser.close()`. This will ensure the `context` is closed gracefully and any artifacts—like HARs and videos—are + fully flushed and saved. - @typing.overload - def once( - self, - event: Literal["framereceived"], - f: typing.Callable[ - ["typing.Union[bytes, str]"], "typing.Union[typing.Awaitable[None], None]" - ], - ) -> None: - """ - Fired when the websocket receives a frame.""" + **Usage** - @typing.overload - def once( - self, - event: Literal["framesent"], - f: typing.Callable[ - ["typing.Union[bytes, str]"], "typing.Union[typing.Awaitable[None], None]" - ], - ) -> None: - """ - Fired when the websocket sends a frame.""" + ```py + browser = await playwright.firefox.launch() # or \"chromium\" or \"webkit\". + # create a new incognito browser context. + context = await browser.new_context() + # create a new page in a pristine context. + page = await context.new_page() + await page.goto(\"https://example.com\") - @typing.overload - def once( - self, - event: Literal["socketerror"], - f: typing.Callable[["str"], "typing.Union[typing.Awaitable[None], None]"], - ) -> None: - """ - Fired when the websocket has an error.""" + # gracefully close up everything + await context.close() + await browser.close() + ``` - def once( - self, - event: str, - f: typing.Callable[..., typing.Union[typing.Awaitable[None], None]], - ) -> None: - return super().once(event=event, f=f) + Parameters + ---------- + accept_downloads : Union[bool, None] + Whether to automatically download all the attachments. Defaults to `true` where all the downloads are accepted. + base_url : Union[str, None] + When using `page.goto()`, `page.route()`, `page.wait_for_url()`, `page.expect_request()`, or + `page.expect_response()` it takes the base URL in consideration by using the + [`URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor for building the corresponding URL. + Unset by default. Examples: + - baseURL: `http://localhost:3000` and navigating to `/bar.html` results in `http://localhost:3000/bar.html` + - baseURL: `http://localhost:3000/foo/` and navigating to `./bar.html` results in + `http://localhost:3000/foo/bar.html` + - baseURL: `http://localhost:3000/foo` (without trailing slash) and navigating to `./bar.html` results in + `http://localhost:3000/bar.html` + bypass_csp : Union[bool, None] + Toggles bypassing page's Content-Security-Policy. Defaults to `false`. + client_certificates : Union[Sequence[{origin: str, certPath: Union[pathlib.Path, str, None], cert: Union[bytes, None], keyPath: Union[pathlib.Path, str, None], key: Union[bytes, None], pfxPath: Union[pathlib.Path, str, None], pfx: Union[bytes, None], passphrase: Union[str, None]}], None] + TLS Client Authentication allows the server to request a client certificate and verify it. - @property - def url(self) -> str: - """WebSocket.url + **Details** - Contains the URL of the WebSocket. + An array of client certificates to be used. Each certificate object must have either both `certPath` and `keyPath`, + a single `pfxPath`, or their corresponding direct value equivalents (`cert` and `key`, or `pfx`). Optionally, + `passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided + with an exact match to the request origin that the certificate is valid for. - Returns - ------- - str - """ - return mapping.from_maybe_impl(self._impl_obj.url) - - @typing.overload - def expect_event( - self, - event: typing.Literal["close"], - predicate: typing.Optional[typing.Callable[["WebSocket"], bool]] = None, - *, - timeout: typing.Optional[float] = None, - ) -> AsyncEventContextManager["WebSocket"]: ... - - @typing.overload - def expect_event( - self, - event: typing.Literal["framereceived"], - predicate: typing.Optional[ - typing.Callable[["typing.Union[bytes, str]"], bool] - ] = None, - *, - timeout: typing.Optional[float] = None, - ) -> AsyncEventContextManager["typing.Union[bytes, str]"]: ... - - @typing.overload - def expect_event( - self, - event: typing.Literal["framesent"], - predicate: typing.Optional[ - typing.Callable[["typing.Union[bytes, str]"], bool] - ] = None, - *, - timeout: typing.Optional[float] = None, - ) -> AsyncEventContextManager["typing.Union[bytes, str]"]: ... - - @typing.overload - def expect_event( - self, - event: typing.Literal["socketerror"], - predicate: typing.Optional[typing.Callable[["str"], bool]] = None, - *, - timeout: typing.Optional[float] = None, - ) -> AsyncEventContextManager["str"]: ... + Client certificate authentication is only active when at least one client certificate is provided. If you want to + reject all client certificates sent by the server, you need to provide a client certificate with an `origin` that + does not match any of the domains you plan to visit. - @typing.overload - def expect_event( - self, - event: str, - predicate: typing.Optional[typing.Callable[..., bool]] = None, - *, - timeout: typing.Optional[float] = None, - ) -> AsyncEventContextManager[typing.Any]: ... + **NOTE** When using WebKit on macOS, accessing `localhost` will not pick up client certificates. You can make it + work by replacing `localhost` with `local.playwright`. - def expect_event( - self, - event: str, - predicate: typing.Optional[typing.Callable] = None, - *, - timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, - ) -> AsyncEventContextManager: - """WebSocket.expect_event + color_scheme : Union["dark", "light", "no-preference", "null", None] + Emulates [prefers-colors-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) + media feature, supported values are `'light'` and `'dark'`. See `page.emulate_media()` for more details. Passing + `'null'` resets emulation to system defaults. Defaults to `'light'`. + contrast : Union["more", "no-preference", "null", None] + Emulates `'prefers-contrast'` media feature, supported values are `'no-preference'`, `'more'`. See + `page.emulate_media()` for more details. Passing `'null'` resets emulation to system defaults. Defaults to + `'no-preference'`. + device_scale_factor : Union[float, None] + Specify device scale factor (can be thought of as dpr). Defaults to `1`. Learn more about + [emulating devices with device scale factor](../emulation.md#devices). + extra_http_headers : Union[Dict[str, str], None] + An object containing additional HTTP headers to be sent with every request. Defaults to none. + forced_colors : Union["active", "none", "null", None] + Emulates `'forced-colors'` media feature, supported values are `'active'`, `'none'`. See `page.emulate_media()` for + more details. Passing `'null'` resets emulation to system defaults. Defaults to `'none'`. + geolocation : Union[{latitude: float, longitude: float, accuracy: Union[float, None]}, None] + has_touch : Union[bool, None] + Specifies if viewport supports touch events. Defaults to false. Learn more about + [mobile emulation](../emulation.md#devices). + http_credentials : Union[Sequence[{username: str, password: str, origin: Union[str, None], send: Union["always", "unauthorized", None]}], {username: str, password: str, origin: Union[str, None], send: Union["always", "unauthorized", None]}, None] + Credentials for [HTTP authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication). If no + origin is specified, the username and password are sent to any servers upon unauthorized responses. - Waits for event to fire and passes its value into the predicate function. Returns when the predicate returns truthy - value. Will throw an error if the webSocket is closed before the event is fired. Returns the event data value. + Pass an array to use different credentials for different origins. The first entry that matches the request origin + is used, and entries with no origin match any request. + ignore_https_errors : Union[bool, None] + Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + is_mobile : Union[bool, None] + Whether the `meta viewport` tag is taken into account and touch events are enabled. isMobile is a part of device, + so you don't actually need to set it manually. Defaults to `false`. Learn more about + [mobile emulation](../emulation.md#ismobile). + java_script_enabled : Union[bool, None] + Whether or not to enable JavaScript in the context. Defaults to `true`. Learn more about + [disabling JavaScript](../emulation.md#javascript-enabled). + locale : Union[str, None] + Specify user locale, for example `en-GB`, `de-DE`, etc. Locale will affect `navigator.language` value, + `Accept-Language` request header value as well as number and date formatting rules. Defaults to the system default + locale. Learn more about emulation in our [emulation guide](../emulation.md#locale--timezone). + no_viewport : Union[bool, None] + Does not enforce fixed viewport, allows resizing window in the headed mode. + offline : Union[bool, None] + Whether to emulate network being offline. Defaults to `false`. Learn more about + [network emulation](../emulation.md#offline). + permissions : Union[Sequence[str], None] + A list of permissions to grant to all pages in this context. See `browser_context.grant_permissions()` for more + details. Defaults to none. + proxy : Union[{server: str, bypass: Union[str, None], username: Union[str, None], password: Union[str, None]}, None] + Network proxy settings to use with this context. Defaults to none. + record_har_content : Union["attach", "embed", "omit", None] + Optional setting to control resource content management. If `omit` is specified, content is not persisted. If + `attach` is specified, resources are persisted as separate files and all of these files are archived along with the + HAR file. Defaults to `embed`, which stores content inline the HAR file as per HAR specification. + record_har_mode : Union["full", "minimal", None] + When set to `minimal`, only record information necessary for routing from HAR. This omits sizes, timing, page, + cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to `full`. + record_har_omit_content : Union[bool, None] + Optional setting to control whether to omit request content from the HAR. Defaults to `false`. + record_har_path : Union[pathlib.Path, str, None] + Enables [HAR](http://www.softwareishard.com/blog/har-12-spec) recording for all pages into the specified HAR file + on the filesystem. If not specified, the HAR is not recorded. Make sure to call `browser_context.close()` for the + HAR to be saved. + record_har_url_filter : Union[Pattern[str], str, None] + record_video_dir : Union[pathlib.Path, str, None] + Enables video recording for all pages into the specified directory. If not specified videos are not recorded. Make + sure to call `browser_context.close()` for videos to be saved. + record_video_fps : Union[int, None] + Frame rate of the recorded videos in frames per second. Defaults to `25`. Firefox and WebKit currently capture up + to 25 frames per second. + record_video_size : Union[{width: int, height: int}, None] + Dimensions of the recorded videos. If not specified the size will be equal to `viewport` scaled down to fit into + 800x800. If `viewport` is not configured explicitly the video size defaults to 800x450. Actual picture of each page + will be scaled down if necessary to fit the specified size. + reduced_motion : Union["no-preference", "null", "reduce", None] + Emulates `'prefers-reduced-motion'` media feature, supported values are `'reduce'`, `'no-preference'`. See + `page.emulate_media()` for more details. Passing `'null'` resets emulation to system defaults. Defaults to + `'no-preference'`. + screen : Union[{width: int, height: int}, None] + Emulates consistent window screen size available inside web page via `window.screen`. Is only used when the + `viewport` is set. + service_workers : Union["allow", "block", None] + Whether to allow sites to register Service workers. Defaults to `'allow'`. + - `'allow'`: [Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) can be + registered. + - `'block'`: Playwright will block all registration of Service Workers. + storage_state : Union[pathlib.Path, str, {cookies: Sequence[{name: str, value: str, domain: str, path: str, expires: float, httpOnly: bool, secure: bool, sameSite: Union["Lax", "None", "Strict"]}], origins: Sequence[{origin: str, localStorage: Sequence[{name: str, value: str}]}]}, None] + Learn more about [storage state and auth](../auth.md). - Parameters - ---------- - event : str - Event name, same one would pass into `webSocket.on(event)`. - predicate : Union[Callable, None] - Receives the event data and resolves to truthy value when the waiting should resolve. - timeout : Union[float, None] - Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The - default value can be changed by using the `browser_context.set_default_timeout()`. + Populates context with given storage state. This option can be used to initialize context with logged-in + information obtained via `browser_context.storage_state()`. + strict_selectors : Union[bool, None] + If set to true, enables strict selectors mode for this context. In the strict selectors mode all operations on + selectors that imply single target DOM element will throw when more than one element matches the selector. This + option does not affect any Locator APIs (Locators are always strict). Defaults to `false`. See `Locator` to learn + more about the strict mode. + timezone_id : Union[str, None] + Changes the timezone of the context. See + [ICU's metaZones.txt](https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1) + for a list of supported timezone IDs. Defaults to the system timezone. + user_agent : Union[str, None] + Specific user agent to use in this context. + viewport : Union[{width: int, height: int}, None] + Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. `no_viewport` disables the fixed + viewport. Learn more about [viewport emulation](../emulation.md#viewport). Returns ------- - EventContextManager + BrowserContext """ - return AsyncEventContextManager( - self._impl_obj.expect_event( - event=event, - predicate=self._wrap_handler(predicate), - timeout=to_milliseconds(timeout), - ).future + return mapping.from_impl( + await self._impl_obj.new_context( + acceptDownloads=accept_downloads, + baseURL=base_url, + bypassCSP=bypass_csp, + clientCertificates=mapping.to_impl(client_certificates), + colorScheme=color_scheme, + contrast=contrast, + defaultBrowserType=default_browser_type, + deviceScaleFactor=device_scale_factor, + extraHTTPHeaders=mapping.to_impl(extra_http_headers), + forcedColors=forced_colors, + geolocation=geolocation, + hasTouch=has_touch, + httpCredentials=mapping.to_impl(http_credentials), + ignoreHTTPSErrors=ignore_https_errors, + isMobile=is_mobile, + javaScriptEnabled=java_script_enabled, + locale=locale, + noViewport=no_viewport, + offline=offline, + permissions=mapping.to_impl(permissions), + proxy=proxy, + recordHarContent=record_har_content, + recordHarMode=record_har_mode, + recordHarOmitContent=record_har_omit_content, + recordHarPath=record_har_path, + recordHarUrlFilter=record_har_url_filter, + recordVideoDir=record_video_dir, + recordVideoFps=record_video_fps, + recordVideoSize=record_video_size, + reducedMotion=reduced_motion, + screen=screen, + serviceWorkers=service_workers, + storageState=storage_state, + strictSelectors=strict_selectors, + timezoneId=timezone_id, + userAgent=user_agent, + viewport=viewport, + ) ) - @typing.overload - async def wait_for_event( - self, - event: typing.Literal["close"], - predicate: typing.Optional[typing.Callable[["WebSocket"], bool]] = None, - *, - timeout: typing.Optional[float] = None, - ) -> "WebSocket": ... - - @typing.overload - async def wait_for_event( + async def new_page( self, - event: typing.Literal["framereceived"], - predicate: typing.Optional[ - typing.Callable[["typing.Union[bytes, str]"], bool] - ] = None, *, - timeout: typing.Optional[float] = None, - ) -> "typing.Union[bytes, str]": ... - - @typing.overload - async def wait_for_event( - self, - event: typing.Literal["framesent"], - predicate: typing.Optional[ - typing.Callable[["typing.Union[bytes, str]"], bool] + accept_downloads: typing.Optional[bool] = None, + base_url: typing.Optional[str] = None, + bypass_csp: typing.Optional[bool] = None, + client_certificates: typing.Optional[typing.Sequence[ClientCertificate]] = None, + color_scheme: typing.Optional[ + Literal["dark", "light", "no-preference", "null"] ] = None, - *, - timeout: typing.Optional[float] = None, - ) -> "typing.Union[bytes, str]": ... - - @typing.overload - async def wait_for_event( - self, - event: typing.Literal["socketerror"], - predicate: typing.Optional[typing.Callable[["str"], bool]] = None, - *, - timeout: typing.Optional[float] = None, - ) -> "str": ... - - @typing.overload - async def wait_for_event( - self, - event: str, - predicate: typing.Optional[typing.Callable[..., bool]] = None, - *, - timeout: typing.Optional[float] = None, - ) -> typing.Any: ... - - async def wait_for_event( - self, - event: str, - predicate: typing.Optional[typing.Callable] = None, - *, - timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, - ) -> typing.Any: - """WebSocket.wait_for_event + contrast: typing.Optional[Literal["more", "no-preference", "null"]] = None, + default_browser_type: typing.Optional[str] = None, + device_scale_factor: typing.Optional[float] = None, + extra_http_headers: typing.Optional[typing.Dict[str, str]] = None, + forced_colors: typing.Optional[Literal["active", "none", "null"]] = None, + geolocation: typing.Optional[Geolocation] = None, + has_touch: typing.Optional[bool] = None, + http_credentials: typing.Optional[ + typing.Union[HttpCredentials, typing.Sequence[HttpCredentials]] + ] = None, + ignore_https_errors: typing.Optional[bool] = None, + is_mobile: typing.Optional[bool] = None, + java_script_enabled: typing.Optional[bool] = None, + locale: typing.Optional[str] = None, + no_viewport: typing.Optional[bool] = None, + offline: typing.Optional[bool] = None, + permissions: typing.Optional[typing.Sequence[str]] = None, + proxy: typing.Optional[ProxySettings] = None, + record_har_content: typing.Optional[Literal["attach", "embed", "omit"]] = None, + record_har_mode: typing.Optional[Literal["full", "minimal"]] = None, + record_har_omit_content: typing.Optional[bool] = None, + record_har_path: typing.Optional[typing.Union[str, pathlib.Path]] = None, + record_har_url_filter: typing.Optional[ + typing.Union[str, typing.Pattern[str]] + ] = None, + record_video_dir: typing.Optional[typing.Union[str, pathlib.Path]] = None, + record_video_fps: typing.Optional[int] = None, + record_video_size: typing.Optional[ViewportSize] = None, + reduced_motion: typing.Optional[ + Literal["no-preference", "null", "reduce"] + ] = None, + screen: typing.Optional[ViewportSize] = None, + service_workers: typing.Optional[Literal["allow", "block"]] = None, + storage_state: typing.Optional[ + typing.Union[str, pathlib.Path, StorageState] + ] = None, + strict_selectors: typing.Optional[bool] = None, + timezone_id: typing.Optional[str] = None, + user_agent: typing.Optional[str] = None, + viewport: typing.Optional[ViewportSize] = None, + ) -> "Page": + """Browser.new_page - **NOTE** In most cases, you should use `web_socket.expect_event()`. + Creates a new page in a new browser context. Closing this page will close the context as well. - Waits for given `event` to fire. If predicate is provided, it passes event's value into the `predicate` function - and waits for `predicate(event)` to return a truthy value. Will throw an error if the socket is closed before the - `event` is fired. + This is a convenience API that should only be used for the single-page scenarios and short snippets. Production + code and testing frameworks should explicitly create `browser.new_context()` followed by the + `browser_context.new_page()` to control their exact life times. Parameters ---------- - event : str - Event name, same one typically passed into `*.on(event)`. - predicate : Union[Callable, None] - Receives the event data and resolves to truthy value when the waiting should resolve. - timeout : Union[float, None] - Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The - default value can be changed by using the `browser_context.set_default_timeout()`. - - Returns - ------- - Any - """ - - return mapping.from_maybe_impl( - await self._impl_obj.wait_for_event( - event=event, - predicate=self._wrap_handler(predicate), - timeout=to_milliseconds(timeout), - ) - ) - - def is_closed(self) -> bool: - """WebSocket.is_closed - - Indicates that the web socket has been closed. - - Returns - ------- - bool - """ + accept_downloads : Union[bool, None] + Whether to automatically download all the attachments. Defaults to `true` where all the downloads are accepted. + base_url : Union[str, None] + When using `page.goto()`, `page.route()`, `page.wait_for_url()`, `page.expect_request()`, or + `page.expect_response()` it takes the base URL in consideration by using the + [`URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor for building the corresponding URL. + Unset by default. Examples: + - baseURL: `http://localhost:3000` and navigating to `/bar.html` results in `http://localhost:3000/bar.html` + - baseURL: `http://localhost:3000/foo/` and navigating to `./bar.html` results in + `http://localhost:3000/foo/bar.html` + - baseURL: `http://localhost:3000/foo` (without trailing slash) and navigating to `./bar.html` results in + `http://localhost:3000/bar.html` + bypass_csp : Union[bool, None] + Toggles bypassing page's Content-Security-Policy. Defaults to `false`. + client_certificates : Union[Sequence[{origin: str, certPath: Union[pathlib.Path, str, None], cert: Union[bytes, None], keyPath: Union[pathlib.Path, str, None], key: Union[bytes, None], pfxPath: Union[pathlib.Path, str, None], pfx: Union[bytes, None], passphrase: Union[str, None]}], None] + TLS Client Authentication allows the server to request a client certificate and verify it. - return mapping.from_maybe_impl(self._impl_obj.is_closed()) + **Details** + An array of client certificates to be used. Each certificate object must have either both `certPath` and `keyPath`, + a single `pfxPath`, or their corresponding direct value equivalents (`cert` and `key`, or `pfx`). Optionally, + `passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided + with an exact match to the request origin that the certificate is valid for. -mapping.register(WebSocketImpl, WebSocket) + Client certificate authentication is only active when at least one client certificate is provided. If you want to + reject all client certificates sent by the server, you need to provide a client certificate with an `origin` that + does not match any of the domains you plan to visit. + **NOTE** When using WebKit on macOS, accessing `localhost` will not pick up client certificates. You can make it + work by replacing `localhost` with `local.playwright`. -class WebSocketRoute(AsyncBase): - _impl_obj: WebSocketRouteImpl + color_scheme : Union["dark", "light", "no-preference", "null", None] + Emulates [prefers-colors-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) + media feature, supported values are `'light'` and `'dark'`. See `page.emulate_media()` for more details. Passing + `'null'` resets emulation to system defaults. Defaults to `'light'`. + contrast : Union["more", "no-preference", "null", None] + Emulates `'prefers-contrast'` media feature, supported values are `'no-preference'`, `'more'`. See + `page.emulate_media()` for more details. Passing `'null'` resets emulation to system defaults. Defaults to + `'no-preference'`. + device_scale_factor : Union[float, None] + Specify device scale factor (can be thought of as dpr). Defaults to `1`. Learn more about + [emulating devices with device scale factor](../emulation.md#devices). + extra_http_headers : Union[Dict[str, str], None] + An object containing additional HTTP headers to be sent with every request. Defaults to none. + forced_colors : Union["active", "none", "null", None] + Emulates `'forced-colors'` media feature, supported values are `'active'`, `'none'`. See `page.emulate_media()` for + more details. Passing `'null'` resets emulation to system defaults. Defaults to `'none'`. + geolocation : Union[{latitude: float, longitude: float, accuracy: Union[float, None]}, None] + has_touch : Union[bool, None] + Specifies if viewport supports touch events. Defaults to false. Learn more about + [mobile emulation](../emulation.md#devices). + http_credentials : Union[Sequence[{username: str, password: str, origin: Union[str, None], send: Union["always", "unauthorized", None]}], {username: str, password: str, origin: Union[str, None], send: Union["always", "unauthorized", None]}, None] + Credentials for [HTTP authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication). If no + origin is specified, the username and password are sent to any servers upon unauthorized responses. - @property - def url(self) -> str: - """WebSocketRoute.url + Pass an array to use different credentials for different origins. The first entry that matches the request origin + is used, and entries with no origin match any request. + ignore_https_errors : Union[bool, None] + Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + is_mobile : Union[bool, None] + Whether the `meta viewport` tag is taken into account and touch events are enabled. isMobile is a part of device, + so you don't actually need to set it manually. Defaults to `false`. Learn more about + [mobile emulation](../emulation.md#ismobile). + java_script_enabled : Union[bool, None] + Whether or not to enable JavaScript in the context. Defaults to `true`. Learn more about + [disabling JavaScript](../emulation.md#javascript-enabled). + locale : Union[str, None] + Specify user locale, for example `en-GB`, `de-DE`, etc. Locale will affect `navigator.language` value, + `Accept-Language` request header value as well as number and date formatting rules. Defaults to the system default + locale. Learn more about emulation in our [emulation guide](../emulation.md#locale--timezone). + no_viewport : Union[bool, None] + Does not enforce fixed viewport, allows resizing window in the headed mode. + offline : Union[bool, None] + Whether to emulate network being offline. Defaults to `false`. Learn more about + [network emulation](../emulation.md#offline). + permissions : Union[Sequence[str], None] + A list of permissions to grant to all pages in this context. See `browser_context.grant_permissions()` for more + details. Defaults to none. + proxy : Union[{server: str, bypass: Union[str, None], username: Union[str, None], password: Union[str, None]}, None] + Network proxy settings to use with this context. Defaults to none. + record_har_content : Union["attach", "embed", "omit", None] + Optional setting to control resource content management. If `omit` is specified, content is not persisted. If + `attach` is specified, resources are persisted as separate files and all of these files are archived along with the + HAR file. Defaults to `embed`, which stores content inline the HAR file as per HAR specification. + record_har_mode : Union["full", "minimal", None] + When set to `minimal`, only record information necessary for routing from HAR. This omits sizes, timing, page, + cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to `full`. + record_har_omit_content : Union[bool, None] + Optional setting to control whether to omit request content from the HAR. Defaults to `false`. + record_har_path : Union[pathlib.Path, str, None] + Enables [HAR](http://www.softwareishard.com/blog/har-12-spec) recording for all pages into the specified HAR file + on the filesystem. If not specified, the HAR is not recorded. Make sure to call `browser_context.close()` for the + HAR to be saved. + record_har_url_filter : Union[Pattern[str], str, None] + record_video_dir : Union[pathlib.Path, str, None] + Enables video recording for all pages into the specified directory. If not specified videos are not recorded. Make + sure to call `browser_context.close()` for videos to be saved. + record_video_fps : Union[int, None] + Frame rate of the recorded videos in frames per second. Defaults to `25`. Firefox and WebKit currently capture up + to 25 frames per second. + record_video_size : Union[{width: int, height: int}, None] + Dimensions of the recorded videos. If not specified the size will be equal to `viewport` scaled down to fit into + 800x800. If `viewport` is not configured explicitly the video size defaults to 800x450. Actual picture of each page + will be scaled down if necessary to fit the specified size. + reduced_motion : Union["no-preference", "null", "reduce", None] + Emulates `'prefers-reduced-motion'` media feature, supported values are `'reduce'`, `'no-preference'`. See + `page.emulate_media()` for more details. Passing `'null'` resets emulation to system defaults. Defaults to + `'no-preference'`. + screen : Union[{width: int, height: int}, None] + Emulates consistent window screen size available inside web page via `window.screen`. Is only used when the + `viewport` is set. + service_workers : Union["allow", "block", None] + Whether to allow sites to register Service workers. Defaults to `'allow'`. + - `'allow'`: [Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) can be + registered. + - `'block'`: Playwright will block all registration of Service Workers. + storage_state : Union[pathlib.Path, str, {cookies: Sequence[{name: str, value: str, domain: str, path: str, expires: float, httpOnly: bool, secure: bool, sameSite: Union["Lax", "None", "Strict"]}], origins: Sequence[{origin: str, localStorage: Sequence[{name: str, value: str}]}]}, None] + Learn more about [storage state and auth](../auth.md). - URL of the WebSocket created in the page. + Populates context with given storage state. This option can be used to initialize context with logged-in + information obtained via `browser_context.storage_state()`. + strict_selectors : Union[bool, None] + If set to true, enables strict selectors mode for this context. In the strict selectors mode all operations on + selectors that imply single target DOM element will throw when more than one element matches the selector. This + option does not affect any Locator APIs (Locators are always strict). Defaults to `false`. See `Locator` to learn + more about the strict mode. + timezone_id : Union[str, None] + Changes the timezone of the context. See + [ICU's metaZones.txt](https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1) + for a list of supported timezone IDs. Defaults to the system timezone. + user_agent : Union[str, None] + Specific user agent to use in this context. + viewport : Union[{width: int, height: int}, None] + Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. `no_viewport` disables the fixed + viewport. Learn more about [viewport emulation](../emulation.md#viewport). Returns ------- - str + Page """ - return mapping.from_maybe_impl(self._impl_obj.url) - - @property - def protocols(self) -> typing.List[str]: - """WebSocketRoute.protocols - - The list of WebSocket subprotocols requested by the page, as passed via the second argument to the - [`WebSocket` constructor](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket). Corresponds to the - `Sec-WebSocket-Protocol` request header. - - Returns an empty array if no protocols were specified. - - **Usage** - - ```py - async def handler(ws: WebSocketRoute): - if \"chat.v2\" in ws.protocols: - ws.on_message(lambda message: ws.send(f\"v2:{message}\")) - else: - await ws.close(code=1002, reason=\"Unsupported protocol\") - await page.route_web_socket(\"wss://example.com/ws\", handler) - ``` - - Returns - ------- - List[str] - """ - return mapping.from_maybe_impl(self._impl_obj.protocols) + return mapping.from_impl( + await self._impl_obj.new_page( + acceptDownloads=accept_downloads, + baseURL=base_url, + bypassCSP=bypass_csp, + clientCertificates=mapping.to_impl(client_certificates), + colorScheme=color_scheme, + contrast=contrast, + defaultBrowserType=default_browser_type, + deviceScaleFactor=device_scale_factor, + extraHTTPHeaders=mapping.to_impl(extra_http_headers), + forcedColors=forced_colors, + geolocation=geolocation, + hasTouch=has_touch, + httpCredentials=mapping.to_impl(http_credentials), + ignoreHTTPSErrors=ignore_https_errors, + isMobile=is_mobile, + javaScriptEnabled=java_script_enabled, + locale=locale, + noViewport=no_viewport, + offline=offline, + permissions=mapping.to_impl(permissions), + proxy=proxy, + recordHarContent=record_har_content, + recordHarMode=record_har_mode, + recordHarOmitContent=record_har_omit_content, + recordHarPath=record_har_path, + recordHarUrlFilter=record_har_url_filter, + recordVideoDir=record_video_dir, + recordVideoFps=record_video_fps, + recordVideoSize=record_video_size, + reducedMotion=reduced_motion, + screen=screen, + serviceWorkers=service_workers, + storageState=storage_state, + strictSelectors=strict_selectors, + timezoneId=timezone_id, + userAgent=user_agent, + viewport=viewport, + ) + ) - async def close( - self, *, code: typing.Optional[int] = None, reason: typing.Optional[str] = None + @typing.overload + def on( + self, + event: Literal["context"], + f: typing.Callable[ + ["BrowserContext"], "typing.Union[typing.Awaitable[None], None]" + ], ) -> None: - """WebSocketRoute.close - - Closes one side of the WebSocket connection. - - Parameters - ---------- - code : Union[int, None] - Optional [close code](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#code). - reason : Union[str, None] - Optional [close reason](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#reason). """ + Emitted when a new browser context is created.""" - await self._impl_obj.close(code=code, reason=reason) - - def connect_to_server(self) -> "WebSocketRoute": - """WebSocketRoute.connect_to_server - - By default, routed WebSocket does not connect to the server, so you can mock entire WebSocket communication. This - method connects to the actual WebSocket server, and returns the server-side `WebSocketRoute` instance, giving the - ability to send and receive messages from the server. - - Once connected to the server: - - Messages received from the server will be **automatically forwarded** to the WebSocket in the page, unless - `web_socket_route.on_message()` is called on the server-side `WebSocketRoute`. - - Messages sent by the [`WebSocket.send()`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send) call - in the page will be **automatically forwarded** to the server, unless `web_socket_route.on_message()` is - called on the original `WebSocketRoute`. - - See examples at the top for more details. - - Returns - ------- - WebSocketRoute + @typing.overload + def on( + self, + event: Literal["disconnected"], + f: typing.Callable[["Browser"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: """ + Emitted when Browser gets disconnected from the browser application. This might happen because of one of the + following: + - Browser application is closed or crashed. + - The `browser.close()` method was called.""" - return mapping.from_impl(self._impl_obj.connect_to_server()) - - def send(self, message: typing.Union[str, bytes]) -> None: - """WebSocketRoute.send + def on( + self, + event: str, + f: typing.Callable[..., typing.Union[typing.Awaitable[None], None]], + ) -> None: + return super().on(event=event, f=f) - Sends a message to the WebSocket. When called on the original WebSocket, sends the message to the page. When called - on the result of `web_socket_route.connect_to_server()`, sends the message to the server. See examples at the - top for more details. + @typing.overload + def once( + self, + event: Literal["context"], + f: typing.Callable[ + ["BrowserContext"], "typing.Union[typing.Awaitable[None], None]" + ], + ) -> None: + """ + Emitted when a new browser context is created.""" - Parameters - ---------- - message : Union[bytes, str] - Message to send. + @typing.overload + def once( + self, + event: Literal["disconnected"], + f: typing.Callable[["Browser"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: """ + Emitted when Browser gets disconnected from the browser application. This might happen because of one of the + following: + - Browser application is closed or crashed. + - The `browser.close()` method was called.""" - self._impl_obj.send(message=message) + def once( + self, + event: str, + f: typing.Callable[..., typing.Union[typing.Awaitable[None], None]], + ) -> None: + return super().once(event=event, f=f) - def on_message( - self, handler: typing.Callable[[typing.Union[str, bytes]], typing.Any] + async def start_tracing( + self, + *, + categories: typing.Optional[typing.Sequence[str]] = None, + page: typing.Optional["Page"] = None, + path: typing.Optional[typing.Union[str, pathlib.Path]] = None, + screenshots: typing.Optional[bool] = None, ) -> None: - """WebSocketRoute.on_message + """Browser.start_tracing - This method allows to handle messages that are sent by the WebSocket, either from the page or from the server. + **NOTE** This API controls + [Chromium Tracing](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool) which is a low-level + chromium-specific debugging tool. API to control [Playwright Tracing](https://playwright.dev/python/docs/trace-viewer) could be found + [here](https://playwright.dev/python/docs/api/class-tracing). - When called on the original WebSocket route, this method handles messages sent from the page. You can handle this - messages by responding to them with `web_socket_route.send()`, forwarding them to the server-side connection - returned by `web_socket_route.connect_to_server()` or do something else. + You can use `browser.start_tracing()` and `browser.stop_tracing()` to create a trace file that can be opened in + Chrome DevTools performance panel. - Once this method is called, messages are not automatically forwarded to the server or to the page - you should do - that manually by calling `web_socket_route.send()`. See examples at the top for more details. + **Usage** - Calling this method again will override the handler with a new one. + ```py + await browser.start_tracing(page, path=\"trace.json\") + await page.goto(\"https://www.google.com\") + await browser.stop_tracing() + ``` Parameters ---------- - handler : Callable[[Union[bytes, str]], Any] - Function that will handle messages. + categories : Union[Sequence[str], None] + specify custom categories to use instead of default. + page : Union[Page, None] + Optional, if specified, tracing includes screenshots of the given page. + path : Union[pathlib.Path, str, None] + A path to write the trace file to. + screenshots : Union[bool, None] + captures screenshots in the trace. """ - self._impl_obj.on_message(handler=self._wrap_handler(handler)) + await self._impl_obj.start_tracing( + categories=mapping.to_impl(categories), + page=page._impl_obj if page else None, + path=path, + screenshots=screenshots, + ) - def on_close( - self, - handler: typing.Callable[ - [typing.Optional[int], typing.Optional[str]], typing.Any - ], - ) -> None: - """WebSocketRoute.on_close + async def stop_tracing(self) -> bytes: + """Browser.stop_tracing - Allows to handle [`WebSocket.close`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close). + **NOTE** This API controls + [Chromium Tracing](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool) which is a low-level + chromium-specific debugging tool. API to control [Playwright Tracing](https://playwright.dev/python/docs/trace-viewer) could be found + [here](https://playwright.dev/python/docs/api/class-tracing). - By default, closing one side of the connection, either in the page or on the server, will close the other side. - However, when `web_socket_route.on_close()` handler is set up, the default forwarding of closure is disabled, - and handler should take care of it. + Returns the buffer with trace data. - Parameters - ---------- - handler : Callable[[Union[int, None], Union[str, None]], Any] - Function that will handle WebSocket closure. Received an optional - [close code](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#code) and an optional - [close reason](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#reason). + Returns + ------- + bytes """ - self._impl_obj.on_close(handler=self._wrap_handler(handler)) + return mapping.from_maybe_impl(await self._impl_obj.stop_tracing()) + async def unbind(self) -> None: + """Browser.unbind -mapping.register(WebSocketRouteImpl, WebSocketRoute) + Unbinds the browser server previously bound with `browser.bind()`. + """ + await self._impl_obj.unbind() -class Keyboard(AsyncBase): - _impl_obj: KeyboardImpl + @property + def version(self) -> str: + """Browser.version - async def down(self, key: str) -> None: - """Keyboard.down + Returns the browser version. - Dispatches a `keydown` event. + Returns + ------- + str + """ + return mapping.from_maybe_impl(self._impl_obj.version) - `key` can specify the intended - [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character - to generate the text for. A superset of the `key` values can be found - [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Examples of the keys are: - `F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`, - `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrowRight`, `ArrowUp`, - etc. +mapping.register(BrowserImpl, Browser) - Following modification shortcuts are also supported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`, - `ControlOrMeta`. `ControlOrMeta` resolves to `Control` on Windows and Linux and to `Meta` on macOS. - Holding down `Shift` will type the text that corresponds to the `key` in the upper case. +class BrowserContext(AsyncContextManager): + _impl_obj: BrowserContextImpl - If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different respective - texts. + async def add_cookies(self, cookies: typing.Sequence[SetCookieParam]) -> None: + """BrowserContext.add_cookies - If `key` is a modifier key, `Shift`, `Meta`, `Control`, or `Alt`, subsequent key presses will be sent with that - modifier active. To release the modifier key, use `keyboard.up()`. + Adds cookies into this browser context. All pages within this context will have these cookies installed. Cookies + can be obtained via `browser_context.cookies()`. - After the key is pressed once, subsequent calls to `keyboard.down()` will have - [repeat](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat) set to true. To release the key, - use `keyboard.up()`. + **Usage** - **NOTE** Modifier keys DO influence `keyboard.down`. Holding down `Shift` will type the text in upper case. + ```py + await browser_context.add_cookies([cookie_object1, cookie_object2]) + ``` Parameters ---------- - key : str - Name of the key to press or a character to generate, such as `ArrowLeft` or `a`. + cookies : Sequence[{name: str, value: str, url: Union[str, None], domain: Union[str, None], path: Union[str, None], expires: Union[float, None], httpOnly: Union[bool, None], secure: Union[bool, None], sameSite: Union["Lax", "None", "Strict", None], partitionKey: Union[str, None]}] """ - await self._impl_obj.down(key=key) - - async def up(self, key: str) -> None: - """Keyboard.up - - Dispatches a `keyup` event. - - Parameters - ---------- - key : str - Name of the key to press or a character to generate, such as `ArrowLeft` or `a`. - """ + await self._impl_obj.add_cookies(cookies=mapping.to_impl(cookies)) - await self._impl_obj.up(key=key) + async def add_init_script( + self, + script: typing.Optional[str] = None, + *, + path: typing.Optional[typing.Union[str, pathlib.Path]] = None, + ) -> "AsyncContextManager": + """BrowserContext.add_init_script - async def insert_text(self, text: str) -> None: - """Keyboard.insert_text + Adds a script which would be evaluated in one of the following scenarios: + - Whenever a page is created in the browser context or is navigated. + - Whenever a child frame is attached or navigated in any page in the browser context. In this case, the script is + evaluated in the context of the newly attached frame. - Dispatches only `input` event, does not emit the `keydown`, `keyup` or `keypress` events. + The script is evaluated after the document was created but before any of its scripts were run. This is useful to + amend the JavaScript environment, e.g. to seed `Math.random`. **Usage** + An example of overriding `Math.random` before the page loads: + ```py - await page.keyboard.insert_text(\"嗨\") + # in your playwright script, assuming the preload.js file is in same directory. + await browser_context.add_init_script(path=\"preload.js\") ``` - **NOTE** Modifier keys DO NOT effect `keyboard.insertText`. Holding down `Shift` will not type the text in upper - case. + **NOTE** The order of evaluation of multiple scripts installed via `browser_context.add_init_script()` and + `page.add_init_script()` is not defined. Parameters ---------- - text : str - Sets input to the specified text value. + script : Union[str, None] + Script to be evaluated in all pages in the browser context. Optional. + path : Union[pathlib.Path, str, None] + Path to the JavaScript file. If `path` is a relative path, then it is resolved relative to the current working + directory. Optional. + + Returns + ------- + AsyncContextManager """ - await self._impl_obj.insert_text(text=text) + return mapping.from_impl( + await self._impl_obj.add_init_script(script=script, path=path) + ) - async def type(self, text: str, *, delay: typing.Optional[float] = None) -> None: - """Keyboard.type + @property + def background_pages(self) -> typing.List["Page"]: + """BrowserContext.background_pages - **NOTE** In most cases, you should use `locator.fill()` instead. You only need to press keys one by one if - there is special keyboard handling on the page - in this case use `locator.press_sequentially()`. + Returns an empty list. - Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text. + Returns + ------- + List[Page] + """ + return mapping.from_impl_list(self._impl_obj.background_pages) - To press a special key, like `Control` or `ArrowDown`, use `keyboard.press()`. + @property + def browser(self) -> typing.Optional["Browser"]: + """BrowserContext.browser + + Gets the browser instance that owns the context. Returns `null` if the context is created outside of normal + browser, e.g. Android or Electron. + + Returns + ------- + Union[Browser, None] + """ + return mapping.from_impl_nullable(self._impl_obj.browser) + + async def clear_cookies( + self, + *, + domain: typing.Optional[typing.Union[str, typing.Pattern[str]]] = None, + name: typing.Optional[typing.Union[str, typing.Pattern[str]]] = None, + path: typing.Optional[typing.Union[str, typing.Pattern[str]]] = None, + ) -> None: + """BrowserContext.clear_cookies + + Removes cookies from context. Accepts optional filter. **Usage** ```py - await page.keyboard.type(\"Hello\") # types instantly - await page.keyboard.type(\"World\", delay=100) # types slower, like a user + await context.clear_cookies() + await context.clear_cookies(name=\"session-id\") + await context.clear_cookies(domain=\"my-origin.com\") + await context.clear_cookies(path=\"/api/v1\") + await context.clear_cookies(name=\"session-id\", domain=\"my-origin.com\") ``` - **NOTE** Modifier keys DO NOT effect `keyboard.type`. Holding down `Shift` will not type the text in upper case. - - **NOTE** For characters that are not on a US keyboard, only an `input` event will be sent. - Parameters ---------- - text : str - A text to type into a focused element. - delay : Union[float, None] - Time to wait between key presses in milliseconds. Defaults to 0. + domain : Union[Pattern[str], str, None] + Only removes cookies with the given domain. + name : Union[Pattern[str], str, None] + Only removes cookies with the given name. + path : Union[Pattern[str], str, None] + Only removes cookies with the given path. """ - await self._impl_obj.type(text=text, delay=delay) - - async def press(self, key: str, *, delay: typing.Optional[float] = None) -> None: - """Keyboard.press - - **NOTE** In most cases, you should use `locator.press()` instead. - - `key` can specify the intended - [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character - to generate the text for. A superset of the `key` values can be found - [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Examples of the keys are: - - `F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`, - `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrowRight`, `ArrowUp`, - etc. - - Following modification shortcuts are also supported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`, - `ControlOrMeta`. `ControlOrMeta` resolves to `Control` on Windows and Linux and to `Meta` on macOS. - - Holding down `Shift` will type the text that corresponds to the `key` in the upper case. + await self._impl_obj.clear_cookies(domain=domain, name=name, path=path) - If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different respective - texts. + async def clear_permissions(self) -> None: + """BrowserContext.clear_permissions - Shortcuts such as `key: \"Control+o\"`, `key: \"Control++` or `key: \"Control+Shift+T\"` are supported as well. When - specified with the modifier, modifier is pressed and being held while the subsequent key is being pressed. + Clears all permission overrides for the browser context. **Usage** ```py - page = await browser.new_page() - await page.goto(\"https://keycode.info\") - await page.keyboard.press(\"a\") - await page.screenshot(path=\"a.png\") - await page.keyboard.press(\"ArrowLeft\") - await page.screenshot(path=\"arrow_left.png\") - await page.keyboard.press(\"Shift+O\") - await page.screenshot(path=\"o.png\") - await browser.close() + context = await browser.new_context() + await context.grant_permissions([\"clipboard-read\"]) + # do stuff .. + context.clear_permissions() ``` - - Shortcut for `keyboard.down()` and `keyboard.up()`. - - Parameters - ---------- - key : str - Name of the key to press or a character to generate, such as `ArrowLeft` or `a`. - delay : Union[float, None] - Time to wait between `keydown` and `keyup` in milliseconds. Defaults to 0. """ - await self._impl_obj.press(key=key, delay=delay) + await self._impl_obj.clear_permissions() + @property + def clock(self) -> "Clock": + """BrowserContext.clock -mapping.register(KeyboardImpl, Keyboard) + Playwright has ability to mock clock and passage of time. + Returns + ------- + Clock + """ + return mapping.from_impl(self._impl_obj.clock) -class Mouse(AsyncBase): - _impl_obj: MouseImpl + async def close(self, *, reason: typing.Optional[str] = None) -> None: + """BrowserContext.close - async def move( - self, x: float, y: float, *, steps: typing.Optional[int] = None - ) -> None: - """Mouse.move + Closes the browser context. All the pages that belong to the browser context will be closed. - Dispatches a `mousemove` event. + **NOTE** The default browser context cannot be closed. Parameters ---------- - x : float - X coordinate relative to the main frame's viewport in CSS pixels. - y : float - Y coordinate relative to the main frame's viewport in CSS pixels. - steps : Union[int, None] - Defaults to 1. Sends `n` interpolated `mousemove` events to represent travel between Playwright's current cursor - position and the provided destination. When set to 1, emits a single `mousemove` event at the destination location. + reason : Union[str, None] + The reason to be reported to the operations interrupted by the context closure. """ - await self._impl_obj.move(x=x, y=y, steps=steps) + await self._impl_obj.close(reason=reason) - async def down( - self, - *, - button: typing.Optional[Literal["left", "middle", "right"]] = None, - click_count: typing.Optional[int] = None, - ) -> None: - """Mouse.down + async def cookies( + self, urls: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None + ) -> typing.List[Cookie]: + """BrowserContext.cookies - Dispatches a `mousedown` event. + If no URLs are specified, this method returns all cookies. If URLs are specified, only cookies that affect those + URLs are returned. Parameters ---------- - button : Union["left", "middle", "right", None] - Defaults to `left`. - click_count : Union[int, None] - defaults to 1. See [UIEvent.detail]. + urls : Union[Sequence[str], str, None] + Optional list of URLs. + + Returns + ------- + List[{name: str, value: str, domain: str, path: str, expires: float, httpOnly: bool, secure: bool, sameSite: Union["Lax", "None", "Strict"], partitionKey: Union[str, None]}] """ - await self._impl_obj.down(button=button, clickCount=click_count) + return mapping.from_impl_list( + await self._impl_obj.cookies(urls=mapping.to_impl(urls)) + ) - async def up( - self, - *, - button: typing.Optional[Literal["left", "middle", "right"]] = None, - click_count: typing.Optional[int] = None, - ) -> None: - """Mouse.up + @property + def credentials(self) -> "Credentials": + """BrowserContext.credentials - Dispatches a `mouseup` event. + Virtual WebAuthn authenticator for this context. Lets tests seed credentials and intercept + `navigator.credentials.create()` / `navigator.credentials.get()` ceremonies. - Parameters - ---------- - button : Union["left", "middle", "right", None] - Defaults to `left`. - click_count : Union[int, None] - defaults to 1. See [UIEvent.detail]. + Returns + ------- + Credentials """ + return mapping.from_impl(self._impl_obj.credentials) - await self._impl_obj.up(button=button, clickCount=click_count) + @property + def debugger(self) -> "Debugger": + """BrowserContext.debugger - async def click( - self, - x: float, - y: float, - *, - delay: typing.Optional[float] = None, - button: typing.Optional[Literal["left", "middle", "right"]] = None, - click_count: typing.Optional[int] = None, - ) -> None: - """Mouse.click - - Shortcut for `mouse.move()`, `mouse.down()`, `mouse.up()`. + Debugger allows to pause and resume the execution. - Parameters - ---------- - x : float - X coordinate relative to the main frame's viewport in CSS pixels. - y : float - Y coordinate relative to the main frame's viewport in CSS pixels. - delay : Union[float, None] - Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0. - button : Union["left", "middle", "right", None] - Defaults to `left`. - click_count : Union[int, None] - defaults to 1. See [UIEvent.detail]. + Returns + ------- + Debugger """ + return mapping.from_impl(self._impl_obj.debugger) - await self._impl_obj.click( - x=x, y=y, delay=delay, button=button, clickCount=click_count - ) - - async def dblclick( + def expect_console_message( self, - x: float, - y: float, + predicate: typing.Optional[typing.Callable[["ConsoleMessage"], bool]] = None, *, - delay: typing.Optional[float] = None, - button: typing.Optional[Literal["left", "middle", "right"]] = None, - ) -> None: - """Mouse.dblclick + timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, + ) -> AsyncEventContextManager["ConsoleMessage"]: + """BrowserContext.expect_console_message - Shortcut for `mouse.move()`, `mouse.down()`, `mouse.up()`, `mouse.down()` and - `mouse.up()`. + Performs action and waits for a `ConsoleMessage` to be logged by in the pages in the context. If predicate is + provided, it passes `ConsoleMessage` value into the `predicate` function and waits for `predicate(message)` to + return a truthy value. Will throw an error if the page is closed before the `browser_context.on('console')` event + is fired. Parameters ---------- - x : float - X coordinate relative to the main frame's viewport in CSS pixels. - y : float - Y coordinate relative to the main frame's viewport in CSS pixels. - delay : Union[float, None] - Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0. - button : Union["left", "middle", "right", None] - Defaults to `left`. - """ - - await self._impl_obj.dblclick(x=x, y=y, delay=delay, button=button) - - async def wheel(self, delta_x: float, delta_y: float) -> None: - """Mouse.wheel - - Dispatches a `wheel` event. This method is usually used to manually scroll the page. See - [scrolling](https://playwright.dev/python/docs/input#scrolling) for alternative ways to scroll. - - **NOTE** Wheel events may cause scrolling if they are not handled, and this method does not wait for the scrolling - to finish before returning. + predicate : Union[Callable[[ConsoleMessage], bool], None] + Receives the `ConsoleMessage` object and resolves to truthy value when the waiting should resolve. + timeout : Union[float, None] + Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + default value can be changed by using the `browser_context.set_default_timeout()`. - Parameters - ---------- - delta_x : float - Pixels to scroll horizontally. - delta_y : float - Pixels to scroll vertically. + Returns + ------- + EventContextManager[ConsoleMessage] """ - await self._impl_obj.wheel(deltaX=delta_x, deltaY=delta_y) - + return AsyncEventContextManager( + self._impl_obj.expect_console_message( + predicate=self._wrap_handler(predicate), + timeout=to_milliseconds(timeout), + ).future + ) -mapping.register(MouseImpl, Mouse) + @typing.overload + def expect_event( + self, + event: typing.Literal["backgroundpage"], + predicate: typing.Optional[typing.Callable[["Page"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["Page"]: ... + @typing.overload + def expect_event( + self, + event: typing.Literal["close"], + predicate: typing.Optional[typing.Callable[["BrowserContext"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["BrowserContext"]: ... -class Touchscreen(AsyncBase): - _impl_obj: TouchscreenImpl + @typing.overload + def expect_event( + self, + event: typing.Literal["console"], + predicate: typing.Optional[typing.Callable[["ConsoleMessage"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["ConsoleMessage"]: ... - async def tap(self, x: float, y: float) -> None: - """Touchscreen.tap + @typing.overload + def expect_event( + self, + event: typing.Literal["dialog"], + predicate: typing.Optional[typing.Callable[["Dialog"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["Dialog"]: ... - Dispatches a `touchstart` and `touchend` event with a single touch at the position (`x`,`y`). + @typing.overload + def expect_event( + self, + event: typing.Literal["dialogclosed"], + predicate: typing.Optional[typing.Callable[["Dialog"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["Dialog"]: ... - **NOTE** `touchscreen.tap()` will throw if the `has_touch` option of the browser context is false. + @typing.overload + def expect_event( + self, + event: typing.Literal["download"], + predicate: typing.Optional[typing.Callable[["Download"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["Download"]: ... - Parameters - ---------- - x : float - X coordinate relative to the main frame's viewport in CSS pixels. - y : float - Y coordinate relative to the main frame's viewport in CSS pixels. - """ + @typing.overload + def expect_event( + self, + event: typing.Literal["frameattached"], + predicate: typing.Optional[typing.Callable[["Frame"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["Frame"]: ... - await self._impl_obj.tap(x=x, y=y) + @typing.overload + def expect_event( + self, + event: typing.Literal["framedetached"], + predicate: typing.Optional[typing.Callable[["Frame"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["Frame"]: ... + @typing.overload + def expect_event( + self, + event: typing.Literal["framenavigated"], + predicate: typing.Optional[typing.Callable[["Frame"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["Frame"]: ... -mapping.register(TouchscreenImpl, Touchscreen) + @typing.overload + def expect_event( + self, + event: typing.Literal["page"], + predicate: typing.Optional[typing.Callable[["Page"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["Page"]: ... + @typing.overload + def expect_event( + self, + event: typing.Literal["pageclose"], + predicate: typing.Optional[typing.Callable[["Page"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["Page"]: ... -class JSHandle(AsyncBase): - _impl_obj: JSHandleImpl + @typing.overload + def expect_event( + self, + event: typing.Literal["pageload"], + predicate: typing.Optional[typing.Callable[["Page"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["Page"]: ... - async def evaluate( - self, expression: str, arg: typing.Optional[typing.Any] = None - ) -> typing.Any: - """JSHandle.evaluate + @typing.overload + def expect_event( + self, + event: typing.Literal["request"], + predicate: typing.Optional[typing.Callable[["Request"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["Request"]: ... - Returns the return value of `expression`. + @typing.overload + def expect_event( + self, + event: typing.Literal["requestfailed"], + predicate: typing.Optional[typing.Callable[["Request"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["Request"]: ... - This method passes this handle as the first argument to `expression`. + @typing.overload + def expect_event( + self, + event: typing.Literal["requestfinished"], + predicate: typing.Optional[typing.Callable[["Request"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["Request"]: ... - If `expression` returns a [Promise], then `handle.evaluate` would wait for the promise to resolve and return its - value. + @typing.overload + def expect_event( + self, + event: typing.Literal["response"], + predicate: typing.Optional[typing.Callable[["Response"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["Response"]: ... - **Usage** + @typing.overload + def expect_event( + self, + event: typing.Literal["serviceworker"], + predicate: typing.Optional[typing.Callable[["Worker"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["Worker"]: ... - ```py - tweet_handle = await page.query_selector(\".tweet .retweets\") - assert await tweet_handle.evaluate(\"node => node.innerText\") == \"10 retweets\" - ``` + @typing.overload + def expect_event( + self, + event: typing.Literal["weberror"], + predicate: typing.Optional[typing.Callable[["WebError"], bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager["WebError"]: ... - Parameters - ---------- - expression : str - JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the - function is automatically invoked. - arg : Union[Any, None] - Optional argument to pass to `expression`. - - Returns - ------- - Any - """ - - return mapping.from_maybe_impl( - await self._impl_obj.evaluate( - expression=expression, arg=mapping.to_impl(arg) - ) - ) - - async def evaluate_handle( - self, expression: str, arg: typing.Optional[typing.Any] = None - ) -> "JSHandle": - """JSHandle.evaluate_handle - - Returns the return value of `expression` as a `JSHandle`. + @typing.overload + def expect_event( + self, + event: str, + predicate: typing.Optional[typing.Callable[..., bool]] = None, + *, + timeout: typing.Optional[float] = None, + ) -> AsyncEventContextManager[typing.Any]: ... - This method passes this handle as the first argument to `expression`. + def expect_event( + self, + event: str, + predicate: typing.Optional[typing.Callable] = None, + *, + timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, + ) -> AsyncEventContextManager: + """BrowserContext.expect_event - The only difference between `jsHandle.evaluate` and `jsHandle.evaluateHandle` is that `jsHandle.evaluateHandle` - returns `JSHandle`. + Waits for event to fire and passes its value into the predicate function. Returns when the predicate returns truthy + value. Will throw an error if the context closes before the event is fired. Returns the event data value. - If the function passed to the `jsHandle.evaluateHandle` returns a [Promise], then `jsHandle.evaluateHandle` would - wait for the promise to resolve and return its value. + **Usage** - See `page.evaluate_handle()` for more details. + ```py + async with context.expect_event(\"page\") as event_info: + await page.get_by_role(\"button\").click() + page = await event_info.value + ``` Parameters ---------- - expression : str - JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the - function is automatically invoked. - arg : Union[Any, None] - Optional argument to pass to `expression`. + event : str + Event name, same one would pass into `browserContext.on(event)`. + predicate : Union[Callable, None] + Receives the event data and resolves to truthy value when the waiting should resolve. + timeout : Union[float, None] + Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + default value can be changed by using the `browser_context.set_default_timeout()`. Returns ------- - JSHandle + EventContextManager """ - return mapping.from_impl( - await self._impl_obj.evaluate_handle( - expression=expression, arg=mapping.to_impl(arg) - ) + return AsyncEventContextManager( + self._impl_obj.expect_event( + event=event, + predicate=self._wrap_handler(predicate), + timeout=to_milliseconds(timeout), + ).future ) - async def get_property(self, property_name: str) -> "JSHandle": - """JSHandle.get_property + def expect_page( + self, + predicate: typing.Optional[typing.Callable[["Page"], bool]] = None, + *, + timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, + ) -> AsyncEventContextManager["Page"]: + """BrowserContext.expect_page - Fetches a single property from the referenced object. + Performs action and waits for a new `Page` to be created in the context. If predicate is provided, it passes `Page` + value into the `predicate` function and waits for `predicate(event)` to return a truthy value. Will throw an error + if the context closes before new `Page` is created. Parameters ---------- - property_name : str - property to get + predicate : Union[Callable[[Page], bool], None] + Receives the `Page` object and resolves to truthy value when the waiting should resolve. + timeout : Union[float, None] + Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + default value can be changed by using the `browser_context.set_default_timeout()`. Returns ------- - JSHandle + EventContextManager[Page] """ - return mapping.from_impl( - await self._impl_obj.get_property(propertyName=property_name) + return AsyncEventContextManager( + self._impl_obj.expect_page( + predicate=self._wrap_handler(predicate), + timeout=to_milliseconds(timeout), + ).future ) - async def get_properties(self) -> typing.Dict[str, "JSHandle"]: - """JSHandle.get_properties + async def expose_binding( + self, name: str, callback: typing.Callable + ) -> "AsyncContextManager": + """BrowserContext.expose_binding - The method returns a map with **own property names** as keys and JSHandle instances for the property values. + The method adds a function called `name` on the `window` object of every frame in every page in the context. When + called, the function executes `callback` and returns a [Promise] which resolves to the return value of `callback`. + If the `callback` returns a [Promise], it will be awaited. + + The first argument of the `callback` function contains information about the caller: `{ browserContext: + BrowserContext, page: Page, frame: Frame }`. + + See `page.expose_binding()` for page-only version. **Usage** + An example of exposing page URL to all frames in all pages in the context: + ```py - handle = await page.evaluate_handle(\"({ window, document })\") - properties = await handle.get_properties() - window_handle = properties.get(\"window\") - document_handle = properties.get(\"document\") - await handle.dispose() + import asyncio + from playwright.async_api import async_playwright, Playwright + + async def run(playwright: Playwright): + webkit = playwright.webkit + browser = await webkit.launch(headless=False) + context = await browser.new_context() + await context.expose_binding(\"pageURL\", lambda source: source[\"page\"].url) + page = await context.new_page() + await page.set_content(\"\"\" + + +
+ \"\"\") + await page.get_by_role(\"button\").click() + + async def main(): + async with async_playwright() as playwright: + await run(playwright) + asyncio.run(main()) ``` + Parameters + ---------- + name : str + Name of the function on the window object. + callback : Callable + Callback function that will be called in the Playwright's context. + Returns ------- - Dict[str, JSHandle] + AsyncContextManager """ - return mapping.from_impl_dict(await self._impl_obj.get_properties()) + return mapping.from_impl( + await self._impl_obj.expose_binding( + name=name, callback=self._wrap_handler(callback) + ) + ) - def as_element(self) -> typing.Optional["ElementHandle"]: - """JSHandle.as_element + async def expose_function( + self, name: str, callback: typing.Callable + ) -> "AsyncContextManager": + """BrowserContext.expose_function - Returns either `null` or the object handle itself, if the object handle is an instance of `ElementHandle`. + The method adds a function called `name` on the `window` object of every frame in every page in the context. When + called, the function executes `callback` and returns a [Promise] which resolves to the return value of `callback`. - Returns - ------- - Union[ElementHandle, None] - """ + If the `callback` returns a [Promise], it will be awaited. - return mapping.from_impl_nullable(self._impl_obj.as_element()) + See `page.expose_function()` for page-only version. - async def dispose(self) -> None: - """JSHandle.dispose + **Usage** - The `jsHandle.dispose` method stops referencing the element handle. - """ + An example of adding a `sha256` function to all pages in the context: - await self._impl_obj.dispose() + ```py + import asyncio + import hashlib + from playwright.async_api import async_playwright, Playwright - async def json_value(self) -> typing.Any: - """JSHandle.json_value + def sha256(text: str) -> str: + m = hashlib.sha256() + m.update(bytes(text, \"utf8\")) + return m.hexdigest() - Returns a JSON representation of the object. If the object has a `toJSON` function, it **will not be called**. + async def run(playwright: Playwright): + webkit = playwright.webkit + browser = await webkit.launch(headless=False) + context = await browser.new_context() + await context.expose_function(\"sha256\", sha256) + page = await context.new_page() + await page.set_content(\"\"\" + + +
+ \"\"\") + await page.get_by_role(\"button\").click() - **NOTE** The method will return an empty JSON object if the referenced object is not stringifiable. It will throw - an error if the object has circular references. + async def main(): + async with async_playwright() as playwright: + await run(playwright) + asyncio.run(main()) + ``` + + Parameters + ---------- + name : str + Name of the function on the window object. + callback : Callable + Callback function that will be called in the Playwright's context. Returns ------- - Any + AsyncContextManager """ - return mapping.from_maybe_impl(await self._impl_obj.json_value()) + return mapping.from_impl( + await self._impl_obj.expose_function( + name=name, callback=self._wrap_handler(callback) + ) + ) + async def grant_permissions( + self, permissions: typing.Sequence[str], *, origin: typing.Optional[str] = None + ) -> None: + """BrowserContext.grant_permissions -mapping.register(JSHandleImpl, JSHandle) + Grants specified permissions to the browser context. Only grants corresponding permissions to the given origin if + specified. + Parameters + ---------- + permissions : Sequence[str] + A list of permissions to grant. -class ElementHandle(JSHandle): - _impl_obj: ElementHandleImpl + **NOTE** Supported permissions differ between browsers, and even between different versions of the same browser. + Any permission may stop working after an update. - async def owner_frame(self) -> typing.Optional["Frame"]: - """ElementHandle.owner_frame - - Returns the frame containing the given element. - - Returns - ------- - Union[Frame, None] + Here are some permissions that may be supported by some browsers: + - `'accelerometer'` + - `'ambient-light-sensor'` + - `'background-sync'` + - `'camera'` + - `'clipboard-read'` + - `'clipboard-write'` + - `'geolocation'` + - `'gyroscope'` + - `'local-fonts'` + - `'local-network-access'` + - `'magnetometer'` + - `'microphone'` + - `'midi-sysex'` (system-exclusive midi) + - `'midi'` + - `'notifications'` + - `'payment-handler'` + - `'storage-access'` + - `'screen-wake-lock'` + origin : Union[str, None] + The [origin] to grant permissions to, e.g. "https://example.com". """ - return mapping.from_impl_nullable(await self._impl_obj.owner_frame()) + await self._impl_obj.grant_permissions( + permissions=mapping.to_impl(permissions), origin=origin + ) - async def content_frame(self) -> typing.Optional["Frame"]: - """ElementHandle.content_frame + def is_closed(self) -> bool: + """BrowserContext.is_closed - Returns the content frame for element handles referencing iframe nodes, or `null` otherwise + Indicates that the browser context is in the process of closing or has already been closed. Returns ------- - Union[Frame, None] + bool """ - return mapping.from_impl_nullable(await self._impl_obj.content_frame()) + return mapping.from_maybe_impl(self._impl_obj.is_closed()) - async def get_attribute(self, name: str) -> typing.Optional[str]: - """ElementHandle.get_attribute + async def new_cdp_session( + self, page: typing.Union["Page", "Frame"] + ) -> "CDPSession": + """BrowserContext.new_cdp_session - Returns element attribute value. + **NOTE** CDP sessions are only supported on Chromium-based browsers. + + Returns the newly created session. Parameters ---------- - name : str - Attribute name to get the value for. + page : Union[Frame, Page] + Target to create new session for. For backwards-compatibility, this parameter is named `page`, but it can be a + `Page` or `Frame` type. Returns ------- - Union[str, None] + CDPSession """ - return mapping.from_maybe_impl(await self._impl_obj.get_attribute(name=name)) + return mapping.from_impl( + await self._impl_obj.new_cdp_session(page=mapping.to_impl(page)) + ) - async def text_content(self) -> typing.Optional[str]: - """ElementHandle.text_content + async def new_page(self) -> "Page": + """BrowserContext.new_page - Returns the `node.textContent`. + Creates a new page in the browser context. Returns ------- - Union[str, None] + Page """ - return mapping.from_maybe_impl(await self._impl_obj.text_content()) - - async def inner_text(self) -> str: - """ElementHandle.inner_text - - Returns the `element.innerText`. + return mapping.from_impl(await self._impl_obj.new_page()) - Returns - ------- - str + @typing.overload + def on( + self, + event: Literal["backgroundpage"], + f: typing.Callable[["Page"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: """ + This event is not emitted.""" - return mapping.from_maybe_impl(await self._impl_obj.inner_text()) - - async def inner_html(self) -> str: - """ElementHandle.inner_html - - Returns the `element.innerHTML`. + @typing.overload + def on( + self, + event: Literal["close"], + f: typing.Callable[ + ["BrowserContext"], "typing.Union[typing.Awaitable[None], None]" + ], + ) -> None: + """ + Emitted when Browser context gets closed. This might happen because of one of the following: + - Browser context is closed. + - Browser application is closed or crashed. + - The `browser.close()` method was called.""" - Returns - ------- - str + @typing.overload + def on( + self, + event: Literal["console"], + f: typing.Callable[ + ["ConsoleMessage"], "typing.Union[typing.Awaitable[None], None]" + ], + ) -> None: """ + Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. - return mapping.from_maybe_impl(await self._impl_obj.inner_html()) + The arguments passed into `console.log` and the page are available on the `ConsoleMessage` event handler argument. - async def is_checked(self) -> bool: - """ElementHandle.is_checked + **Usage** - Returns whether the element is checked. Throws if the element is not a checkbox or radio input. + ```py + async def print_args(msg): + values = [] + for arg in msg.args: + values.append(await arg.json_value()) + print(values) - Returns - ------- - bool + context.on(\"console\", print_args) + await page.evaluate(\"console.log('hello', 5, { foo: 'bar' })\") + ```""" + + @typing.overload + def on( + self, + event: Literal["dialog"], + f: typing.Callable[["Dialog"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: """ + Emitted when a JavaScript dialog appears, such as `alert`, `prompt`, `confirm` or `beforeunload`. Listener **must** + either `dialog.accept()` or `dialog.dismiss()` the dialog - otherwise the page will + [freeze](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking) waiting for the dialog, + and actions like click will never finish. - return mapping.from_maybe_impl(await self._impl_obj.is_checked()) + **Usage** - async def is_disabled(self) -> bool: - """ElementHandle.is_disabled + ```python + context.on(\"dialog\", lambda dialog: dialog.accept()) + ``` - Returns whether the element is disabled, the opposite of [enabled](https://playwright.dev/python/docs/actionability#enabled). + **NOTE** When no `page.on('dialog')` or `browser_context.on('dialog')` listeners are present, all dialogs are + automatically dismissed.""" - Returns - ------- - bool + @typing.overload + def on( + self, + event: Literal["dialogclosed"], + f: typing.Callable[["Dialog"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: + """ + Emitted when a JavaScript dialog in any page belonging to this context has been closed, either by + `dialog.accept()`, by `dialog.dismiss()`, or manually by the user in the headed browser. """ - return mapping.from_maybe_impl(await self._impl_obj.is_disabled()) - - async def is_editable(self) -> bool: - """ElementHandle.is_editable - - Returns whether the element is [editable](https://playwright.dev/python/docs/actionability#editable). - - Returns - ------- - bool + @typing.overload + def on( + self, + event: Literal["download"], + f: typing.Callable[["Download"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: """ + Emitted when attachment download started in any page belonging to this context. User can access basic file + operations on downloaded content via the passed `Download` instance. See also `page.on('download')` to receive + events about a specific page.""" - return mapping.from_maybe_impl(await self._impl_obj.is_editable()) + @typing.overload + def on( + self, + event: Literal["frameattached"], + f: typing.Callable[["Frame"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: + """ + Emitted when a frame is attached in any page belonging to this context. See also `page.on('frameattached')` to + receive events about a specific page.""" - async def is_enabled(self) -> bool: - """ElementHandle.is_enabled + @typing.overload + def on( + self, + event: Literal["framedetached"], + f: typing.Callable[["Frame"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: + """ + Emitted when a frame is detached in any page belonging to this context. See also `page.on('framedetached')` to + receive events about a specific page.""" - Returns whether the element is [enabled](https://playwright.dev/python/docs/actionability#enabled). + @typing.overload + def on( + self, + event: Literal["framenavigated"], + f: typing.Callable[["Frame"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: + """ + Emitted when a frame is navigated to a new url in any page belonging to this context. See also + `page.on('framenavigated')` to receive events about navigations in a specific page. + """ - Returns - ------- - bool + @typing.overload + def on( + self, + event: Literal["page"], + f: typing.Callable[["Page"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: """ + The event is emitted when a new Page is created in the BrowserContext. The page may still be loading. The event + will also fire for popup pages. See also `page.on('popup')` to receive events about popups relevant to a specific + page. - return mapping.from_maybe_impl(await self._impl_obj.is_enabled()) + The earliest moment that page is available is when it has navigated to the initial url. For example, when opening a + popup with `window.open('http://example.com')`, this event will fire when the network request to + \"http://example.com\" is done and its response has started loading in the popup. If you would like to route/listen + to this network request, use `browser_context.route()` and `browser_context.on('request')` respectively instead of + similar methods on the `Page`. - async def is_hidden(self) -> bool: - """ElementHandle.is_hidden + ```py + async with context.expect_page() as page_info: + await page.get_by_text(\"open new page\").click(), + page = await page_info.value + print(await page.evaluate(\"location.href\")) + ``` - Returns whether the element is hidden, the opposite of [visible](https://playwright.dev/python/docs/actionability#visible). + **NOTE** Use `page.wait_for_load_state()` to wait until the page gets to a particular state (you should not need it + in most cases).""" - Returns - ------- - bool + @typing.overload + def on( + self, + event: Literal["pageclose"], + f: typing.Callable[["Page"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: + """ + Emitted when a page in this context is closed. See also `page.on('close')` to receive events about a specific page. """ - return mapping.from_maybe_impl(await self._impl_obj.is_hidden()) - - async def is_visible(self) -> bool: - """ElementHandle.is_visible - - Returns whether the element is [visible](https://playwright.dev/python/docs/actionability#visible). + @typing.overload + def on( + self, + event: Literal["pageload"], + f: typing.Callable[["Page"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: + """ + Emitted when the JavaScript [`load`](https://developer.mozilla.org/en-US/docs/Web/Events/load) event is dispatched + in any page belonging to this context. See also `page.on('load')` to receive events about a specific page. + """ - Returns - ------- - bool + @typing.overload + def on( + self, + event: Literal["request"], + f: typing.Callable[["Request"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: """ + Emitted when a request is issued from any pages created through this context. The [request] object is read-only. To + only listen for requests from a particular page, use `page.on('request')`. - return mapping.from_maybe_impl(await self._impl_obj.is_visible()) + In order to intercept and mutate requests, see `browser_context.route()` or `page.route()`. + """ - async def dispatch_event( - self, type: str, event_init: typing.Optional[typing.Dict] = None + @typing.overload + def on( + self, + event: Literal["requestfailed"], + f: typing.Callable[["Request"], "typing.Union[typing.Awaitable[None], None]"], ) -> None: - """ElementHandle.dispatch_event + """ + Emitted when a request fails, for example by timing out. To only listen for failed requests from a particular page, + use `page.on('requestfailed')`. - The snippet below dispatches the `click` event on the element. Regardless of the visibility state of the element, - `click` is dispatched. This is equivalent to calling - [element.click()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click). + **NOTE** HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request + will complete with `browser_context.on('requestfinished')` event and not with + `browser_context.on('requestfailed')`.""" - **Usage** + @typing.overload + def on( + self, + event: Literal["requestfinished"], + f: typing.Callable[["Request"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: + """ + Emitted when a request finishes successfully after downloading the response body. For a successful response, the + sequence of events is `request`, `response` and `requestfinished`. To listen for successful requests from a + particular page, use `page.on('requestfinished')`.""" - ```py - await element_handle.dispatch_event(\"click\") - ``` + @typing.overload + def on( + self, + event: Literal["response"], + f: typing.Callable[["Response"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: + """ + Emitted when [response] status and headers are received for a request. For a successful response, the sequence of + events is `request`, `response` and `requestfinished`. To listen for response events from a particular page, use + `page.on('response')`.""" - Under the hood, it creates an instance of an event based on the given `type`, initializes it with `event_init` - properties and dispatches it on the element. Events are `composed`, `cancelable` and bubble by default. + @typing.overload + def on( + self, + event: Literal["serviceworker"], + f: typing.Callable[["Worker"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: + """ + **NOTE** Service workers are only supported on Chromium-based browsers. - Since `event_init` is event-specific, please refer to the events documentation for the lists of initial properties: - - [DeviceMotionEvent](https://developer.mozilla.org/en-US/docs/Web/API/DeviceMotionEvent/DeviceMotionEvent) - - [DeviceOrientationEvent](https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent/DeviceOrientationEvent) - - [DragEvent](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent/DragEvent) - - [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event/Event) - - [FocusEvent](https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/FocusEvent) - - [KeyboardEvent](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/KeyboardEvent) - - [MouseEvent](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/MouseEvent) - - [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/PointerEvent) - - [TouchEvent](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/TouchEvent) - - [WheelEvent](https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/WheelEvent) + Emitted when new service worker is created in the context.""" - You can also specify `JSHandle` as the property value if you want live objects to be passed into the event: + @typing.overload + def on( + self, + event: Literal["weberror"], + f: typing.Callable[["WebError"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: + """ + Emitted when exception is unhandled in any of the pages in this context. To listen for errors from a particular + page, use `page.on('pageerror')` instead.""" - ```py - # note you can only create data_transfer in chromium and firefox - data_transfer = await page.evaluate_handle(\"new DataTransfer()\") - await element_handle.dispatch_event(\"#source\", \"dragstart\", {\"dataTransfer\": data_transfer}) - ``` + def on( + self, + event: str, + f: typing.Callable[..., typing.Union[typing.Awaitable[None], None]], + ) -> None: + return super().on(event=event, f=f) - Parameters - ---------- - type : str - DOM event type: `"click"`, `"dragstart"`, etc. - event_init : Union[Dict, None] - Optional event-specific initialization properties. + @typing.overload + def once( + self, + event: Literal["backgroundpage"], + f: typing.Callable[["Page"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: """ + This event is not emitted.""" - await self._impl_obj.dispatch_event( - type=type, eventInit=mapping.to_impl(event_init) - ) - - async def scroll_into_view_if_needed( + @typing.overload + def once( self, - *, - timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, + event: Literal["close"], + f: typing.Callable[ + ["BrowserContext"], "typing.Union[typing.Awaitable[None], None]" + ], ) -> None: - """ElementHandle.scroll_into_view_if_needed + """ + Emitted when Browser context gets closed. This might happen because of one of the following: + - Browser context is closed. + - Browser application is closed or crashed. + - The `browser.close()` method was called.""" - This method waits for [actionability](https://playwright.dev/python/docs/actionability) checks, then tries to scroll element into view, unless - it is completely visible as defined by - [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)'s `ratio`. + @typing.overload + def once( + self, + event: Literal["console"], + f: typing.Callable[ + ["ConsoleMessage"], "typing.Union[typing.Awaitable[None], None]" + ], + ) -> None: + """ + Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. - Throws when `elementHandle` does not point to an element - [connected](https://developer.mozilla.org/en-US/docs/Web/API/Node/isConnected) to a Document or a ShadowRoot. + The arguments passed into `console.log` and the page are available on the `ConsoleMessage` event handler argument. - See [scrolling](https://playwright.dev/python/docs/input#scrolling) for alternative ways to scroll. + **Usage** - Parameters - ---------- - timeout : Union[float, None] - Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can - be changed by using the `browser_context.set_default_timeout()` or `page.set_default_timeout()` methods. - """ + ```py + async def print_args(msg): + values = [] + for arg in msg.args: + values.append(await arg.json_value()) + print(values) - await self._impl_obj.scroll_into_view_if_needed( - timeout=to_milliseconds(timeout) - ) + context.on(\"console\", print_args) + await page.evaluate(\"console.log('hello', 5, { foo: 'bar' })\") + ```""" - async def hover( + @typing.overload + def once( self, - *, - modifiers: typing.Optional[ - typing.Sequence[Literal["Alt", "Control", "ControlOrMeta", "Meta", "Shift"]] - ] = None, - position: typing.Optional[Position] = None, - timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, - no_wait_after: typing.Optional[bool] = None, - force: typing.Optional[bool] = None, - trial: typing.Optional[bool] = None, - scroll: typing.Optional[Literal["auto", "none"]] = None, + event: Literal["dialog"], + f: typing.Callable[["Dialog"], "typing.Union[typing.Awaitable[None], None]"], ) -> None: - """ElementHandle.hover + """ + Emitted when a JavaScript dialog appears, such as `alert`, `prompt`, `confirm` or `beforeunload`. Listener **must** + either `dialog.accept()` or `dialog.dismiss()` the dialog - otherwise the page will + [freeze](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking) waiting for the dialog, + and actions like click will never finish. - This method hovers over the element by performing the following steps: - 1. Wait for [actionability](https://playwright.dev/python/docs/actionability) checks on the element, unless `force` option is set. - 1. Scroll the element into view if needed. - 1. Use `page.mouse` to hover over the center of the element, or the specified `position`. + **Usage** - If the element is detached from the DOM at any moment during the action, this method throws. + ```python + context.on(\"dialog\", lambda dialog: dialog.accept()) + ``` - When all steps combined have not finished during the specified `timeout`, this method throws a `TimeoutError`. - Passing zero timeout disables this. + **NOTE** When no `page.on('dialog')` or `browser_context.on('dialog')` listeners are present, all dialogs are + automatically dismissed.""" - Parameters - ---------- - modifiers : Union[Sequence[Union["Alt", "Control", "ControlOrMeta", "Meta", "Shift"]], None] - Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores - current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to - "Control" on Windows and Linux and to "Meta" on macOS. - position : Union[{x: float, y: float}, None] - A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of - the element. - timeout : Union[float, None] - Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can - be changed by using the `browser_context.set_default_timeout()` or `page.set_default_timeout()` methods. - no_wait_after : Union[bool, None] - This option has no effect. - Deprecated: This option has no effect. - force : Union[bool, None] - Whether to bypass the [actionability](../actionability.md) checks. Defaults to `false`. - trial : Union[bool, None] - When set, this method only performs the [actionability](../actionability.md) checks and skips the action. Defaults - to `false`. Useful to wait until the element is ready for the action without performing it. - scroll : Union["auto", "none", None] - Controls whether Playwright scrolls the element into view before performing the action. Defaults to `"auto"`, which - scrolls the element into view when necessary, including scrolling nested scrollable containers. When set to - `"none"`, Playwright does not scroll the element and the action fails if the element is not already in the - viewport. This is useful to assert that an element is reachable by the user without additional scrolling. + @typing.overload + def once( + self, + event: Literal["dialogclosed"], + f: typing.Callable[["Dialog"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: + """ + Emitted when a JavaScript dialog in any page belonging to this context has been closed, either by + `dialog.accept()`, by `dialog.dismiss()`, or manually by the user in the headed browser. """ - await self._impl_obj.hover( - modifiers=mapping.to_impl(modifiers), - position=position, - timeout=to_milliseconds(timeout), - noWaitAfter=no_wait_after, - force=force, - trial=trial, - scroll=scroll, - ) - - async def click( + @typing.overload + def once( self, - *, - modifiers: typing.Optional[ - typing.Sequence[Literal["Alt", "Control", "ControlOrMeta", "Meta", "Shift"]] - ] = None, - position: typing.Optional[Position] = None, - delay: typing.Optional[float] = None, - button: typing.Optional[Literal["left", "middle", "right"]] = None, - click_count: typing.Optional[int] = None, - timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, - force: typing.Optional[bool] = None, - no_wait_after: typing.Optional[bool] = None, - trial: typing.Optional[bool] = None, - steps: typing.Optional[int] = None, - scroll: typing.Optional[Literal["auto", "none"]] = None, + event: Literal["download"], + f: typing.Callable[["Download"], "typing.Union[typing.Awaitable[None], None]"], ) -> None: - """ElementHandle.click - - This method clicks the element by performing the following steps: - 1. Wait for [actionability](https://playwright.dev/python/docs/actionability) checks on the element, unless `force` option is set. - 1. Scroll the element into view if needed. - 1. Use `page.mouse` to click in the center of the element, or the specified `position`. - 1. Wait for initiated navigations to either succeed or fail, unless `no_wait_after` option is set. - - If the element is detached from the DOM at any moment during the action, this method throws. - - When all steps combined have not finished during the specified `timeout`, this method throws a `TimeoutError`. - Passing zero timeout disables this. + """ + Emitted when attachment download started in any page belonging to this context. User can access basic file + operations on downloaded content via the passed `Download` instance. See also `page.on('download')` to receive + events about a specific page.""" - Parameters - ---------- - modifiers : Union[Sequence[Union["Alt", "Control", "ControlOrMeta", "Meta", "Shift"]], None] - Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores - current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to - "Control" on Windows and Linux and to "Meta" on macOS. - position : Union[{x: float, y: float}, None] - A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of - the element. - delay : Union[float, None] - Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0. - button : Union["left", "middle", "right", None] - Defaults to `left`. - click_count : Union[int, None] - defaults to 1. See [UIEvent.detail]. - timeout : Union[float, None] - Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can - be changed by using the `browser_context.set_default_timeout()` or `page.set_default_timeout()` methods. - force : Union[bool, None] - Whether to bypass the [actionability](../actionability.md) checks. Defaults to `false`. - no_wait_after : Union[bool, None] - Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You - can opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as - navigating to inaccessible pages. Defaults to `false`. - Deprecated: This option will default to `true` in the future. - trial : Union[bool, None] - When set, this method only performs the [actionability](../actionability.md) checks and skips the action. Defaults - to `false`. Useful to wait until the element is ready for the action without performing it. - steps : Union[int, None] - Defaults to 1. Sends `n` interpolated `mousemove` events to represent travel between Playwright's current cursor - position and the provided destination. When set to 1, emits a single `mousemove` event at the destination location. - scroll : Union["auto", "none", None] - Controls whether Playwright scrolls the element into view before performing the action. Defaults to `"auto"`, which - scrolls the element into view when necessary, including scrolling nested scrollable containers. When set to - `"none"`, Playwright does not scroll the element and the action fails if the element is not already in the - viewport. This is useful to assert that an element is reachable by the user without additional scrolling. + @typing.overload + def once( + self, + event: Literal["frameattached"], + f: typing.Callable[["Frame"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: """ + Emitted when a frame is attached in any page belonging to this context. See also `page.on('frameattached')` to + receive events about a specific page.""" - await self._impl_obj.click( - modifiers=mapping.to_impl(modifiers), - position=position, - delay=delay, - button=button, - clickCount=click_count, - timeout=to_milliseconds(timeout), - force=force, - noWaitAfter=no_wait_after, - trial=trial, - steps=steps, - scroll=scroll, - ) + @typing.overload + def once( + self, + event: Literal["framedetached"], + f: typing.Callable[["Frame"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: + """ + Emitted when a frame is detached in any page belonging to this context. See also `page.on('framedetached')` to + receive events about a specific page.""" - async def dblclick( + @typing.overload + def once( self, - *, - modifiers: typing.Optional[ - typing.Sequence[Literal["Alt", "Control", "ControlOrMeta", "Meta", "Shift"]] - ] = None, - position: typing.Optional[Position] = None, - delay: typing.Optional[float] = None, - button: typing.Optional[Literal["left", "middle", "right"]] = None, - timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, - force: typing.Optional[bool] = None, - no_wait_after: typing.Optional[bool] = None, - trial: typing.Optional[bool] = None, - steps: typing.Optional[int] = None, - scroll: typing.Optional[Literal["auto", "none"]] = None, + event: Literal["framenavigated"], + f: typing.Callable[["Frame"], "typing.Union[typing.Awaitable[None], None]"], ) -> None: - """ElementHandle.dblclick + """ + Emitted when a frame is navigated to a new url in any page belonging to this context. See also + `page.on('framenavigated')` to receive events about navigations in a specific page. + """ - This method double clicks the element by performing the following steps: - 1. Wait for [actionability](https://playwright.dev/python/docs/actionability) checks on the element, unless `force` option is set. - 1. Scroll the element into view if needed. - 1. Use `page.mouse` to double click in the center of the element, or the specified `position`. + @typing.overload + def once( + self, + event: Literal["page"], + f: typing.Callable[["Page"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: + """ + The event is emitted when a new Page is created in the BrowserContext. The page may still be loading. The event + will also fire for popup pages. See also `page.on('popup')` to receive events about popups relevant to a specific + page. - If the element is detached from the DOM at any moment during the action, this method throws. + The earliest moment that page is available is when it has navigated to the initial url. For example, when opening a + popup with `window.open('http://example.com')`, this event will fire when the network request to + \"http://example.com\" is done and its response has started loading in the popup. If you would like to route/listen + to this network request, use `browser_context.route()` and `browser_context.on('request')` respectively instead of + similar methods on the `Page`. - When all steps combined have not finished during the specified `timeout`, this method throws a `TimeoutError`. - Passing zero timeout disables this. + ```py + async with context.expect_page() as page_info: + await page.get_by_text(\"open new page\").click(), + page = await page_info.value + print(await page.evaluate(\"location.href\")) + ``` - **NOTE** `elementHandle.dblclick()` dispatches two `click` events and a single `dblclick` event. + **NOTE** Use `page.wait_for_load_state()` to wait until the page gets to a particular state (you should not need it + in most cases).""" - Parameters - ---------- - modifiers : Union[Sequence[Union["Alt", "Control", "ControlOrMeta", "Meta", "Shift"]], None] - Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores - current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to - "Control" on Windows and Linux and to "Meta" on macOS. - position : Union[{x: float, y: float}, None] - A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of - the element. - delay : Union[float, None] - Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0. - button : Union["left", "middle", "right", None] - Defaults to `left`. - timeout : Union[float, None] - Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can - be changed by using the `browser_context.set_default_timeout()` or `page.set_default_timeout()` methods. - force : Union[bool, None] - Whether to bypass the [actionability](../actionability.md) checks. Defaults to `false`. - no_wait_after : Union[bool, None] - This option has no effect. - Deprecated: This option has no effect. - trial : Union[bool, None] - When set, this method only performs the [actionability](../actionability.md) checks and skips the action. Defaults - to `false`. Useful to wait until the element is ready for the action without performing it. - steps : Union[int, None] - Defaults to 1. Sends `n` interpolated `mousemove` events to represent travel between Playwright's current cursor - position and the provided destination. When set to 1, emits a single `mousemove` event at the destination location. - scroll : Union["auto", "none", None] - Controls whether Playwright scrolls the element into view before performing the action. Defaults to `"auto"`, which - scrolls the element into view when necessary, including scrolling nested scrollable containers. When set to - `"none"`, Playwright does not scroll the element and the action fails if the element is not already in the - viewport. This is useful to assert that an element is reachable by the user without additional scrolling. + @typing.overload + def once( + self, + event: Literal["pageclose"], + f: typing.Callable[["Page"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: + """ + Emitted when a page in this context is closed. See also `page.on('close')` to receive events about a specific page. """ - await self._impl_obj.dblclick( - modifiers=mapping.to_impl(modifiers), - position=position, - delay=delay, - button=button, - timeout=to_milliseconds(timeout), - force=force, - noWaitAfter=no_wait_after, - trial=trial, - steps=steps, - scroll=scroll, - ) - - async def select_option( + @typing.overload + def once( self, - value: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, - *, - index: typing.Optional[typing.Union[int, typing.Sequence[int]]] = None, - label: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, - element: typing.Optional[ - typing.Union["ElementHandle", typing.Sequence["ElementHandle"]] - ] = None, - timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None, - force: typing.Optional[bool] = None, - no_wait_after: typing.Optional[bool] = None, - ) -> typing.List[str]: - """ElementHandle.select_option + event: Literal["pageload"], + f: typing.Callable[["Page"], "typing.Union[typing.Awaitable[None], None]"], + ) -> None: + """ + Emitted when the JavaScript [`load`](https://developer.mozilla.org/en-US/docs/Web/Events/load) event is dispatched + in any page belonging to this context. See also `page.on('load')` to receive events about a specific page. + """ - This method waits for [actionability](https://playwright.dev/python/docs/actionability) checks, waits until all specified options are present in - the `` element, this method throws an error. However, if the element is inside - the `