Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/skills/playwright-roll/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ The Python port is hand-written code in `playwright/_impl/`, plus a generator (`
2. applies the Python facts that the docs do not contain, from `scripts/codegen/python_rules.js`, and
3. emits the whole public API into `playwright/{async,sync}_api/_generated.py`: signatures, types, docstrings, event overloads, and the call into `_impl/` for every member.

The generator never reads `_impl/`. A new member or option in the docs therefore shows up in `_generated.py` right away, as a call into `_impl/` that does not exist yet. Each generated class types its `_impl_obj`, so **`mypy playwright` lists every such gap** as an error in `_generated.py`. (Temporary: while `scripts/codegen/legacy_order.json` exists, `_impl_obj` is not typed and mypy reports nothing. Find the gaps in the docs diff and with the tests instead.) Three resolutions:
The generator never reads `_impl/`. A new member or option in the docs therefore shows up in `_generated.py` right away, as a call into `_impl/` that does not exist yet. Each generated class types its `_impl_obj`, so **`mypy playwright` lists every such gap** as an error in `_generated.py`. Three resolutions:

- **PORT** — the new API is intended for Python (no `langs.only` filter, or `langs.only` includes `"python"`). Implement it in `_impl/` until mypy is clean.
- **MISMATCH** — the shipped Python API differs from the docs (a callback signature uses unions, a kwarg uses a legacy name, etc.). The shipped implementation wins. Add an entry to `scripts/codegen/python_rules.js` with a comment explaining *why*, and propose the upstream docs change that would make the entry unnecessary.
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Python bindings for [Playwright](https://playwright.dev). The Python client talk
- `playwright/async_api/_generated.py`, `playwright/sync_api/_generated.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, and the calls into `_impl/`. It does not read `_impl/`.
- `scripts/codegen/python_rules.js` — the Python facts that the docs do not contain (positional parameters, struct names, 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. 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. While the file exists, `_impl_obj` is not typed, so the mypy check described below is not active yet: a docs member that `_impl/` lacks fails only at run time. A follow-up change deletes the file and the `TEMPORARY` code.
- `scripts/codegen/legacy_order.json` — **temporary**. The old generator's order of classes, members, keyword-only parameters and union members. 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-<version>-<suffix>.zip`), so it doubles as the build cache key.
Expand Down
2 changes: 1 addition & 1 deletion ROLLING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ 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`
* 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`. (Temporary: while `scripts/codegen/legacy_order.json` exists, mypy does not check this yet; rely on the tests.)
* 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
4 changes: 1 addition & 3 deletions playwright/_impl/_async_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@ def __init__(self, impl_obj: Any) -> None:
def __str__(self) -> str:
return self._impl_obj.__str__()

def _wrap_handler(
self, handler: Union[Callable[..., Any], Any]
) -> Callable[..., None]:
def _wrap_handler(self, handler: Union[Callable[..., Any], Any]) -> Any:
if callable(handler):
return mapping.wrap_handler(handler)
return handler
Expand Down
15 changes: 15 additions & 0 deletions playwright/_impl/_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
TypeVar,
Union,
cast,
overload,
)
from urllib.parse import ParseResult, urljoin, urlparse, urlunparse

Expand Down Expand Up @@ -591,6 +592,20 @@ def is_textual_mime_type(mime_type: str) -> bool:
return bool(TEXTUAL_MIME_TYPE.match(mime_type))


@overload
def to_milliseconds(value: Union[float, datetime.timedelta]) -> float: ...


@overload
def to_milliseconds(value: None) -> None: ...


@overload
def to_milliseconds(
value: Union[float, datetime.timedelta, None],
) -> Optional[float]: ...


def to_milliseconds(
value: Union[float, datetime.timedelta, None],
) -> Optional[float]:
Expand Down
4 changes: 1 addition & 3 deletions playwright/_impl/_sync_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,7 @@ def _sync(
wait_for_future(self._loop, self._dispatcher_fiber, task)
return task.result()

def _wrap_handler(
self, handler: Union[Callable[..., Any], Any]
) -> Callable[..., None]:
def _wrap_handler(self, handler: Union[Callable[..., Any], Any]) -> Any:
if callable(handler):
return mapping.wrap_handler(handler)
return handler
Expand Down
Loading
Loading