playwright-browserstack 1.62.0__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. playwright/__init__.py +19 -0
  2. playwright/__main__.py +33 -0
  3. playwright/_impl/__init__.py +0 -0
  4. playwright/_impl/__pyinstaller/__init__.py +20 -0
  5. playwright/_impl/__pyinstaller/hook-playwright.async_api.py +17 -0
  6. playwright/_impl/__pyinstaller/hook-playwright.sync_api.py +17 -0
  7. playwright/_impl/_android.py +704 -0
  8. playwright/_impl/_api_structures.py +365 -0
  9. playwright/_impl/_artifact.py +87 -0
  10. playwright/_impl/_assertions.py +1124 -0
  11. playwright/_impl/_async_base.py +105 -0
  12. playwright/_impl/_browser.py +293 -0
  13. playwright/_impl/_browser_context.py +754 -0
  14. playwright/_impl/_browser_type.py +368 -0
  15. playwright/_impl/_cdp_session.py +46 -0
  16. playwright/_impl/_clock.py +104 -0
  17. playwright/_impl/_connection.py +764 -0
  18. playwright/_impl/_console_message.py +98 -0
  19. playwright/_impl/_credentials.py +57 -0
  20. playwright/_impl/_debugger.py +54 -0
  21. playwright/_impl/_dialog.py +63 -0
  22. playwright/_impl/_disposable.py +96 -0
  23. playwright/_impl/_download.py +64 -0
  24. playwright/_impl/_driver.py +41 -0
  25. playwright/_impl/_element_handle.py +480 -0
  26. playwright/_impl/_errors.py +64 -0
  27. playwright/_impl/_event_context_manager.py +33 -0
  28. playwright/_impl/_fetch.py +626 -0
  29. playwright/_impl/_file_chooser.py +57 -0
  30. playwright/_impl/_form_data.py +34 -0
  31. playwright/_impl/_frame.py +985 -0
  32. playwright/_impl/_glob.py +65 -0
  33. playwright/_impl/_greenlets.py +49 -0
  34. playwright/_impl/_har_router.py +122 -0
  35. playwright/_impl/_helper.py +601 -0
  36. playwright/_impl/_impl_to_api_mapping.py +158 -0
  37. playwright/_impl/_input.py +111 -0
  38. playwright/_impl/_js_handle.py +336 -0
  39. playwright/_impl/_json_pipe.py +97 -0
  40. playwright/_impl/_local_utils.py +95 -0
  41. playwright/_impl/_locator.py +1024 -0
  42. playwright/_impl/_map.py +31 -0
  43. playwright/_impl/_network.py +1017 -0
  44. playwright/_impl/_object_factory.py +116 -0
  45. playwright/_impl/_page.py +1637 -0
  46. playwright/_impl/_path_utils.py +27 -0
  47. playwright/_impl/_playwright.py +68 -0
  48. playwright/_impl/_screencast.py +177 -0
  49. playwright/_impl/_selectors.py +67 -0
  50. playwright/_impl/_set_input_files_helpers.py +158 -0
  51. playwright/_impl/_str_utils.py +76 -0
  52. playwright/_impl/_stream.py +46 -0
  53. playwright/_impl/_sync_base.py +151 -0
  54. playwright/_impl/_tracing.py +281 -0
  55. playwright/_impl/_transport.py +184 -0
  56. playwright/_impl/_video.py +56 -0
  57. playwright/_impl/_waiter.py +197 -0
  58. playwright/_impl/_web_error.py +48 -0
  59. playwright/_impl/_web_storage.py +58 -0
  60. playwright/_impl/_writable_stream.py +42 -0
  61. playwright/_repo_version.py +24 -0
  62. playwright/async_api/__init__.py +275 -0
  63. playwright/async_api/_android_generated.py +462 -0
  64. playwright/async_api/_context_manager.py +57 -0
  65. playwright/async_api/_generated.py +23875 -0
  66. playwright/driver/LICENSE +2946 -0
  67. playwright/driver/README.md +1 -0
  68. playwright/driver/node.exe +0 -0
  69. playwright/driver/package/LICENSE +202 -0
  70. playwright/driver/package/NOTICE +5 -0
  71. playwright/driver/package/README.md +3 -0
  72. playwright/driver/package/ThirdPartyNotices.txt +13 -0
  73. playwright/driver/package/bin/install_media_pack.ps1 +5 -0
  74. playwright/driver/package/bin/install_webkit_wsl.ps1 +33 -0
  75. playwright/driver/package/bin/reinstall_chrome_beta_linux.sh +42 -0
  76. playwright/driver/package/bin/reinstall_chrome_beta_mac.sh +13 -0
  77. playwright/driver/package/bin/reinstall_chrome_beta_win.ps1 +24 -0
  78. playwright/driver/package/bin/reinstall_chrome_stable_linux.sh +42 -0
  79. playwright/driver/package/bin/reinstall_chrome_stable_mac.sh +12 -0
  80. playwright/driver/package/bin/reinstall_chrome_stable_win.ps1 +24 -0
  81. playwright/driver/package/bin/reinstall_msedge_beta_linux.sh +48 -0
  82. playwright/driver/package/bin/reinstall_msedge_beta_mac.sh +11 -0
  83. playwright/driver/package/bin/reinstall_msedge_beta_win.ps1 +23 -0
  84. playwright/driver/package/bin/reinstall_msedge_dev_linux.sh +48 -0
  85. playwright/driver/package/bin/reinstall_msedge_dev_mac.sh +11 -0
  86. playwright/driver/package/bin/reinstall_msedge_dev_win.ps1 +23 -0
  87. playwright/driver/package/bin/reinstall_msedge_stable_linux.sh +48 -0
  88. playwright/driver/package/bin/reinstall_msedge_stable_mac.sh +11 -0
  89. playwright/driver/package/bin/reinstall_msedge_stable_win.ps1 +24 -0
  90. playwright/driver/package/browsers.json +75 -0
  91. playwright/driver/package/cli.js +21 -0
  92. playwright/driver/package/index.d.ts +17 -0
  93. playwright/driver/package/index.js +17 -0
  94. playwright/driver/package/index.mjs +28 -0
  95. playwright/driver/package/lib/bootstrap.js +88 -0
  96. playwright/driver/package/lib/coreBundle.js +74830 -0
  97. playwright/driver/package/lib/entry/cliDaemon.js +5 -0
  98. playwright/driver/package/lib/entry/dashboardApp.js +3 -0
  99. playwright/driver/package/lib/entry/mcp.js +10 -0
  100. playwright/driver/package/lib/entry/oopBrowserDownload.js +3 -0
  101. playwright/driver/package/lib/package.js +50 -0
  102. playwright/driver/package/lib/server/chromium/appIcon.png +0 -0
  103. playwright/driver/package/lib/server/electron/loader.js +118 -0
  104. playwright/driver/package/lib/serverRegistry.js +7347 -0
  105. playwright/driver/package/lib/serverRegistry.js.LICENSE +354 -0
  106. playwright/driver/package/lib/tools/cli-client/channelSessions.js +141 -0
  107. playwright/driver/package/lib/tools/cli-client/cli.js +6 -0
  108. playwright/driver/package/lib/tools/cli-client/help.json +708 -0
  109. playwright/driver/package/lib/tools/cli-client/minimist.js +128 -0
  110. playwright/driver/package/lib/tools/cli-client/output.js +343 -0
  111. playwright/driver/package/lib/tools/cli-client/program.js +404 -0
  112. playwright/driver/package/lib/tools/cli-client/registry.js +176 -0
  113. playwright/driver/package/lib/tools/cli-client/session.js +258 -0
  114. playwright/driver/package/lib/tools/dashboard/appIcon.png +0 -0
  115. playwright/driver/package/lib/tools/skills/playwright-cli/SKILL.md +420 -0
  116. playwright/driver/package/lib/tools/skills/playwright-cli/references/element-attributes.md +23 -0
  117. playwright/driver/package/lib/tools/skills/playwright-cli/references/playwright-tests.md +39 -0
  118. playwright/driver/package/lib/tools/skills/playwright-cli/references/request-mocking.md +87 -0
  119. playwright/driver/package/lib/tools/skills/playwright-cli/references/running-code.md +241 -0
  120. playwright/driver/package/lib/tools/skills/playwright-cli/references/session-management.md +225 -0
  121. playwright/driver/package/lib/tools/skills/playwright-cli/references/storage-state.md +275 -0
  122. playwright/driver/package/lib/tools/skills/playwright-cli/references/test-generation.md +433 -0
  123. playwright/driver/package/lib/tools/skills/playwright-cli/references/tracing.md +139 -0
  124. playwright/driver/package/lib/tools/skills/playwright-cli/references/video-recording.md +143 -0
  125. playwright/driver/package/lib/tools/skills/playwright-component-testing/SKILL.md +143 -0
  126. playwright/driver/package/lib/tools/skills/playwright-component-testing/references/gallery-spec.md +144 -0
  127. playwright/driver/package/lib/tools/skills/playwright-component-testing/references/migration.md +85 -0
  128. playwright/driver/package/lib/tools/skills/playwright-component-testing/references/react.md +67 -0
  129. playwright/driver/package/lib/tools/skills/playwright-component-testing/references/vue.md +75 -0
  130. playwright/driver/package/lib/tools/skills/playwright-trace/SKILL.md +171 -0
  131. playwright/driver/package/lib/tools/utils/extension.js +101 -0
  132. playwright/driver/package/lib/tools/utils/socketConnection.js +108 -0
  133. playwright/driver/package/lib/utilsBundle.js +90764 -0
  134. playwright/driver/package/lib/utilsBundle.js.LICENSE +2179 -0
  135. playwright/driver/package/lib/vite/dashboard/assets/codicon-DCmgc-ay.ttf +0 -0
  136. playwright/driver/package/lib/vite/dashboard/assets/firefox-1bWoP6pv.svg +1 -0
  137. playwright/driver/package/lib/vite/dashboard/assets/firefox-beta-k3eOH_eK.svg +1 -0
  138. playwright/driver/package/lib/vite/dashboard/assets/firefox-nightly-Cp5nfeDT.svg +1 -0
  139. playwright/driver/package/lib/vite/dashboard/assets/index-CyWAfh-p.js +11 -0
  140. playwright/driver/package/lib/vite/dashboard/assets/index-DhC616m4.css +1 -0
  141. playwright/driver/package/lib/vite/dashboard/assets/safari-na3_-uQk.svg +1 -0
  142. playwright/driver/package/lib/vite/dashboard/index.html +29 -0
  143. playwright/driver/package/lib/vite/dashboard/playwright-logo.svg +24 -0
  144. playwright/driver/package/lib/vite/htmlReport/index.html +16 -0
  145. playwright/driver/package/lib/vite/htmlReport/report.css +2 -0
  146. playwright/driver/package/lib/vite/htmlReport/report.js +32 -0
  147. playwright/driver/package/lib/vite/recorder/assets/codeMirrorModule--QdMvsKi.css +1 -0
  148. playwright/driver/package/lib/vite/recorder/assets/codeMirrorModule-CwYYHbcZ.js +32 -0
  149. playwright/driver/package/lib/vite/recorder/assets/codicon-DCmgc-ay.ttf +0 -0
  150. playwright/driver/package/lib/vite/recorder/assets/index-DYjdXIbE.js +129 -0
  151. playwright/driver/package/lib/vite/recorder/assets/index-l_lX622x.css +1 -0
  152. playwright/driver/package/lib/vite/recorder/index.html +29 -0
  153. playwright/driver/package/lib/vite/recorder/playwright-logo.svg +9 -0
  154. playwright/driver/package/lib/vite/traceViewer/assets/codeMirrorModule-By56iMx7.js +32 -0
  155. playwright/driver/package/lib/vite/traceViewer/assets/defaultSettingsView-B34OrIms.js +181 -0
  156. playwright/driver/package/lib/vite/traceViewer/assets/urlMatch-L3liM589.js +1 -0
  157. playwright/driver/package/lib/vite/traceViewer/assets/xtermModule-COQkjINf.js +7 -0
  158. playwright/driver/package/lib/vite/traceViewer/codeMirrorModule.-QdMvsKi.css +1 -0
  159. playwright/driver/package/lib/vite/traceViewer/codicon.DCmgc-ay.ttf +0 -0
  160. playwright/driver/package/lib/vite/traceViewer/defaultSettingsView.BLFoOugd.css +1 -0
  161. playwright/driver/package/lib/vite/traceViewer/index.B_TqY17P.css +1 -0
  162. playwright/driver/package/lib/vite/traceViewer/index.Dl36UVQT.js +1 -0
  163. playwright/driver/package/lib/vite/traceViewer/index.html +44 -0
  164. playwright/driver/package/lib/vite/traceViewer/manifest.webmanifest +16 -0
  165. playwright/driver/package/lib/vite/traceViewer/playwright-logo.svg +9 -0
  166. playwright/driver/package/lib/vite/traceViewer/snapshot.B_Jk1wbt.js +1 -0
  167. playwright/driver/package/lib/vite/traceViewer/snapshot.html +10 -0
  168. playwright/driver/package/lib/vite/traceViewer/sw.bundle.js +4 -0
  169. playwright/driver/package/lib/vite/traceViewer/uiMode.C7UW1sC9.css +1 -0
  170. playwright/driver/package/lib/vite/traceViewer/uiMode.D962mr9b.js +5 -0
  171. playwright/driver/package/lib/vite/traceViewer/uiMode.html +18 -0
  172. playwright/driver/package/lib/vite/traceViewer/xtermModule.kHJ-D0s7.css +1 -0
  173. playwright/driver/package/lib/webp_codec.LICENSE +173 -0
  174. playwright/driver/package/lib/webp_codec.wasm +0 -0
  175. playwright/driver/package/lib/xdg-open +1267 -0
  176. playwright/driver/package/package.json +34 -0
  177. playwright/driver/package/types/protocol.d.ts +24842 -0
  178. playwright/driver/package/types/structs.d.ts +47 -0
  179. playwright/driver/package/types/types.d.ts +26188 -0
  180. playwright/py.typed +0 -0
  181. playwright/sync_api/__init__.py +275 -0
  182. playwright/sync_api/_android_generated.py +494 -0
  183. playwright/sync_api/_context_manager.py +98 -0
  184. playwright/sync_api/_generated.py +24045 -0
  185. playwright_browserstack-1.62.0.dist-info/METADATA +82 -0
  186. playwright_browserstack-1.62.0.dist-info/RECORD +192 -0
  187. playwright_browserstack-1.62.0.dist-info/WHEEL +5 -0
  188. playwright_browserstack-1.62.0.dist-info/entry_points.txt +5 -0
  189. playwright_browserstack-1.62.0.dist-info/licenses/LICENSE +202 -0
  190. playwright_browserstack-1.62.0.dist-info/licenses/LICENSE.txt +51 -0
  191. playwright_browserstack-1.62.0.dist-info/licenses/NOTICE +18 -0
  192. playwright_browserstack-1.62.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1637 @@
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
+ import asyncio
16
+ import base64
17
+ import inspect
18
+ import re
19
+ import sys
20
+ from pathlib import Path
21
+ from types import SimpleNamespace
22
+ from typing import (
23
+ TYPE_CHECKING,
24
+ Any,
25
+ Awaitable,
26
+ Callable,
27
+ Dict,
28
+ List,
29
+ Literal,
30
+ Optional,
31
+ Pattern,
32
+ Sequence,
33
+ Union,
34
+ cast,
35
+ )
36
+
37
+ from playwright._impl._api_structures import (
38
+ AriaRole,
39
+ FilePayload,
40
+ FloatRect,
41
+ PdfMargins,
42
+ Position,
43
+ ViewportSize,
44
+ )
45
+ from playwright._impl._artifact import Artifact
46
+ from playwright._impl._clock import Clock
47
+ from playwright._impl._connection import (
48
+ ChannelOwner,
49
+ from_channel,
50
+ from_nullable_channel,
51
+ )
52
+ from playwright._impl._console_message import ConsoleMessage
53
+ from playwright._impl._disposable import Disposable, DisposableStub
54
+ from playwright._impl._download import Download
55
+ from playwright._impl._element_handle import ElementHandle, determine_screenshot_type
56
+ from playwright._impl._errors import Error, TargetClosedError, is_target_closed_error
57
+ from playwright._impl._event_context_manager import EventContextManagerImpl
58
+ from playwright._impl._file_chooser import FileChooser
59
+ from playwright._impl._frame import Frame
60
+ from playwright._impl._greenlets import LocatorHandlerGreenlet
61
+ from playwright._impl._har_router import HarRouter
62
+ from playwright._impl._helper import (
63
+ ColorScheme,
64
+ Contrast,
65
+ DocumentLoadState,
66
+ ForcedColors,
67
+ HarMode,
68
+ KeyboardModifier,
69
+ MouseButton,
70
+ ReducedMotion,
71
+ RouteFromHarNotFoundPolicy,
72
+ RouteHandler,
73
+ RouteHandlerCallback,
74
+ TimeoutSettings,
75
+ URLMatch,
76
+ URLMatchRequest,
77
+ URLMatchResponse,
78
+ WebSocketRouteHandlerCallback,
79
+ async_readfile,
80
+ async_writefile,
81
+ locals_to_params,
82
+ make_dirs_for_file,
83
+ parse_error,
84
+ serialize_error,
85
+ url_matches,
86
+ )
87
+ from playwright._impl._input import Keyboard, Mouse, Touchscreen
88
+ from playwright._impl._js_handle import (
89
+ JSHandle,
90
+ Serializable,
91
+ add_source_url_to_script,
92
+ parse_result,
93
+ serialize_argument,
94
+ )
95
+ from playwright._impl._network import (
96
+ Request,
97
+ Response,
98
+ Route,
99
+ WebSocketRoute,
100
+ WebSocketRouteHandler,
101
+ serialize_headers,
102
+ )
103
+ from playwright._impl._screencast import Screencast
104
+ from playwright._impl._video import Video
105
+ from playwright._impl._waiter import Waiter
106
+ from playwright._impl._web_storage import WebStorage
107
+
108
+ if TYPE_CHECKING: # pragma: no cover
109
+ from playwright._impl._browser_context import BrowserContext
110
+ from playwright._impl._fetch import APIRequestContext
111
+ from playwright._impl._locator import FrameLocator, Locator
112
+ from playwright._impl._network import WebSocket
113
+
114
+
115
+ class LocatorHandler:
116
+ locator: "Locator"
117
+ handler: Union[Callable[["Locator"], Any], Callable[..., Any]]
118
+ times: Union[int, None]
119
+
120
+ def __init__(
121
+ self, locator: "Locator", handler: Callable[..., Any], times: Union[int, None]
122
+ ) -> None:
123
+ self.locator = locator
124
+ self._handler = handler
125
+ self.times = times
126
+
127
+ def __call__(self) -> Any:
128
+ arg_count = len(inspect.signature(self._handler).parameters)
129
+ if arg_count == 0:
130
+ return self._handler()
131
+ return self._handler(self.locator)
132
+
133
+
134
+ class Page(ChannelOwner):
135
+ Events = SimpleNamespace(
136
+ Close="close",
137
+ Crash="crash",
138
+ Console="console",
139
+ Dialog="dialog",
140
+ Download="download",
141
+ FileChooser="filechooser",
142
+ DOMContentLoaded="domcontentloaded",
143
+ PageError="pageerror",
144
+ Request="request",
145
+ Response="response",
146
+ RequestFailed="requestfailed",
147
+ RequestFinished="requestfinished",
148
+ FrameAttached="frameattached",
149
+ FrameDetached="framedetached",
150
+ FrameNavigated="framenavigated",
151
+ Load="load",
152
+ Popup="popup",
153
+ WebSocket="websocket",
154
+ Worker="worker",
155
+ )
156
+ keyboard: Keyboard
157
+ mouse: Mouse
158
+ touchscreen: Touchscreen
159
+
160
+ def __init__(
161
+ self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
162
+ ) -> None:
163
+ super().__init__(parent, type, guid, initializer)
164
+ self._browser_context = cast("BrowserContext", parent)
165
+ self.keyboard = Keyboard(self._channel)
166
+ self.mouse = Mouse(self._channel)
167
+ self.touchscreen = Touchscreen(self._channel)
168
+
169
+ self._main_frame: Frame = from_channel(initializer["mainFrame"])
170
+ self._main_frame._page = self
171
+ self._frames = [self._main_frame]
172
+ self._viewport_size: Optional[ViewportSize] = initializer.get("viewportSize")
173
+ self._is_closed = False
174
+ self._workers: List["Worker"] = []
175
+ self._bindings: Dict[str, Any] = {}
176
+ self._routes: List[RouteHandler] = []
177
+ self._web_socket_routes: List[WebSocketRouteHandler] = []
178
+ self._owned_context: Optional["BrowserContext"] = None
179
+ self._timeout_settings: TimeoutSettings = TimeoutSettings(
180
+ self._browser_context._timeout_settings
181
+ )
182
+ self._video: Video = Video(
183
+ self,
184
+ cast(Optional[Artifact], from_nullable_channel(initializer.get("video"))),
185
+ )
186
+ self._screencast: Screencast = Screencast(self)
187
+ self._local_storage = WebStorage(self, "local")
188
+ self._session_storage = WebStorage(self, "session")
189
+ self._opener = cast("Page", from_nullable_channel(initializer.get("opener")))
190
+ self._close_reason: Optional[str] = None
191
+ self._close_was_called = False
192
+ self._har_routers: List[HarRouter] = []
193
+ self._locator_handlers: Dict[str, LocatorHandler] = {}
194
+
195
+ self._channel.on(
196
+ "bindingCall",
197
+ lambda params: self._on_binding(from_channel(params["binding"])),
198
+ )
199
+ self._channel.on("close", lambda _: self._on_close())
200
+ self._channel.on("crash", lambda _: self._on_crash())
201
+ self._channel.on("download", lambda params: self._on_download(params))
202
+ self._channel.on(
203
+ "fileChooser",
204
+ lambda params: self.emit(
205
+ Page.Events.FileChooser,
206
+ FileChooser(
207
+ self, from_channel(params["element"]), params["isMultiple"]
208
+ ),
209
+ ),
210
+ )
211
+ self._channel.on(
212
+ "frameAttached",
213
+ lambda params: self._on_frame_attached(from_channel(params["frame"])),
214
+ )
215
+ self._channel.on(
216
+ "frameDetached",
217
+ lambda params: self._on_frame_detached(from_channel(params["frame"])),
218
+ )
219
+ self._channel.on(
220
+ "locatorHandlerTriggered",
221
+ lambda params: self._loop.create_task(
222
+ self._on_locator_handler_triggered(params["uid"])
223
+ ),
224
+ )
225
+ self._channel.on(
226
+ "route",
227
+ lambda params: self._loop.create_task(
228
+ self._on_route(from_channel(params["route"]))
229
+ ),
230
+ )
231
+ self._channel.on(
232
+ "webSocketRoute",
233
+ lambda params: self._loop.create_task(
234
+ self._on_web_socket_route(from_channel(params["webSocketRoute"]))
235
+ ),
236
+ )
237
+ self._channel.on("viewportSizeChanged", self._on_viewport_size_changed)
238
+ self._channel.on(
239
+ "webSocket",
240
+ lambda params: self.emit(
241
+ Page.Events.WebSocket, from_channel(params["webSocket"])
242
+ ),
243
+ )
244
+ self._channel.on(
245
+ "worker", lambda params: self._on_worker(from_channel(params["worker"]))
246
+ )
247
+ self._closed_or_crashed_future: asyncio.Future = asyncio.Future()
248
+ self.on(
249
+ Page.Events.Close,
250
+ lambda _: (
251
+ self._closed_or_crashed_future.set_result(
252
+ self._close_error_with_reason()
253
+ )
254
+ if not self._closed_or_crashed_future.done()
255
+ else None
256
+ ),
257
+ )
258
+ self.on(
259
+ Page.Events.Crash,
260
+ lambda _: (
261
+ self._closed_or_crashed_future.set_result(TargetClosedError())
262
+ if not self._closed_or_crashed_future.done()
263
+ else None
264
+ ),
265
+ )
266
+
267
+ self._set_event_to_subscription_mapping(
268
+ {
269
+ Page.Events.Console: "console",
270
+ Page.Events.Dialog: "dialog",
271
+ Page.Events.Request: "request",
272
+ Page.Events.Response: "response",
273
+ Page.Events.RequestFinished: "requestFinished",
274
+ Page.Events.RequestFailed: "requestFailed",
275
+ Page.Events.FileChooser: "fileChooser",
276
+ }
277
+ )
278
+
279
+ def __repr__(self) -> str:
280
+ return f"<Page url={self.url!r}>"
281
+
282
+ def _on_frame_attached(self, frame: Frame) -> None:
283
+ frame._page = self
284
+ self._frames.append(frame)
285
+ self.emit(Page.Events.FrameAttached, frame)
286
+ self._browser_context.emit("frameattached", frame)
287
+
288
+ def _on_frame_detached(self, frame: Frame) -> None:
289
+ self._frames.remove(frame)
290
+ frame._detached = True
291
+ self.emit(Page.Events.FrameDetached, frame)
292
+ self._browser_context.emit("framedetached", frame)
293
+
294
+ async def _on_route(self, route: Route) -> None:
295
+ route._context = self.context
296
+ route_handlers = self._routes.copy()
297
+ for route_handler in route_handlers:
298
+ # If the page was closed we stall all requests right away.
299
+ if self._close_was_called or self.context._closing_or_closed:
300
+ return
301
+ if not route_handler.matches(route.request.url):
302
+ continue
303
+ if route_handler not in self._routes:
304
+ continue
305
+ if route_handler.will_expire:
306
+ self._routes.remove(route_handler)
307
+ try:
308
+ handled = await route_handler.handle(route)
309
+ finally:
310
+ if len(self._routes) == 0:
311
+
312
+ async def _update_interceptor_patterns_ignore_exceptions() -> None:
313
+ try:
314
+ await self._update_interception_patterns()
315
+ except Error:
316
+ pass
317
+
318
+ asyncio.create_task(
319
+ self._connection.wrap_api_call(
320
+ _update_interceptor_patterns_ignore_exceptions, True
321
+ )
322
+ )
323
+ if handled:
324
+ return
325
+ await self._browser_context._on_route(route)
326
+
327
+ async def _on_web_socket_route(self, web_socket_route: WebSocketRoute) -> None:
328
+ route_handler = next(
329
+ (
330
+ route_handler
331
+ for route_handler in self._web_socket_routes
332
+ if route_handler.matches(web_socket_route.url)
333
+ ),
334
+ None,
335
+ )
336
+ if route_handler:
337
+ await route_handler.handle(web_socket_route)
338
+ else:
339
+ await self._browser_context._on_web_socket_route(web_socket_route)
340
+
341
+ def _on_binding(self, binding_call: "BindingCall") -> None:
342
+ func = self._bindings.get(binding_call._initializer["name"])
343
+ if func:
344
+ asyncio.create_task(binding_call.call(func))
345
+ self._browser_context._on_binding(binding_call)
346
+
347
+ def _on_worker(self, worker: "Worker") -> None:
348
+ self._workers.append(worker)
349
+ worker._page = self
350
+ self.emit(Page.Events.Worker, worker)
351
+
352
+ def _on_close(self) -> None:
353
+ self._is_closed = True
354
+ if self in self._browser_context._pages:
355
+ self._browser_context._pages.remove(self)
356
+ self._dispose_har_routers()
357
+ self.emit(Page.Events.Close, self)
358
+ self._browser_context.emit("pageclose", self)
359
+
360
+ def _on_crash(self) -> None:
361
+ self.emit(Page.Events.Crash, self)
362
+
363
+ def _on_download(self, params: Any) -> None:
364
+ url = params["url"]
365
+ suggested_filename = params["suggestedFilename"]
366
+ artifact = cast(Artifact, from_channel(params["artifact"]))
367
+ download = Download(self, url, suggested_filename, artifact)
368
+ self.emit(Page.Events.Download, download)
369
+ self._browser_context.emit("download", download)
370
+
371
+ def _on_viewport_size_changed(self, params: Any) -> None:
372
+ self._viewport_size = params["viewportSize"]
373
+
374
+ @property
375
+ def context(self) -> "BrowserContext":
376
+ return self._browser_context
377
+
378
+ @property
379
+ def clock(self) -> Clock:
380
+ return self._browser_context.clock
381
+
382
+ async def opener(self) -> Optional["Page"]:
383
+ if self._opener and self._opener.is_closed():
384
+ return None
385
+ return self._opener
386
+
387
+ @property
388
+ def main_frame(self) -> Frame:
389
+ return self._main_frame
390
+
391
+ def frame(self, name: str = None, url: URLMatch = None) -> Optional[Frame]:
392
+ for frame in self._frames:
393
+ if name and frame.name == name:
394
+ return frame
395
+ if url and url_matches(self._browser_context._base_url, frame.url, url):
396
+ return frame
397
+
398
+ return None
399
+
400
+ @property
401
+ def frames(self) -> List[Frame]:
402
+ return self._frames.copy()
403
+
404
+ def set_default_navigation_timeout(self, timeout: float) -> None:
405
+ self._timeout_settings.set_default_navigation_timeout(timeout)
406
+
407
+ def set_default_timeout(self, timeout: float) -> None:
408
+ self._timeout_settings.set_default_timeout(timeout)
409
+
410
+ async def query_selector(
411
+ self,
412
+ selector: str,
413
+ strict: bool = None,
414
+ ) -> Optional[ElementHandle]:
415
+ return await self._main_frame.query_selector(selector, strict)
416
+
417
+ async def query_selector_all(self, selector: str) -> List[ElementHandle]:
418
+ return await self._main_frame.query_selector_all(selector)
419
+
420
+ async def wait_for_selector(
421
+ self,
422
+ selector: str,
423
+ timeout: float = None,
424
+ state: Literal["attached", "detached", "hidden", "visible"] = None,
425
+ strict: bool = None,
426
+ ) -> Optional[ElementHandle]:
427
+ return await self._main_frame.wait_for_selector(**locals_to_params(locals()))
428
+
429
+ async def is_checked(
430
+ self, selector: str, strict: bool = None, timeout: float = None
431
+ ) -> bool:
432
+ return await self._main_frame.is_checked(**locals_to_params(locals()))
433
+
434
+ async def is_disabled(
435
+ self, selector: str, strict: bool = None, timeout: float = None
436
+ ) -> bool:
437
+ return await self._main_frame.is_disabled(**locals_to_params(locals()))
438
+
439
+ async def is_editable(
440
+ self, selector: str, strict: bool = None, timeout: float = None
441
+ ) -> bool:
442
+ return await self._main_frame.is_editable(**locals_to_params(locals()))
443
+
444
+ async def is_enabled(
445
+ self, selector: str, strict: bool = None, timeout: float = None
446
+ ) -> bool:
447
+ return await self._main_frame.is_enabled(**locals_to_params(locals()))
448
+
449
+ async def is_hidden(
450
+ self, selector: str, strict: bool = None, timeout: float = None
451
+ ) -> bool:
452
+ # timeout is deprecated and does nothing
453
+ return await self._main_frame.is_hidden(selector=selector, strict=strict)
454
+
455
+ async def is_visible(
456
+ self, selector: str, strict: bool = None, timeout: float = None
457
+ ) -> bool:
458
+ # timeout is deprecated and does nothing
459
+ return await self._main_frame.is_visible(selector=selector, strict=strict)
460
+
461
+ async def dispatch_event(
462
+ self,
463
+ selector: str,
464
+ type: str,
465
+ eventInit: Dict = None,
466
+ timeout: float = None,
467
+ strict: bool = None,
468
+ ) -> None:
469
+ return await self._main_frame.dispatch_event(**locals_to_params(locals()))
470
+
471
+ async def evaluate(self, expression: str, arg: Serializable = None) -> Any:
472
+ return await self._main_frame.evaluate(expression, arg)
473
+
474
+ async def evaluate_handle(
475
+ self, expression: str, arg: Serializable = None
476
+ ) -> JSHandle:
477
+ return await self._main_frame.evaluate_handle(expression, arg)
478
+
479
+ async def eval_on_selector(
480
+ self,
481
+ selector: str,
482
+ expression: str,
483
+ arg: Serializable = None,
484
+ strict: bool = None,
485
+ ) -> Any:
486
+ return await self._main_frame.eval_on_selector(
487
+ selector, expression, arg, strict
488
+ )
489
+
490
+ async def eval_on_selector_all(
491
+ self,
492
+ selector: str,
493
+ expression: str,
494
+ arg: Serializable = None,
495
+ ) -> Any:
496
+ return await self._main_frame.eval_on_selector_all(selector, expression, arg)
497
+
498
+ async def add_script_tag(
499
+ self,
500
+ url: str = None,
501
+ path: Union[str, Path] = None,
502
+ content: str = None,
503
+ type: str = None,
504
+ ) -> ElementHandle:
505
+ return await self._main_frame.add_script_tag(**locals_to_params(locals()))
506
+
507
+ async def add_style_tag(
508
+ self, url: str = None, path: Union[str, Path] = None, content: str = None
509
+ ) -> ElementHandle:
510
+ return await self._main_frame.add_style_tag(**locals_to_params(locals()))
511
+
512
+ async def expose_function(self, name: str, callback: Callable) -> Disposable:
513
+ return await self.expose_binding(name, lambda source, *args: callback(*args))
514
+
515
+ async def expose_binding(self, name: str, callback: Callable) -> Disposable:
516
+ if name in self._bindings:
517
+ raise Error(f'Function "{name}" has been already registered')
518
+ if name in self._browser_context._bindings:
519
+ raise Error(
520
+ f'Function "{name}" has been already registered in the browser context'
521
+ )
522
+ self._bindings[name] = callback
523
+ return from_channel(
524
+ await self._channel.send(
525
+ "exposeBinding",
526
+ None,
527
+ dict(name=name),
528
+ )
529
+ )
530
+
531
+ async def set_extra_http_headers(self, headers: Dict[str, str]) -> None:
532
+ await self._channel.send(
533
+ "setExtraHTTPHeaders",
534
+ None,
535
+ dict(headers=serialize_headers(headers)),
536
+ )
537
+
538
+ @property
539
+ def url(self) -> str:
540
+ return self._main_frame.url
541
+
542
+ async def content(self) -> str:
543
+ return await self._main_frame.content()
544
+
545
+ async def set_content(
546
+ self,
547
+ html: str,
548
+ timeout: float = None,
549
+ waitUntil: DocumentLoadState = None,
550
+ ) -> None:
551
+ return await self._main_frame.set_content(**locals_to_params(locals()))
552
+
553
+ async def goto(
554
+ self,
555
+ url: str,
556
+ timeout: float = None,
557
+ waitUntil: DocumentLoadState = None,
558
+ referer: str = None,
559
+ ) -> Optional[Response]:
560
+ return await self._main_frame.goto(**locals_to_params(locals()))
561
+
562
+ async def reload(
563
+ self,
564
+ timeout: float = None,
565
+ waitUntil: DocumentLoadState = None,
566
+ ) -> Optional[Response]:
567
+ return from_nullable_channel(
568
+ await self._channel.send(
569
+ "reload",
570
+ self._timeout_settings.navigation_timeout,
571
+ locals_to_params(locals()),
572
+ )
573
+ )
574
+
575
+ async def wait_for_load_state(
576
+ self,
577
+ state: Literal["domcontentloaded", "load", "networkidle"] = None,
578
+ timeout: float = None,
579
+ ) -> None:
580
+ return await self._main_frame.wait_for_load_state(**locals_to_params(locals()))
581
+
582
+ async def wait_for_url(
583
+ self,
584
+ url: URLMatch,
585
+ waitUntil: DocumentLoadState = None,
586
+ timeout: float = None,
587
+ ) -> None:
588
+ return await self._main_frame.wait_for_url(**locals_to_params(locals()))
589
+
590
+ async def wait_for_event(
591
+ self, event: str, predicate: Callable = None, timeout: float = None
592
+ ) -> Any:
593
+ async with self.expect_event(event, predicate, timeout) as event_info:
594
+ pass
595
+ return await event_info
596
+
597
+ async def go_back(
598
+ self,
599
+ timeout: float = None,
600
+ waitUntil: DocumentLoadState = None,
601
+ ) -> Optional[Response]:
602
+ return from_nullable_channel(
603
+ await self._channel.send(
604
+ "goBack",
605
+ self._timeout_settings.navigation_timeout,
606
+ locals_to_params(locals()),
607
+ )
608
+ )
609
+
610
+ async def go_forward(
611
+ self,
612
+ timeout: float = None,
613
+ waitUntil: DocumentLoadState = None,
614
+ ) -> Optional[Response]:
615
+ return from_nullable_channel(
616
+ await self._channel.send(
617
+ "goForward",
618
+ self._timeout_settings.navigation_timeout,
619
+ locals_to_params(locals()),
620
+ )
621
+ )
622
+
623
+ async def request_gc(self) -> None:
624
+ await self._channel.send("requestGC", None)
625
+
626
+ async def emulate_media(
627
+ self,
628
+ media: Literal["null", "print", "screen"] = None,
629
+ colorScheme: ColorScheme = None,
630
+ reducedMotion: ReducedMotion = None,
631
+ forcedColors: ForcedColors = None,
632
+ contrast: Contrast = None,
633
+ ) -> None:
634
+ params = locals_to_params(locals())
635
+ if "media" in params:
636
+ params["media"] = "no-override" if params["media"] == "null" else media
637
+ if "colorScheme" in params:
638
+ params["colorScheme"] = (
639
+ "no-override" if params["colorScheme"] == "null" else colorScheme
640
+ )
641
+ if "reducedMotion" in params:
642
+ params["reducedMotion"] = (
643
+ "no-override" if params["reducedMotion"] == "null" else reducedMotion
644
+ )
645
+ if "forcedColors" in params:
646
+ params["forcedColors"] = (
647
+ "no-override" if params["forcedColors"] == "null" else forcedColors
648
+ )
649
+ if "contrast" in params:
650
+ params["contrast"] = (
651
+ "no-override" if params["contrast"] == "null" else contrast
652
+ )
653
+ await self._channel.send("emulateMedia", None, params)
654
+
655
+ async def set_viewport_size(self, viewportSize: ViewportSize) -> None:
656
+ self._viewport_size = viewportSize
657
+ await self._channel.send(
658
+ "setViewportSize",
659
+ None,
660
+ locals_to_params(locals()),
661
+ )
662
+
663
+ @property
664
+ def viewport_size(self) -> Optional[ViewportSize]:
665
+ return self._viewport_size
666
+
667
+ async def bring_to_front(self) -> None:
668
+ await self._channel.send("bringToFront", None)
669
+
670
+ async def hide_highlight(self) -> None:
671
+ await self._channel.send("hideHighlight", None)
672
+
673
+ async def add_init_script(
674
+ self, script: str = None, path: Union[str, Path] = None
675
+ ) -> Disposable:
676
+ if path:
677
+ script = add_source_url_to_script(
678
+ (await async_readfile(path)).decode(), path
679
+ )
680
+ if not isinstance(script, str):
681
+ raise Error("Either path or script parameter must be specified")
682
+ return from_channel(
683
+ await self._channel.send("addInitScript", None, dict(source=script))
684
+ )
685
+
686
+ async def route(
687
+ self, url: URLMatch, handler: RouteHandlerCallback, times: int = None
688
+ ) -> DisposableStub:
689
+ self._routes.insert(
690
+ 0,
691
+ RouteHandler(
692
+ self._browser_context._base_url,
693
+ url,
694
+ handler,
695
+ True if self._dispatcher_fiber else False,
696
+ times,
697
+ ),
698
+ )
699
+ await self._update_interception_patterns()
700
+ return DisposableStub(lambda: self.unroute(url, handler), self)
701
+
702
+ async def unroute(
703
+ self, url: URLMatch, handler: Optional[RouteHandlerCallback] = None
704
+ ) -> None:
705
+ removed = []
706
+ remaining = []
707
+ for route in self._routes:
708
+ if route.url != url or (handler and route.handler != handler):
709
+ remaining.append(route)
710
+ else:
711
+ removed.append(route)
712
+ await self._unroute_internal(removed, remaining, "default")
713
+
714
+ async def _unroute_internal(
715
+ self,
716
+ removed: List[RouteHandler],
717
+ remaining: List[RouteHandler],
718
+ behavior: Literal["default", "ignoreErrors", "wait"] = None,
719
+ ) -> None:
720
+ self._routes = remaining
721
+ if behavior is not None and behavior != "default":
722
+ await asyncio.gather(
723
+ *map(
724
+ lambda route: route.stop(behavior), # type: ignore
725
+ removed,
726
+ )
727
+ )
728
+ await self._update_interception_patterns()
729
+
730
+ async def route_web_socket(
731
+ self, url: URLMatch, handler: WebSocketRouteHandlerCallback
732
+ ) -> None:
733
+ self._web_socket_routes.insert(
734
+ 0,
735
+ WebSocketRouteHandler(self._browser_context._base_url, url, handler),
736
+ )
737
+ await self._update_web_socket_interception_patterns()
738
+
739
+ def _dispose_har_routers(self) -> None:
740
+ for router in self._har_routers:
741
+ router.dispose()
742
+ self._har_routers = []
743
+
744
+ async def unroute_all(
745
+ self, behavior: Literal["default", "ignoreErrors", "wait"] = None
746
+ ) -> None:
747
+ await self._unroute_internal(self._routes, [], behavior)
748
+ self._dispose_har_routers()
749
+
750
+ async def route_from_har(
751
+ self,
752
+ har: Union[Path, str],
753
+ url: Union[Pattern[str], str] = None,
754
+ notFound: RouteFromHarNotFoundPolicy = None,
755
+ update: bool = None,
756
+ updateContent: Literal["attach", "embed"] = None,
757
+ updateMode: HarMode = None,
758
+ ) -> None:
759
+ if update:
760
+ await self._browser_context._tracing._record_into_har(
761
+ har=har,
762
+ page=self,
763
+ url=url,
764
+ update_content=updateContent,
765
+ update_mode=updateMode,
766
+ )
767
+ return
768
+ router = await HarRouter.create(
769
+ local_utils=self._connection.local_utils,
770
+ file=str(har),
771
+ not_found_action=notFound or "abort",
772
+ url_matcher=url,
773
+ )
774
+ self._har_routers.append(router)
775
+ await router.add_page_route(self)
776
+
777
+ async def _update_interception_patterns(self) -> None:
778
+ patterns = RouteHandler.prepare_interception_patterns(self._routes)
779
+ await self._channel.send(
780
+ "setNetworkInterceptionPatterns",
781
+ None,
782
+ {"patterns": patterns},
783
+ )
784
+
785
+ async def _update_web_socket_interception_patterns(self) -> None:
786
+ patterns = WebSocketRouteHandler.prepare_interception_patterns(
787
+ self._web_socket_routes
788
+ )
789
+ await self._channel.send(
790
+ "setWebSocketInterceptionPatterns",
791
+ None,
792
+ {"patterns": patterns},
793
+ )
794
+
795
+ async def screenshot(
796
+ self,
797
+ timeout: float = None,
798
+ type: Literal["jpeg", "png", "webp"] = None,
799
+ path: Union[str, Path] = None,
800
+ quality: int = None,
801
+ omitBackground: bool = None,
802
+ fullPage: bool = None,
803
+ clip: FloatRect = None,
804
+ animations: Literal["allow", "disabled"] = None,
805
+ caret: Literal["hide", "initial"] = None,
806
+ scale: Literal["css", "device"] = None,
807
+ mask: Sequence["Locator"] = None,
808
+ maskColor: str = None,
809
+ style: str = None,
810
+ ) -> bytes:
811
+ params = locals_to_params(locals())
812
+ if "path" in params:
813
+ if "type" not in params:
814
+ params["type"] = determine_screenshot_type(params["path"])
815
+ del params["path"]
816
+ if "mask" in params:
817
+ params["mask"] = list(
818
+ map(
819
+ lambda locator: (
820
+ {
821
+ "frame": locator._frame._channel,
822
+ "selector": locator._selector,
823
+ }
824
+ ),
825
+ params["mask"],
826
+ )
827
+ )
828
+ encoded_binary = await self._channel.send(
829
+ "screenshot", self._timeout_settings.timeout, params
830
+ )
831
+ decoded_binary = base64.b64decode(encoded_binary)
832
+ if path:
833
+ make_dirs_for_file(path)
834
+ await async_writefile(path, decoded_binary)
835
+ return decoded_binary
836
+
837
+ async def title(self) -> str:
838
+ return await self._main_frame.title()
839
+
840
+ async def aria_snapshot(
841
+ self,
842
+ timeout: float = None,
843
+ depth: int = None,
844
+ mode: Literal["ai", "default"] = None,
845
+ boxes: bool = None,
846
+ ) -> str:
847
+ return await self._main_frame._channel.send(
848
+ "ariaSnapshot",
849
+ self._main_frame._timeout,
850
+ locals_to_params(locals()),
851
+ )
852
+
853
+ async def close(self, runBeforeUnload: bool = None, reason: str = None) -> None:
854
+ self._close_reason = reason
855
+ if not runBeforeUnload:
856
+ self._close_was_called = True
857
+ try:
858
+ if self._owned_context:
859
+ await self._owned_context.close()
860
+ elif runBeforeUnload:
861
+ await self._channel.send("runBeforeUnload", None)
862
+ else:
863
+ await self._channel.send("close", None, {"reason": reason})
864
+ except Exception as e:
865
+ if is_target_closed_error(e) and not runBeforeUnload:
866
+ return
867
+ raise e
868
+
869
+ def is_closed(self) -> bool:
870
+ return self._is_closed
871
+
872
+ async def click(
873
+ self,
874
+ selector: str,
875
+ modifiers: Sequence[KeyboardModifier] = None,
876
+ position: Position = None,
877
+ delay: float = None,
878
+ button: MouseButton = None,
879
+ clickCount: int = None,
880
+ timeout: float = None,
881
+ force: bool = None,
882
+ noWaitAfter: bool = None,
883
+ trial: bool = None,
884
+ strict: bool = None,
885
+ scroll: Literal["auto", "none"] = None,
886
+ ) -> None:
887
+ return await self._main_frame._click(**locals_to_params(locals()))
888
+
889
+ async def dblclick(
890
+ self,
891
+ selector: str,
892
+ modifiers: Sequence[KeyboardModifier] = None,
893
+ position: Position = None,
894
+ delay: float = None,
895
+ button: MouseButton = None,
896
+ timeout: float = None,
897
+ force: bool = None,
898
+ noWaitAfter: bool = None,
899
+ strict: bool = None,
900
+ trial: bool = None,
901
+ scroll: Literal["auto", "none"] = None,
902
+ ) -> None:
903
+ return await self._main_frame.dblclick(**locals_to_params(locals()))
904
+
905
+ async def tap(
906
+ self,
907
+ selector: str,
908
+ modifiers: Sequence[KeyboardModifier] = None,
909
+ position: Position = None,
910
+ timeout: float = None,
911
+ force: bool = None,
912
+ noWaitAfter: bool = None,
913
+ strict: bool = None,
914
+ trial: bool = None,
915
+ scroll: Literal["auto", "none"] = None,
916
+ ) -> None:
917
+ return await self._main_frame.tap(**locals_to_params(locals()))
918
+
919
+ async def fill(
920
+ self,
921
+ selector: str,
922
+ value: str,
923
+ timeout: float = None,
924
+ noWaitAfter: bool = None,
925
+ strict: bool = None,
926
+ force: bool = None,
927
+ ) -> None:
928
+ return await self._main_frame.fill(**locals_to_params(locals()))
929
+
930
+ def locator(
931
+ self,
932
+ selector: str,
933
+ hasText: Union[str, Pattern[str]] = None,
934
+ hasNotText: Union[str, Pattern[str]] = None,
935
+ has: "Locator" = None,
936
+ hasNot: "Locator" = None,
937
+ ) -> "Locator":
938
+ return self._main_frame.locator(
939
+ selector,
940
+ hasText=hasText,
941
+ hasNotText=hasNotText,
942
+ has=has,
943
+ hasNot=hasNot,
944
+ )
945
+
946
+ def get_by_alt_text(
947
+ self, text: Union[str, Pattern[str]], exact: bool = None
948
+ ) -> "Locator":
949
+ return self._main_frame.get_by_alt_text(text, exact=exact)
950
+
951
+ def get_by_label(
952
+ self, text: Union[str, Pattern[str]], exact: bool = None
953
+ ) -> "Locator":
954
+ return self._main_frame.get_by_label(text, exact=exact)
955
+
956
+ def get_by_placeholder(
957
+ self, text: Union[str, Pattern[str]], exact: bool = None
958
+ ) -> "Locator":
959
+ return self._main_frame.get_by_placeholder(text, exact=exact)
960
+
961
+ def get_by_role(
962
+ self,
963
+ role: AriaRole,
964
+ checked: bool = None,
965
+ disabled: bool = None,
966
+ expanded: bool = None,
967
+ includeHidden: bool = None,
968
+ level: int = None,
969
+ name: Union[str, Pattern[str]] = None,
970
+ pressed: bool = None,
971
+ selected: bool = None,
972
+ exact: bool = None,
973
+ description: Union[str, Pattern[str]] = None,
974
+ ) -> "Locator":
975
+ return self._main_frame.get_by_role(
976
+ role,
977
+ checked=checked,
978
+ disabled=disabled,
979
+ expanded=expanded,
980
+ includeHidden=includeHidden,
981
+ level=level,
982
+ name=name,
983
+ pressed=pressed,
984
+ selected=selected,
985
+ exact=exact,
986
+ description=description,
987
+ )
988
+
989
+ def get_by_test_id(self, testId: Union[str, Pattern[str]]) -> "Locator":
990
+ return self._main_frame.get_by_test_id(testId)
991
+
992
+ def get_by_text(
993
+ self, text: Union[str, Pattern[str]], exact: bool = None
994
+ ) -> "Locator":
995
+ return self._main_frame.get_by_text(text, exact=exact)
996
+
997
+ def get_by_title(
998
+ self, text: Union[str, Pattern[str]], exact: bool = None
999
+ ) -> "Locator":
1000
+ return self._main_frame.get_by_title(text, exact=exact)
1001
+
1002
+ def frame_locator(self, selector: str) -> "FrameLocator":
1003
+ return self.main_frame.frame_locator(selector)
1004
+
1005
+ async def focus(
1006
+ self, selector: str, strict: bool = None, timeout: float = None
1007
+ ) -> None:
1008
+ return await self._main_frame.focus(**locals_to_params(locals()))
1009
+
1010
+ async def text_content(
1011
+ self, selector: str, strict: bool = None, timeout: float = None
1012
+ ) -> Optional[str]:
1013
+ return await self._main_frame.text_content(**locals_to_params(locals()))
1014
+
1015
+ async def inner_text(
1016
+ self, selector: str, strict: bool = None, timeout: float = None
1017
+ ) -> str:
1018
+ return await self._main_frame.inner_text(**locals_to_params(locals()))
1019
+
1020
+ async def inner_html(
1021
+ self, selector: str, strict: bool = None, timeout: float = None
1022
+ ) -> str:
1023
+ return await self._main_frame.inner_html(**locals_to_params(locals()))
1024
+
1025
+ async def get_attribute(
1026
+ self, selector: str, name: str, strict: bool = None, timeout: float = None
1027
+ ) -> Optional[str]:
1028
+ return await self._main_frame.get_attribute(**locals_to_params(locals()))
1029
+
1030
+ async def hover(
1031
+ self,
1032
+ selector: str,
1033
+ modifiers: Sequence[KeyboardModifier] = None,
1034
+ position: Position = None,
1035
+ timeout: float = None,
1036
+ noWaitAfter: bool = None,
1037
+ force: bool = None,
1038
+ strict: bool = None,
1039
+ trial: bool = None,
1040
+ scroll: Literal["auto", "none"] = None,
1041
+ ) -> None:
1042
+ return await self._main_frame.hover(**locals_to_params(locals()))
1043
+
1044
+ async def drag_and_drop(
1045
+ self,
1046
+ source: str,
1047
+ target: str,
1048
+ sourcePosition: Position = None,
1049
+ targetPosition: Position = None,
1050
+ force: bool = None,
1051
+ noWaitAfter: bool = None,
1052
+ timeout: float = None,
1053
+ strict: bool = None,
1054
+ trial: bool = None,
1055
+ steps: int = None,
1056
+ scroll: Literal["auto", "none"] = None,
1057
+ ) -> None:
1058
+ return await self._main_frame.drag_and_drop(**locals_to_params(locals()))
1059
+
1060
+ async def select_option(
1061
+ self,
1062
+ selector: str,
1063
+ value: Union[str, Sequence[str]] = None,
1064
+ index: Union[int, Sequence[int]] = None,
1065
+ label: Union[str, Sequence[str]] = None,
1066
+ element: Union["ElementHandle", Sequence["ElementHandle"]] = None,
1067
+ timeout: float = None,
1068
+ noWaitAfter: bool = None,
1069
+ force: bool = None,
1070
+ strict: bool = None,
1071
+ ) -> List[str]:
1072
+ params = locals_to_params(locals())
1073
+ return await self._main_frame.select_option(**params)
1074
+
1075
+ async def input_value(
1076
+ self, selector: str, strict: bool = None, timeout: float = None
1077
+ ) -> str:
1078
+ params = locals_to_params(locals())
1079
+ return await self._main_frame.input_value(**params)
1080
+
1081
+ async def set_input_files(
1082
+ self,
1083
+ selector: str,
1084
+ files: Union[
1085
+ str, Path, FilePayload, Sequence[Union[str, Path]], Sequence[FilePayload]
1086
+ ],
1087
+ timeout: float = None,
1088
+ strict: bool = None,
1089
+ noWaitAfter: bool = None,
1090
+ ) -> None:
1091
+ return await self._main_frame.set_input_files(**locals_to_params(locals()))
1092
+
1093
+ async def type(
1094
+ self,
1095
+ selector: str,
1096
+ text: str,
1097
+ delay: float = None,
1098
+ timeout: float = None,
1099
+ noWaitAfter: bool = None,
1100
+ strict: bool = None,
1101
+ ) -> None:
1102
+ return await self._main_frame.type(**locals_to_params(locals()))
1103
+
1104
+ async def press(
1105
+ self,
1106
+ selector: str,
1107
+ key: str,
1108
+ delay: float = None,
1109
+ timeout: float = None,
1110
+ noWaitAfter: bool = None,
1111
+ strict: bool = None,
1112
+ ) -> None:
1113
+ return await self._main_frame.press(**locals_to_params(locals()))
1114
+
1115
+ async def check(
1116
+ self,
1117
+ selector: str,
1118
+ position: Position = None,
1119
+ timeout: float = None,
1120
+ force: bool = None,
1121
+ noWaitAfter: bool = None,
1122
+ strict: bool = None,
1123
+ trial: bool = None,
1124
+ scroll: Literal["auto", "none"] = None,
1125
+ ) -> None:
1126
+ return await self._main_frame.check(**locals_to_params(locals()))
1127
+
1128
+ async def uncheck(
1129
+ self,
1130
+ selector: str,
1131
+ position: Position = None,
1132
+ timeout: float = None,
1133
+ force: bool = None,
1134
+ noWaitAfter: bool = None,
1135
+ strict: bool = None,
1136
+ trial: bool = None,
1137
+ scroll: Literal["auto", "none"] = None,
1138
+ ) -> None:
1139
+ return await self._main_frame.uncheck(**locals_to_params(locals()))
1140
+
1141
+ async def wait_for_timeout(self, timeout: float) -> None:
1142
+ await self._main_frame.wait_for_timeout(timeout)
1143
+
1144
+ async def wait_for_function(
1145
+ self,
1146
+ expression: str,
1147
+ arg: Serializable = None,
1148
+ timeout: float = None,
1149
+ polling: Union[float, Literal["raf"]] = None,
1150
+ ) -> JSHandle:
1151
+ return await self._main_frame.wait_for_function(**locals_to_params(locals()))
1152
+
1153
+ @property
1154
+ def workers(self) -> List["Worker"]:
1155
+ return self._workers.copy()
1156
+
1157
+ @property
1158
+ def request(self) -> "APIRequestContext":
1159
+ return self.context.request
1160
+
1161
+ async def pause(self) -> None:
1162
+ default_navigation_timeout = (
1163
+ self._browser_context._timeout_settings.default_navigation_timeout()
1164
+ )
1165
+ default_timeout = self._browser_context._timeout_settings.default_timeout()
1166
+ self._browser_context.set_default_navigation_timeout(0)
1167
+ self._browser_context.set_default_timeout(0)
1168
+ try:
1169
+ await asyncio.wait(
1170
+ [
1171
+ asyncio.create_task(
1172
+ self._browser_context._channel.send("pause", None)
1173
+ ),
1174
+ self._closed_or_crashed_future,
1175
+ ],
1176
+ return_when=asyncio.FIRST_COMPLETED,
1177
+ )
1178
+ finally:
1179
+ self._browser_context._set_default_navigation_timeout_impl(
1180
+ default_navigation_timeout
1181
+ )
1182
+ self._browser_context._set_default_timeout_impl(default_timeout)
1183
+
1184
+ async def pdf(
1185
+ self,
1186
+ scale: float = None,
1187
+ displayHeaderFooter: bool = None,
1188
+ headerTemplate: str = None,
1189
+ footerTemplate: str = None,
1190
+ printBackground: bool = None,
1191
+ landscape: bool = None,
1192
+ pageRanges: str = None,
1193
+ format: str = None,
1194
+ width: Union[str, float] = None,
1195
+ height: Union[str, float] = None,
1196
+ preferCSSPageSize: bool = None,
1197
+ margin: PdfMargins = None,
1198
+ path: Union[str, Path] = None,
1199
+ outline: bool = None,
1200
+ tagged: bool = None,
1201
+ ) -> bytes:
1202
+ params = locals_to_params(locals())
1203
+ if "path" in params:
1204
+ del params["path"]
1205
+ encoded_binary = await self._channel.send("pdf", None, params)
1206
+ decoded_binary = base64.b64decode(encoded_binary)
1207
+ if path:
1208
+ make_dirs_for_file(path)
1209
+ await async_writefile(path, decoded_binary)
1210
+ return decoded_binary
1211
+
1212
+ @property
1213
+ def video(self) -> Optional[Video]:
1214
+ # Video is only exposed when the page actually produced a recording artifact.
1215
+ # The initializer carries the artifact; if absent, no video was recorded.
1216
+ if not self._video._artifact:
1217
+ return None
1218
+ return self._video
1219
+
1220
+ @property
1221
+ def screencast(self) -> Screencast:
1222
+ return self._screencast
1223
+
1224
+ @property
1225
+ def local_storage(self) -> WebStorage:
1226
+ return self._local_storage
1227
+
1228
+ @property
1229
+ def session_storage(self) -> WebStorage:
1230
+ return self._session_storage
1231
+
1232
+ def _close_error_with_reason(self) -> TargetClosedError:
1233
+ return TargetClosedError(
1234
+ self._close_reason or self._browser_context._effective_close_reason()
1235
+ )
1236
+
1237
+ def expect_event(
1238
+ self,
1239
+ event: str,
1240
+ predicate: Callable = None,
1241
+ timeout: float = None,
1242
+ ) -> EventContextManagerImpl:
1243
+ return self._expect_event(
1244
+ event, predicate, timeout, f'waiting for event "{event}"'
1245
+ )
1246
+
1247
+ def _expect_event(
1248
+ self,
1249
+ event: str,
1250
+ predicate: Callable = None,
1251
+ timeout: float = None,
1252
+ log_line: str = None,
1253
+ ) -> EventContextManagerImpl:
1254
+ if timeout is None:
1255
+ timeout = self._timeout_settings.timeout()
1256
+ waiter = Waiter(self, f"page.expect_event({event})")
1257
+ waiter.reject_on_timeout(
1258
+ timeout, f'Timeout {timeout}ms exceeded while waiting for event "{event}"'
1259
+ )
1260
+ if log_line:
1261
+ waiter.log(log_line)
1262
+ if event != Page.Events.Crash:
1263
+ waiter.reject_on_event(self, Page.Events.Crash, Error("Page crashed"))
1264
+ if event != Page.Events.Close:
1265
+ waiter.reject_on_event(
1266
+ self, Page.Events.Close, lambda: self._close_error_with_reason()
1267
+ )
1268
+ waiter.wait_for_event(self, event, predicate)
1269
+ return EventContextManagerImpl(waiter.result())
1270
+
1271
+ def expect_console_message(
1272
+ self,
1273
+ predicate: Callable[[ConsoleMessage], bool] = None,
1274
+ timeout: float = None,
1275
+ ) -> EventContextManagerImpl[ConsoleMessage]:
1276
+ return self.expect_event(Page.Events.Console, predicate, timeout)
1277
+
1278
+ def expect_download(
1279
+ self,
1280
+ predicate: Callable[[Download], bool] = None,
1281
+ timeout: float = None,
1282
+ ) -> EventContextManagerImpl[Download]:
1283
+ return self.expect_event(Page.Events.Download, predicate, timeout)
1284
+
1285
+ def expect_file_chooser(
1286
+ self,
1287
+ predicate: Callable[[FileChooser], bool] = None,
1288
+ timeout: float = None,
1289
+ ) -> EventContextManagerImpl[FileChooser]:
1290
+ return self.expect_event(Page.Events.FileChooser, predicate, timeout)
1291
+
1292
+ def expect_navigation(
1293
+ self,
1294
+ url: URLMatch = None,
1295
+ waitUntil: DocumentLoadState = None,
1296
+ timeout: float = None,
1297
+ ) -> EventContextManagerImpl[Response]:
1298
+ return self.main_frame.expect_navigation(url, waitUntil, timeout)
1299
+
1300
+ def expect_popup(
1301
+ self,
1302
+ predicate: Callable[["Page"], bool] = None,
1303
+ timeout: float = None,
1304
+ ) -> EventContextManagerImpl["Page"]:
1305
+ return self.expect_event(Page.Events.Popup, predicate, timeout)
1306
+
1307
+ def expect_request(
1308
+ self,
1309
+ urlOrPredicate: URLMatchRequest,
1310
+ timeout: float = None,
1311
+ ) -> EventContextManagerImpl[Request]:
1312
+ def my_predicate(request: Request) -> Union[bool, Awaitable[bool]]:
1313
+ if not callable(urlOrPredicate):
1314
+ return url_matches(
1315
+ self._browser_context._base_url,
1316
+ request.url,
1317
+ urlOrPredicate,
1318
+ )
1319
+ return urlOrPredicate(request)
1320
+
1321
+ trimmed_url = trim_url(urlOrPredicate)
1322
+ log_line = f"waiting for request {trimmed_url}" if trimmed_url else None
1323
+ return self._expect_event(
1324
+ Page.Events.Request,
1325
+ predicate=my_predicate,
1326
+ timeout=timeout,
1327
+ log_line=log_line,
1328
+ )
1329
+
1330
+ def expect_request_finished(
1331
+ self,
1332
+ predicate: Callable[["Request"], bool] = None,
1333
+ timeout: float = None,
1334
+ ) -> EventContextManagerImpl[Request]:
1335
+ return self.expect_event(
1336
+ Page.Events.RequestFinished, predicate=predicate, timeout=timeout
1337
+ )
1338
+
1339
+ def expect_response(
1340
+ self,
1341
+ urlOrPredicate: URLMatchResponse,
1342
+ timeout: float = None,
1343
+ ) -> EventContextManagerImpl[Response]:
1344
+ def my_predicate(request: Response) -> Union[bool, Awaitable[bool]]:
1345
+ if not callable(urlOrPredicate):
1346
+ return url_matches(
1347
+ self._browser_context._base_url,
1348
+ request.url,
1349
+ urlOrPredicate,
1350
+ )
1351
+ return urlOrPredicate(request)
1352
+
1353
+ trimmed_url = trim_url(urlOrPredicate)
1354
+ log_line = f"waiting for response {trimmed_url}" if trimmed_url else None
1355
+ return self._expect_event(
1356
+ Page.Events.Response,
1357
+ predicate=my_predicate,
1358
+ timeout=timeout,
1359
+ log_line=log_line,
1360
+ )
1361
+
1362
+ def expect_websocket(
1363
+ self,
1364
+ predicate: Callable[["WebSocket"], bool] = None,
1365
+ timeout: float = None,
1366
+ ) -> EventContextManagerImpl["WebSocket"]:
1367
+ return self.expect_event("websocket", predicate, timeout)
1368
+
1369
+ def expect_worker(
1370
+ self,
1371
+ predicate: Callable[["Worker"], bool] = None,
1372
+ timeout: float = None,
1373
+ ) -> EventContextManagerImpl["Worker"]:
1374
+ return self.expect_event("worker", predicate, timeout)
1375
+
1376
+ async def set_checked(
1377
+ self,
1378
+ selector: str,
1379
+ checked: bool,
1380
+ position: Position = None,
1381
+ timeout: float = None,
1382
+ force: bool = None,
1383
+ noWaitAfter: bool = None,
1384
+ strict: bool = None,
1385
+ trial: bool = None,
1386
+ scroll: Literal["auto", "none"] = None,
1387
+ ) -> None:
1388
+ if checked:
1389
+ await self.check(
1390
+ selector=selector,
1391
+ position=position,
1392
+ timeout=timeout,
1393
+ force=force,
1394
+ strict=strict,
1395
+ trial=trial,
1396
+ scroll=scroll,
1397
+ )
1398
+ else:
1399
+ await self.uncheck(
1400
+ selector=selector,
1401
+ position=position,
1402
+ timeout=timeout,
1403
+ force=force,
1404
+ strict=strict,
1405
+ trial=trial,
1406
+ scroll=scroll,
1407
+ )
1408
+
1409
+ async def add_locator_handler(
1410
+ self,
1411
+ locator: "Locator",
1412
+ handler: Union[Callable[["Locator"], Any], Callable[[], Any]],
1413
+ noWaitAfter: bool = None,
1414
+ times: int = None,
1415
+ ) -> None:
1416
+ if locator._frame != self._main_frame:
1417
+ raise Error("Locator must belong to the main frame of this page")
1418
+ if times == 0:
1419
+ return
1420
+ uid = await self._channel.send(
1421
+ "registerLocatorHandler",
1422
+ None,
1423
+ {
1424
+ "selector": locator._selector,
1425
+ "noWaitAfter": noWaitAfter,
1426
+ },
1427
+ )
1428
+ self._locator_handlers[uid] = LocatorHandler(
1429
+ handler=handler, times=times, locator=locator
1430
+ )
1431
+
1432
+ async def _on_locator_handler_triggered(self, uid: str) -> None:
1433
+ remove = False
1434
+ try:
1435
+ handler = self._locator_handlers.get(uid)
1436
+ if handler and handler.times != 0:
1437
+ if handler.times is not None:
1438
+ handler.times -= 1
1439
+ if self._dispatcher_fiber:
1440
+ handler_finished_future = self._loop.create_future()
1441
+
1442
+ def _handler() -> None:
1443
+ try:
1444
+ handler()
1445
+ handler_finished_future.set_result(None)
1446
+ except Exception as e:
1447
+ handler_finished_future.set_exception(e)
1448
+
1449
+ g = LocatorHandlerGreenlet(_handler)
1450
+ g.switch()
1451
+ await handler_finished_future
1452
+ else:
1453
+ coro_or_future = handler()
1454
+ if coro_or_future:
1455
+ await coro_or_future
1456
+ remove = handler.times == 0
1457
+ finally:
1458
+ if remove:
1459
+ del self._locator_handlers[uid]
1460
+ try:
1461
+ await self._connection.wrap_api_call(
1462
+ lambda: self._channel.send(
1463
+ "resolveLocatorHandlerNoReply",
1464
+ None,
1465
+ {"uid": uid, "remove": remove},
1466
+ ),
1467
+ is_internal=True,
1468
+ )
1469
+ except Error:
1470
+ pass
1471
+
1472
+ async def remove_locator_handler(self, locator: "Locator") -> None:
1473
+ for uid, data in self._locator_handlers.copy().items():
1474
+ if data.locator._equals(locator):
1475
+ del self._locator_handlers[uid]
1476
+ self._channel.send_no_reply(
1477
+ "unregisterLocatorHandler",
1478
+ None,
1479
+ {"uid": uid},
1480
+ )
1481
+
1482
+ async def requests(self) -> List[Request]:
1483
+ request_objects = await self._channel.send("requests", None)
1484
+ return [from_channel(r) for r in request_objects]
1485
+
1486
+ async def console_messages(
1487
+ self, filter: Literal["all", "since-navigation"] = None
1488
+ ) -> List[ConsoleMessage]:
1489
+ message_dicts = await self._channel.send(
1490
+ "consoleMessages", None, locals_to_params(locals())
1491
+ )
1492
+ return [
1493
+ ConsoleMessage(
1494
+ {**event, "page": self._channel}, self._loop, self._dispatcher_fiber
1495
+ )
1496
+ for event in message_dicts
1497
+ ]
1498
+
1499
+ async def page_errors(
1500
+ self, filter: Literal["all", "since-navigation"] = None
1501
+ ) -> List[Error]:
1502
+ error_objects = await self._channel.send(
1503
+ "pageErrors", None, locals_to_params(locals())
1504
+ )
1505
+ return [parse_error(error["error"]) for error in error_objects]
1506
+
1507
+ async def clear_console_messages(self) -> None:
1508
+ await self._channel.send("clearConsoleMessages", None)
1509
+
1510
+ async def clear_page_errors(self) -> None:
1511
+ await self._channel.send("clearPageErrors", None)
1512
+
1513
+ async def pick_locator(self) -> "Locator":
1514
+ selector = await self._channel.send("pickLocator", None, {})
1515
+ return self.locator(selector)
1516
+
1517
+ async def cancel_pick_locator(self) -> None:
1518
+ await self._channel.send("cancelPickLocator", None, {})
1519
+
1520
+
1521
+ class Worker(ChannelOwner):
1522
+ Events = SimpleNamespace(Close="close", Console="console")
1523
+
1524
+ def __init__(
1525
+ self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
1526
+ ) -> None:
1527
+ super().__init__(parent, type, guid, initializer)
1528
+ self._set_event_to_subscription_mapping({Worker.Events.Console: "console"})
1529
+ self._channel.on("close", lambda _: self._on_close())
1530
+ self._page: Optional[Page] = None
1531
+ self._context: Optional["BrowserContext"] = None
1532
+
1533
+ def __repr__(self) -> str:
1534
+ return f"<Worker url={self.url!r}>"
1535
+
1536
+ def _on_close(self) -> None:
1537
+ if self._page:
1538
+ self._page._workers.remove(self)
1539
+ if self._context:
1540
+ self._context._service_workers.remove(self)
1541
+ self.emit(Worker.Events.Close, self)
1542
+
1543
+ @property
1544
+ def url(self) -> str:
1545
+ return self._initializer["url"]
1546
+
1547
+ async def evaluate(self, expression: str, arg: Serializable = None) -> Any:
1548
+ return parse_result(
1549
+ await self._channel.send(
1550
+ "evaluateExpression",
1551
+ None,
1552
+ dict(
1553
+ expression=expression,
1554
+ arg=serialize_argument(arg),
1555
+ ),
1556
+ )
1557
+ )
1558
+
1559
+ async def evaluate_handle(
1560
+ self, expression: str, arg: Serializable = None
1561
+ ) -> JSHandle:
1562
+ return from_channel(
1563
+ await self._channel.send(
1564
+ "evaluateExpressionHandle",
1565
+ None,
1566
+ dict(
1567
+ expression=expression,
1568
+ arg=serialize_argument(arg),
1569
+ ),
1570
+ )
1571
+ )
1572
+
1573
+ def expect_event(
1574
+ self,
1575
+ event: str,
1576
+ predicate: Callable = None,
1577
+ timeout: float = None,
1578
+ ) -> EventContextManagerImpl:
1579
+ if timeout is None:
1580
+ if self._page:
1581
+ timeout = self._page._timeout_settings.timeout()
1582
+ elif self._context:
1583
+ timeout = self._context._timeout_settings.timeout()
1584
+ else:
1585
+ timeout = 30000
1586
+ waiter = Waiter(self, f"worker.expect_event({event})")
1587
+ waiter.reject_on_timeout(
1588
+ cast(float, timeout),
1589
+ f'Timeout {timeout}ms exceeded while waiting for event "{event}"',
1590
+ )
1591
+ if event != Worker.Events.Close:
1592
+ waiter.reject_on_event(
1593
+ self, Worker.Events.Close, lambda: TargetClosedError()
1594
+ )
1595
+ waiter.wait_for_event(self, event, predicate)
1596
+ return EventContextManagerImpl(waiter.result())
1597
+
1598
+
1599
+ class BindingCall(ChannelOwner):
1600
+ def __init__(
1601
+ self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
1602
+ ) -> None:
1603
+ super().__init__(parent, type, guid, initializer)
1604
+
1605
+ async def call(self, func: Callable) -> None:
1606
+ try:
1607
+ frame = from_channel(self._initializer["frame"])
1608
+ source = dict(context=frame._page.context, page=frame._page, frame=frame)
1609
+ if self._initializer.get("handle"):
1610
+ result = func(source, from_channel(self._initializer["handle"]))
1611
+ else:
1612
+ func_args = list(map(parse_result, self._initializer["args"]))
1613
+ result = func(source, *func_args)
1614
+ if inspect.iscoroutine(result):
1615
+ result = await result
1616
+ self._channel.send_may_fail(
1617
+ "resolve", None, dict(result=serialize_argument(result))
1618
+ )
1619
+ except Exception as e:
1620
+ tb = sys.exc_info()[2]
1621
+ self._channel.send_may_fail(
1622
+ "reject", None, dict(error=dict(error=serialize_error(e, tb)))
1623
+ )
1624
+
1625
+
1626
+ def trim_url(param: Union[URLMatchRequest, URLMatchResponse]) -> Optional[str]:
1627
+ if isinstance(param, re.Pattern):
1628
+ return trim_end(param.pattern)
1629
+ if isinstance(param, str):
1630
+ return trim_end(param)
1631
+ return None
1632
+
1633
+
1634
+ def trim_end(s: str) -> str:
1635
+ if len(s) > 50:
1636
+ return s[:50] + "\u2026"
1637
+ return s