Skip to content

Commit 3c7c545

Browse files
authored
chore(codegen): import the impl classes from one module (#3257)
1 parent 8f0e739 commit 3c7c545

9 files changed

Lines changed: 193 additions & 119 deletions

File tree

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,10 @@ Implement the change in `playwright/_impl/<module>.py`. Use the upstream JS impl
183183

184184
When implementing a new ChannelOwner subclass (one constructed by the protocol with `(parent, type, guid, initializer)`):
185185
1. Register it in `playwright/_impl/_object_factory.py:create_remote_object` — otherwise the guid resolves to `DummyObject` and downstream code breaks mysteriously.
186-
2. Nothing to do in codegen: the generator emits every Python class in the docs. If the class does not live in `_impl/_<snake_case name>.py`, add it to `implModules` in `scripts/codegen/python_rules.js`.
186+
2. Add it to `playwright/_impl/_api_classes.py` (the import and `__all__`). The generator emits every Python class in the docs, and the generated API imports each implementation from that file. If the class is missing there, `_generated.py` fails to import.
187187

188188
When implementing a non-ChannelOwner wrapper class (a plain class that holds a Page/Context reference, like `Screencast`, `Clock`):
189+
- Add it to `playwright/_impl/_api_classes.py`, as for a ChannelOwner subclass.
189190
- Set `self._loop = parent._loop` and `self._dispatcher_fiber = parent._dispatcher_fiber` in `__init__`. The generated `AsyncBase`/`SyncBase` wrappers read these; missing them gives `AttributeError: 'X' object has no attribute '_loop'` at first use.
190191

191192
When the docs add a new struct (an inline `[Object]` with named fields):
@@ -314,7 +315,6 @@ All keys use docs names: `Class.member` or `Class.member.arg`, with the upstream
314315
| `extraMembers`, `extraOptions` | Python-only members and hidden options; generated without docstrings. |
315316
| `positionalOptions` | Option names that are positional everywhere (`predicate`). |
316317
| `structTotal` | `total=` of a TypedDict, where it differs from "total=False if any field is optional". |
317-
| `implModules` | `_impl/` module of classes not in `_<snake_case name>.py`. |
318318

319319
## Tips & gotchas
320320

‎playwright/_impl/_api_classes.py‎

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Copyright (c) Microsoft Corporation.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# The implementation of every class in the generated API. The generated API
16+
# imports them from here, so the generator does not need to know which module
17+
# holds each class.
18+
19+
from playwright._impl._assertions import (
20+
APIResponseAssertions,
21+
LocatorAssertions,
22+
PageAssertions,
23+
)
24+
from playwright._impl._browser import Browser
25+
from playwright._impl._browser_context import BrowserContext
26+
from playwright._impl._browser_type import BrowserType
27+
from playwright._impl._cdp_session import CDPSession
28+
from playwright._impl._clock import Clock
29+
from playwright._impl._console_message import ConsoleMessage
30+
from playwright._impl._credentials import Credentials
31+
from playwright._impl._debugger import Debugger
32+
from playwright._impl._dialog import Dialog
33+
from playwright._impl._disposable import Disposable
34+
from playwright._impl._download import Download
35+
from playwright._impl._element_handle import ElementHandle
36+
from playwright._impl._fetch import APIRequest, APIRequestContext, APIResponse
37+
from playwright._impl._file_chooser import FileChooser
38+
from playwright._impl._frame import Frame
39+
from playwright._impl._input import Keyboard, Mouse, Touchscreen
40+
from playwright._impl._js_handle import JSHandle
41+
from playwright._impl._locator import FrameLocator, Locator
42+
from playwright._impl._network import (
43+
Request,
44+
Response,
45+
Route,
46+
WebSocket,
47+
WebSocketRoute,
48+
)
49+
from playwright._impl._page import Page, Worker
50+
from playwright._impl._playwright import Playwright
51+
from playwright._impl._screencast import Screencast
52+
from playwright._impl._selectors import Selectors
53+
from playwright._impl._tracing import Tracing
54+
from playwright._impl._video import Video
55+
from playwright._impl._web_error import WebError
56+
from playwright._impl._web_mcp import WebMCP
57+
from playwright._impl._web_storage import WebStorage
58+
59+
__all__ = [
60+
"APIRequest",
61+
"APIRequestContext",
62+
"APIResponse",
63+
"APIResponseAssertions",
64+
"Browser",
65+
"BrowserContext",
66+
"BrowserType",
67+
"CDPSession",
68+
"Clock",
69+
"ConsoleMessage",
70+
"Credentials",
71+
"Debugger",
72+
"Dialog",
73+
"Disposable",
74+
"Download",
75+
"ElementHandle",
76+
"FileChooser",
77+
"Frame",
78+
"FrameLocator",
79+
"JSHandle",
80+
"Keyboard",
81+
"Locator",
82+
"LocatorAssertions",
83+
"Mouse",
84+
"Page",
85+
"PageAssertions",
86+
"Playwright",
87+
"Request",
88+
"Response",
89+
"Route",
90+
"Screencast",
91+
"Selectors",
92+
"Touchscreen",
93+
"Tracing",
94+
"Video",
95+
"WebError",
96+
"WebMCP",
97+
"WebSocket",
98+
"WebSocketRoute",
99+
"WebStorage",
100+
"Worker",
101+
]

‎playwright/_impl/_frame.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
from playwright._impl._network import Response
8181
from playwright._impl._set_input_files_helpers import convert_input_files
8282
from playwright._impl._waiter import Waiter
83-
from playwright._impl._webmcp import WebMCP
83+
from playwright._impl._web_mcp import WebMCP
8484

8585
if TYPE_CHECKING: # pragma: no cover
8686
from playwright._impl._page import Page

‎playwright/_impl/_page.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@
104104
from playwright._impl._signature import signature
105105
from playwright._impl._video import Video
106106
from playwright._impl._waiter import Waiter
107+
from playwright._impl._web_mcp import WebMCP
107108
from playwright._impl._web_storage import WebStorage
108-
from playwright._impl._webmcp import WebMCP
109109

110110
if TYPE_CHECKING: # pragma: no cover
111111
from playwright._impl._browser_context import BrowserContext

‎playwright/async_api/_generated.py‎

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,49 @@
1818
import typing
1919
from typing import Literal
2020

21+
from playwright._impl._api_classes import APIRequest as APIRequestImpl
22+
from playwright._impl._api_classes import APIRequestContext as APIRequestContextImpl
23+
from playwright._impl._api_classes import APIResponse as APIResponseImpl
24+
from playwright._impl._api_classes import (
25+
APIResponseAssertions as APIResponseAssertionsImpl,
26+
)
27+
from playwright._impl._api_classes import Browser as BrowserImpl
28+
from playwright._impl._api_classes import BrowserContext as BrowserContextImpl
29+
from playwright._impl._api_classes import BrowserType as BrowserTypeImpl
30+
from playwright._impl._api_classes import CDPSession as CDPSessionImpl
31+
from playwright._impl._api_classes import Clock as ClockImpl
32+
from playwright._impl._api_classes import ConsoleMessage as ConsoleMessageImpl
33+
from playwright._impl._api_classes import Credentials as CredentialsImpl
34+
from playwright._impl._api_classes import Debugger as DebuggerImpl
35+
from playwright._impl._api_classes import Dialog as DialogImpl
36+
from playwright._impl._api_classes import Disposable as DisposableImpl
37+
from playwright._impl._api_classes import Download as DownloadImpl
38+
from playwright._impl._api_classes import ElementHandle as ElementHandleImpl
39+
from playwright._impl._api_classes import FileChooser as FileChooserImpl
40+
from playwright._impl._api_classes import Frame as FrameImpl
41+
from playwright._impl._api_classes import FrameLocator as FrameLocatorImpl
42+
from playwright._impl._api_classes import JSHandle as JSHandleImpl
43+
from playwright._impl._api_classes import Keyboard as KeyboardImpl
44+
from playwright._impl._api_classes import Locator as LocatorImpl
45+
from playwright._impl._api_classes import LocatorAssertions as LocatorAssertionsImpl
46+
from playwright._impl._api_classes import Mouse as MouseImpl
47+
from playwright._impl._api_classes import Page as PageImpl
48+
from playwright._impl._api_classes import PageAssertions as PageAssertionsImpl
49+
from playwright._impl._api_classes import Playwright as PlaywrightImpl
50+
from playwright._impl._api_classes import Request as RequestImpl
51+
from playwright._impl._api_classes import Response as ResponseImpl
52+
from playwright._impl._api_classes import Route as RouteImpl
53+
from playwright._impl._api_classes import Screencast as ScreencastImpl
54+
from playwright._impl._api_classes import Selectors as SelectorsImpl
55+
from playwright._impl._api_classes import Touchscreen as TouchscreenImpl
56+
from playwright._impl._api_classes import Tracing as TracingImpl
57+
from playwright._impl._api_classes import Video as VideoImpl
58+
from playwright._impl._api_classes import WebError as WebErrorImpl
59+
from playwright._impl._api_classes import WebMCP as WebMCPImpl
60+
from playwright._impl._api_classes import WebSocket as WebSocketImpl
61+
from playwright._impl._api_classes import WebSocketRoute as WebSocketRouteImpl
62+
from playwright._impl._api_classes import WebStorage as WebStorageImpl
63+
from playwright._impl._api_classes import Worker as WorkerImpl
2164
from playwright._impl._api_structures import (
2265
BrowserBindResult,
2366
ClientCertificate,
@@ -53,58 +96,15 @@
5396
WebMCPTool,
5497
WebStorageItem,
5598
)
56-
from playwright._impl._assertions import (
57-
APIResponseAssertions as APIResponseAssertionsImpl,
58-
)
59-
from playwright._impl._assertions import LocatorAssertions as LocatorAssertionsImpl
60-
from playwright._impl._assertions import PageAssertions as PageAssertionsImpl
6199
from playwright._impl._async_base import (
62100
AsyncBase,
63101
AsyncContextManager,
64102
AsyncEventContextManager,
65103
mapping,
66104
)
67-
from playwright._impl._browser import Browser as BrowserImpl
68-
from playwright._impl._browser_context import BrowserContext as BrowserContextImpl
69-
from playwright._impl._browser_type import BrowserType as BrowserTypeImpl
70-
from playwright._impl._cdp_session import CDPSession as CDPSessionImpl
71-
from playwright._impl._clock import Clock as ClockImpl
72-
from playwright._impl._console_message import ConsoleMessage as ConsoleMessageImpl
73-
from playwright._impl._credentials import Credentials as CredentialsImpl
74-
from playwright._impl._debugger import Debugger as DebuggerImpl
75-
from playwright._impl._dialog import Dialog as DialogImpl
76-
from playwright._impl._disposable import Disposable as DisposableImpl
77-
from playwright._impl._download import Download as DownloadImpl
78-
from playwright._impl._element_handle import ElementHandle as ElementHandleImpl
79105
from playwright._impl._errors import Error
80-
from playwright._impl._fetch import APIRequest as APIRequestImpl
81-
from playwright._impl._fetch import APIRequestContext as APIRequestContextImpl
82-
from playwright._impl._fetch import APIResponse as APIResponseImpl
83-
from playwright._impl._file_chooser import FileChooser as FileChooserImpl
84106
from playwright._impl._form_data import FormData
85-
from playwright._impl._frame import Frame as FrameImpl
86107
from playwright._impl._helper import to_milliseconds
87-
from playwright._impl._input import Keyboard as KeyboardImpl
88-
from playwright._impl._input import Mouse as MouseImpl
89-
from playwright._impl._input import Touchscreen as TouchscreenImpl
90-
from playwright._impl._js_handle import JSHandle as JSHandleImpl
91-
from playwright._impl._locator import FrameLocator as FrameLocatorImpl
92-
from playwright._impl._locator import Locator as LocatorImpl
93-
from playwright._impl._network import Request as RequestImpl
94-
from playwright._impl._network import Response as ResponseImpl
95-
from playwright._impl._network import Route as RouteImpl
96-
from playwright._impl._network import WebSocket as WebSocketImpl
97-
from playwright._impl._network import WebSocketRoute as WebSocketRouteImpl
98-
from playwright._impl._page import Page as PageImpl
99-
from playwright._impl._page import Worker as WorkerImpl
100-
from playwright._impl._playwright import Playwright as PlaywrightImpl
101-
from playwright._impl._screencast import Screencast as ScreencastImpl
102-
from playwright._impl._selectors import Selectors as SelectorsImpl
103-
from playwright._impl._tracing import Tracing as TracingImpl
104-
from playwright._impl._video import Video as VideoImpl
105-
from playwright._impl._web_error import WebError as WebErrorImpl
106-
from playwright._impl._web_storage import WebStorage as WebStorageImpl
107-
from playwright._impl._webmcp import WebMCP as WebMCPImpl
108108

109109

110110
class APIRequest(AsyncBase):

‎playwright/sync_api/_generated.py‎

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,49 @@
1818
import typing
1919
from typing import Literal
2020

21+
from playwright._impl._api_classes import APIRequest as APIRequestImpl
22+
from playwright._impl._api_classes import APIRequestContext as APIRequestContextImpl
23+
from playwright._impl._api_classes import APIResponse as APIResponseImpl
24+
from playwright._impl._api_classes import (
25+
APIResponseAssertions as APIResponseAssertionsImpl,
26+
)
27+
from playwright._impl._api_classes import Browser as BrowserImpl
28+
from playwright._impl._api_classes import BrowserContext as BrowserContextImpl
29+
from playwright._impl._api_classes import BrowserType as BrowserTypeImpl
30+
from playwright._impl._api_classes import CDPSession as CDPSessionImpl
31+
from playwright._impl._api_classes import Clock as ClockImpl
32+
from playwright._impl._api_classes import ConsoleMessage as ConsoleMessageImpl
33+
from playwright._impl._api_classes import Credentials as CredentialsImpl
34+
from playwright._impl._api_classes import Debugger as DebuggerImpl
35+
from playwright._impl._api_classes import Dialog as DialogImpl
36+
from playwright._impl._api_classes import Disposable as DisposableImpl
37+
from playwright._impl._api_classes import Download as DownloadImpl
38+
from playwright._impl._api_classes import ElementHandle as ElementHandleImpl
39+
from playwright._impl._api_classes import FileChooser as FileChooserImpl
40+
from playwright._impl._api_classes import Frame as FrameImpl
41+
from playwright._impl._api_classes import FrameLocator as FrameLocatorImpl
42+
from playwright._impl._api_classes import JSHandle as JSHandleImpl
43+
from playwright._impl._api_classes import Keyboard as KeyboardImpl
44+
from playwright._impl._api_classes import Locator as LocatorImpl
45+
from playwright._impl._api_classes import LocatorAssertions as LocatorAssertionsImpl
46+
from playwright._impl._api_classes import Mouse as MouseImpl
47+
from playwright._impl._api_classes import Page as PageImpl
48+
from playwright._impl._api_classes import PageAssertions as PageAssertionsImpl
49+
from playwright._impl._api_classes import Playwright as PlaywrightImpl
50+
from playwright._impl._api_classes import Request as RequestImpl
51+
from playwright._impl._api_classes import Response as ResponseImpl
52+
from playwright._impl._api_classes import Route as RouteImpl
53+
from playwright._impl._api_classes import Screencast as ScreencastImpl
54+
from playwright._impl._api_classes import Selectors as SelectorsImpl
55+
from playwright._impl._api_classes import Touchscreen as TouchscreenImpl
56+
from playwright._impl._api_classes import Tracing as TracingImpl
57+
from playwright._impl._api_classes import Video as VideoImpl
58+
from playwright._impl._api_classes import WebError as WebErrorImpl
59+
from playwright._impl._api_classes import WebMCP as WebMCPImpl
60+
from playwright._impl._api_classes import WebSocket as WebSocketImpl
61+
from playwright._impl._api_classes import WebSocketRoute as WebSocketRouteImpl
62+
from playwright._impl._api_classes import WebStorage as WebStorageImpl
63+
from playwright._impl._api_classes import Worker as WorkerImpl
2164
from playwright._impl._api_structures import (
2265
BrowserBindResult,
2366
ClientCertificate,
@@ -53,58 +96,15 @@
5396
WebMCPTool,
5497
WebStorageItem,
5598
)
56-
from playwright._impl._assertions import (
57-
APIResponseAssertions as APIResponseAssertionsImpl,
58-
)
59-
from playwright._impl._assertions import LocatorAssertions as LocatorAssertionsImpl
60-
from playwright._impl._assertions import PageAssertions as PageAssertionsImpl
61-
from playwright._impl._browser import Browser as BrowserImpl
62-
from playwright._impl._browser_context import BrowserContext as BrowserContextImpl
63-
from playwright._impl._browser_type import BrowserType as BrowserTypeImpl
64-
from playwright._impl._cdp_session import CDPSession as CDPSessionImpl
65-
from playwright._impl._clock import Clock as ClockImpl
66-
from playwright._impl._console_message import ConsoleMessage as ConsoleMessageImpl
67-
from playwright._impl._credentials import Credentials as CredentialsImpl
68-
from playwright._impl._debugger import Debugger as DebuggerImpl
69-
from playwright._impl._dialog import Dialog as DialogImpl
70-
from playwright._impl._disposable import Disposable as DisposableImpl
71-
from playwright._impl._download import Download as DownloadImpl
72-
from playwright._impl._element_handle import ElementHandle as ElementHandleImpl
7399
from playwright._impl._errors import Error
74-
from playwright._impl._fetch import APIRequest as APIRequestImpl
75-
from playwright._impl._fetch import APIRequestContext as APIRequestContextImpl
76-
from playwright._impl._fetch import APIResponse as APIResponseImpl
77-
from playwright._impl._file_chooser import FileChooser as FileChooserImpl
78100
from playwright._impl._form_data import FormData
79-
from playwright._impl._frame import Frame as FrameImpl
80101
from playwright._impl._helper import to_milliseconds
81-
from playwright._impl._input import Keyboard as KeyboardImpl
82-
from playwright._impl._input import Mouse as MouseImpl
83-
from playwright._impl._input import Touchscreen as TouchscreenImpl
84-
from playwright._impl._js_handle import JSHandle as JSHandleImpl
85-
from playwright._impl._locator import FrameLocator as FrameLocatorImpl
86-
from playwright._impl._locator import Locator as LocatorImpl
87-
from playwright._impl._network import Request as RequestImpl
88-
from playwright._impl._network import Response as ResponseImpl
89-
from playwright._impl._network import Route as RouteImpl
90-
from playwright._impl._network import WebSocket as WebSocketImpl
91-
from playwright._impl._network import WebSocketRoute as WebSocketRouteImpl
92-
from playwright._impl._page import Page as PageImpl
93-
from playwright._impl._page import Worker as WorkerImpl
94-
from playwright._impl._playwright import Playwright as PlaywrightImpl
95-
from playwright._impl._screencast import Screencast as ScreencastImpl
96-
from playwright._impl._selectors import Selectors as SelectorsImpl
97102
from playwright._impl._sync_base import (
98103
EventContextManager,
99104
SyncBase,
100105
SyncContextManager,
101106
mapping,
102107
)
103-
from playwright._impl._tracing import Tracing as TracingImpl
104-
from playwright._impl._video import Video as VideoImpl
105-
from playwright._impl._web_error import WebError as WebErrorImpl
106-
from playwright._impl._web_storage import WebStorage as WebStorageImpl
107-
from playwright._impl._webmcp import WebMCP as WebMCPImpl
108108

109109

110110
class APIRequest(SyncBase):

‎scripts/codegen/generate_api.js‎

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -821,11 +821,6 @@ const LICENSE = `# Copyright (c) Microsoft Corporation.
821821
# limitations under the License.
822822
`;
823823

824-
/** @param {string} className */
825-
function implModule(className) {
826-
return lookupRule('implModules', className) || `_${toSnakeCase(className)}`;
827-
}
828-
829824
/** @param {any} event */
830825
function eventPayload(clazz, event) {
831826
let payload = docType(toPy(event.type, { dir: 'out', place: `${clazz.name}.${event.name}` }));
@@ -1104,7 +1099,7 @@ function emitStructs() {
11041099
}
11051100

11061101
function checkRules() {
1107-
for (const table of ['extraMembers', 'extraOptions', 'structTotal', 'implModules']) {
1102+
for (const table of ['extraMembers', 'extraOptions', 'structTotal']) {
11081103
for (const key of Object.keys(/** @type {any} */ (rules)[table])) {
11091104
if (!usedRules.has(`${table}:${key}`))
11101105
errors.push(`${table}: the entry "${key}" no longer matches anything; remove it`);
@@ -1128,7 +1123,7 @@ function main() {
11281123
if (usedStructs.size)
11291124
header.push(`from playwright._impl._api_structures import ${[...usedStructs].sort().join(', ')}`);
11301125
for (const clazz of classes)
1131-
header.push(`from playwright._impl.${implModule(clazz.name)} import ${clazz.name} as ${clazz.name}Impl`);
1126+
header.push(`from playwright._impl._api_classes import ${clazz.name} as ${clazz.name}Impl`);
11321127
header.push('from playwright._impl._errors import Error');
11331128
header.push('from playwright._impl._form_data import FormData');
11341129
header.push('from playwright._impl._helper import to_milliseconds');

0 commit comments

Comments
 (0)