Skip to content

Commit 69f5d71

Browse files
committed
chore(codegen): use the docs order in the generated API
- Removes scripts/codegen/legacy_order.json and the code that applied it. - The generated classes, members, keyword-only parameters and union members now follow the docs order, and 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-<new> branch, and list the checks that it is on that branch, clean, and up to date with origin.
1 parent 222a2e0 commit 69f5d71

9 files changed

Lines changed: 35692 additions & 36161 deletions

File tree

‎.claude/skills/playwright-roll/SKILL.md‎

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,30 @@ The upstream documentation source of truth is `docs/src/api/*.md` in the playwri
3939

4040
### 2. Bump the driver pin, download it, and generate api.json
4141

42-
You need a nearby `microsoft/playwright` checkout for the docs walk and for
43-
codegen. Point `PW_SRC_DIR` at it and check out the release branch for the new
44-
version there (the branch has the release's docs plus any cherry-picks):
42+
The docs walk and codegen read the upstream docs from a `microsoft/playwright`
43+
checkout at `$PW_SRC_DIR`. **Use a separate checkout that exists only for
44+
rolls, on the exact release branch you roll to**: `release-<new>`, the
45+
`major.minor` of the new `DRIVER_VERSION` (the branch has the release's docs
46+
plus any cherry-picks). Never point `PW_SRC_DIR` at a checkout that someone
47+
works in: on `main` or a feature branch the docs differ, and the generator
48+
silently emits that API instead of the release's.
4549

4650
```sh
47-
export PW_SRC_DIR=../playwright
48-
git -C "$PW_SRC_DIR" fetch origin 'release-*:release-*'
49-
git -C "$PW_SRC_DIR" checkout release-<new> # e.g. release-1.62
51+
export PW_SRC_DIR=../playwright-for-python # the roll checkout, nothing else
52+
# First roll on this machine: clone it (no npm install needed).
53+
git clone https://github.com/microsoft/playwright.git "$PW_SRC_DIR"
54+
# Every roll: move it to the release branch.
55+
git -C "$PW_SRC_DIR" fetch origin
56+
git -C "$PW_SRC_DIR" checkout release-<new> # e.g. release-1.62
57+
git -C "$PW_SRC_DIR" merge --ff-only origin/release-<new>
58+
```
59+
60+
Check the checkout before you generate, and again before you commit:
61+
62+
```sh
63+
git -C "$PW_SRC_DIR" rev-parse --abbrev-ref HEAD # must print release-<new>
64+
git -C "$PW_SRC_DIR" status --porcelain # must print nothing
65+
git -C "$PW_SRC_DIR" rev-parse HEAD origin/release-<new> # both lines must be equal
5066
```
5167

5268
Then bump the pins and assemble the driver:
@@ -73,7 +89,7 @@ the walk.
7389

7490
### 3. Identify the commit range
7591

76-
Use the nearby `microsoft/playwright` checkout at `$PW_SRC_DIR` (from step 2).
92+
Use the roll checkout at `$PW_SRC_DIR` (from step 2).
7793
Bring it up to date and ensure release branches/tags are present before walking
7894
the range:
7995

@@ -220,7 +236,7 @@ Tick the box in `/tmp/roll-<new>-commits.md` with one line: `[x] <sha> <subject>
220236
### 5. Regenerate
221237

222238
```sh
223-
PW_SRC_DIR=../playwright ./scripts/update_api.sh # PW_SRC_DIR already exported in step 2
239+
./scripts/update_api.sh # uses PW_SRC_DIR from step 2; run the checkout checks there first
224240
```
225241

226242
The script, for `sync` and then `async`:
@@ -248,10 +264,10 @@ Failure modes and fixes:
248264
| mypy: `Unexpected keyword argument "z" for "y" of "XImpl"` | New parameter or option on an existing method. | Add the kwarg (docs camelCase name) in `_impl/`. If Python must not have it, `skipArgs`. |
249265
| 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. |
250266
| generator: `No Python name for the struct at X.y.z` | A new inline `[Object]` with no `* alias:` in the docs. | Add the TypedDict and name it: `alias-python` upstream, or `structNamesByPlace` / `structRenames`. |
267+
| `_generated.py` gains or loses members that the commit walk never mentioned | `PW_SRC_DIR` is not on `release-<new>` (for example on `main` or a feature branch), or is behind `origin/release-<new>`. | Run the checkout checks from step 2, fix the checkout, regenerate. |
251268
| 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`. |
252269
| 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. |
253270
| 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. |
254-
| generator: `legacy_order.json: … has no …; remove it` | A member or parameter 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. |
255271
| `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. |
256272
| `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. |
257273
| 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`). |
@@ -279,6 +295,8 @@ For each PORT, add one async test and a matching sync test. Conventions:
279295

280296
### 8. Final verification
281297

298+
Repeat the checkout checks from step 2: the committed `_generated.py` must come from `release-<new>`.
299+
282300
```sh
283301
pre-commit run --all-files
284302
mypy playwright # 2 pre-existing errors in _json_pipe.py and _artifact.py are unrelated

‎CLAUDE.md‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,12 @@ Python bindings for [Playwright](https://playwright.dev). The Python client talk
1212
- `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/`.
1313
- `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/`.
1414
- `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.
15-
- `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.
1615
- `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.
1716
- `tests/async/`, `tests/sync/` — pytest suites. Most new tests are added to the async file with a sync mirror.
1817
- `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.
1918
- `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`).
2019
- `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).
21-
- 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.
20+
- 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.
2221
- `ROLLING.md`, `CONTRIBUTING.md` — human-facing setup and roll docs.
2322

2423
## Setup

‎CONTRIBUTING.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,14 @@ For more details look at the [CI configuration](./.github/workflows/ci.yml).
7676
### Regenerating APIs
7777

7878
`update_api.sh` generates `playwright/{async,sync}_api/_generated.py` from the
79-
API docs in a nearby `microsoft/playwright` checkout (at the release branch
80-
matching `DRIVER_VERSION`); point `PW_SRC_DIR` at it. The generator is
79+
API docs in a separate `microsoft/playwright` checkout on the exact release
80+
branch for `DRIVER_VERSION` (for example `release-1.64`); point `PW_SRC_DIR`
81+
at it. The generator is
8182
`scripts/codegen/generate_api.js`; Python facts that the docs do not contain
8283
live in `scripts/codegen/python_rules.js`.
8384

8485
```bash
85-
PW_SRC_DIR=../playwright ./scripts/update_api.sh
86+
PW_SRC_DIR=../playwright-for-python ./scripts/update_api.sh
8687
pre-commit run --all-files
8788
```
8889

‎ROLLING.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pip install -e .
1313
```
1414
* 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`
1515
* 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).
16-
* 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`
16+
* 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`
1717
* 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`.
1818
* commit changes & send PR
1919
* wait for bots to pass & merge the PR

0 commit comments

Comments
 (0)