pure-patchright 1.62.3__py3-none-any.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 (142) hide show
  1. patchright/__init__.py +5 -0
  2. patchright/__main__.py +18 -0
  3. patchright/_impl/__init__.py +0 -0
  4. patchright/_impl/__pyinstaller/__init__.py +20 -0
  5. patchright/_impl/__pyinstaller/hook-playwright.async_api.py +3 -0
  6. patchright/_impl/__pyinstaller/hook-playwright.sync_api.py +3 -0
  7. patchright/_impl/_api_structures.py +343 -0
  8. patchright/_impl/_artifact.py +46 -0
  9. patchright/_impl/_assertions.py +1014 -0
  10. patchright/_impl/_async_base.py +88 -0
  11. patchright/_impl/_browser.py +267 -0
  12. patchright/_impl/_browser_context.py +759 -0
  13. patchright/_impl/_browser_type.py +336 -0
  14. patchright/_impl/_cdp_session.py +25 -0
  15. patchright/_impl/_clock.py +62 -0
  16. patchright/_impl/_connection.py +686 -0
  17. patchright/_impl/_console_message.py +83 -0
  18. patchright/_impl/_credentials.py +38 -0
  19. patchright/_impl/_debugger.py +37 -0
  20. patchright/_impl/_dialog.py +45 -0
  21. patchright/_impl/_disposable.py +71 -0
  22. patchright/_impl/_download.py +49 -0
  23. patchright/_impl/_driver.py +24 -0
  24. patchright/_impl/_element_handle.py +446 -0
  25. patchright/_impl/_errors.py +46 -0
  26. patchright/_impl/_event_context_manager.py +19 -0
  27. patchright/_impl/_fetch.py +592 -0
  28. patchright/_impl/_file_chooser.py +42 -0
  29. patchright/_impl/_form_data.py +19 -0
  30. patchright/_impl/_frame.py +959 -0
  31. patchright/_impl/_glob.py +47 -0
  32. patchright/_impl/_greenlets.py +35 -0
  33. patchright/_impl/_har_router.py +98 -0
  34. patchright/_impl/_helper.py +551 -0
  35. patchright/_impl/_impl_to_api_mapping.py +141 -0
  36. patchright/_impl/_input.py +85 -0
  37. patchright/_impl/_js_handle.py +297 -0
  38. patchright/_impl/_json_pipe.py +55 -0
  39. patchright/_impl/_local_utils.py +73 -0
  40. patchright/_impl/_locator.py +894 -0
  41. patchright/_impl/_map.py +18 -0
  42. patchright/_impl/_network.py +953 -0
  43. patchright/_impl/_object_factory.py +93 -0
  44. patchright/_impl/_page.py +1601 -0
  45. patchright/_impl/_path_utils.py +13 -0
  46. patchright/_impl/_playwright.py +43 -0
  47. patchright/_impl/_screencast.py +149 -0
  48. patchright/_impl/_selectors.py +48 -0
  49. patchright/_impl/_set_input_files_helpers.py +134 -0
  50. patchright/_impl/_str_utils.py +59 -0
  51. patchright/_impl/_stream.py +31 -0
  52. patchright/_impl/_sync_base.py +130 -0
  53. patchright/_impl/_tracing.py +243 -0
  54. patchright/_impl/_transport.py +151 -0
  55. patchright/_impl/_video.py +41 -0
  56. patchright/_impl/_waiter.py +168 -0
  57. patchright/_impl/_web_error.py +33 -0
  58. patchright/_impl/_web_storage.py +41 -0
  59. patchright/_impl/_writable_stream.py +26 -0
  60. patchright/_repo_version.py +1 -0
  61. patchright/async_api/__init__.py +234 -0
  62. patchright/async_api/_context_manager.py +38 -0
  63. patchright/async_api/_generated.py +23396 -0
  64. patchright/driver/README.md +1 -0
  65. patchright/driver/package/README.md +3 -0
  66. patchright/driver/package/ThirdPartyNotices.txt +13 -0
  67. patchright/driver/package/bin/install_media_pack.ps1 +5 -0
  68. patchright/driver/package/bin/install_webkit_wsl.ps1 +33 -0
  69. patchright/driver/package/bin/reinstall_chrome_beta_linux.sh +42 -0
  70. patchright/driver/package/bin/reinstall_chrome_beta_mac.sh +13 -0
  71. patchright/driver/package/bin/reinstall_chrome_beta_win.ps1 +24 -0
  72. patchright/driver/package/bin/reinstall_chrome_stable_linux.sh +42 -0
  73. patchright/driver/package/bin/reinstall_chrome_stable_mac.sh +12 -0
  74. patchright/driver/package/bin/reinstall_chrome_stable_win.ps1 +24 -0
  75. patchright/driver/package/bin/reinstall_msedge_beta_linux.sh +48 -0
  76. patchright/driver/package/bin/reinstall_msedge_beta_mac.sh +11 -0
  77. patchright/driver/package/bin/reinstall_msedge_beta_win.ps1 +23 -0
  78. patchright/driver/package/bin/reinstall_msedge_dev_linux.sh +48 -0
  79. patchright/driver/package/bin/reinstall_msedge_dev_mac.sh +11 -0
  80. patchright/driver/package/bin/reinstall_msedge_dev_win.ps1 +23 -0
  81. patchright/driver/package/bin/reinstall_msedge_stable_linux.sh +48 -0
  82. patchright/driver/package/bin/reinstall_msedge_stable_mac.sh +11 -0
  83. patchright/driver/package/bin/reinstall_msedge_stable_win.ps1 +24 -0
  84. patchright/driver/package/browsers.json +75 -0
  85. patchright/driver/package/cli.js +21 -0
  86. patchright/driver/package/index.js +17 -0
  87. patchright/driver/package/index.mjs +28 -0
  88. patchright/driver/package/lib/bootstrap.js +88 -0
  89. patchright/driver/package/lib/coreBundle.js +77498 -0
  90. patchright/driver/package/lib/entry/cliDaemon.js +5 -0
  91. patchright/driver/package/lib/entry/dashboardApp.js +3 -0
  92. patchright/driver/package/lib/entry/mcp.js +10 -0
  93. patchright/driver/package/lib/entry/oopBrowserDownload.js +3 -0
  94. patchright/driver/package/lib/package.js +50 -0
  95. patchright/driver/package/lib/server/chromium/appIcon.png +0 -0
  96. patchright/driver/package/lib/server/electron/loader.js +107 -0
  97. patchright/driver/package/lib/serverRegistry.js +7347 -0
  98. patchright/driver/package/lib/serverRegistry.js.LICENSE +354 -0
  99. patchright/driver/package/lib/tools/cli-client/channelSessions.js +141 -0
  100. patchright/driver/package/lib/tools/cli-client/cli.js +6 -0
  101. patchright/driver/package/lib/tools/cli-client/help.json +708 -0
  102. patchright/driver/package/lib/tools/cli-client/minimist.js +128 -0
  103. patchright/driver/package/lib/tools/cli-client/output.js +343 -0
  104. patchright/driver/package/lib/tools/cli-client/program.js +404 -0
  105. patchright/driver/package/lib/tools/cli-client/registry.js +176 -0
  106. patchright/driver/package/lib/tools/cli-client/session.js +258 -0
  107. patchright/driver/package/lib/tools/dashboard/appIcon.png +0 -0
  108. patchright/driver/package/lib/tools/skills/playwright-cli/SKILL.md +420 -0
  109. patchright/driver/package/lib/tools/skills/playwright-cli/references/element-attributes.md +23 -0
  110. patchright/driver/package/lib/tools/skills/playwright-cli/references/playwright-tests.md +39 -0
  111. patchright/driver/package/lib/tools/skills/playwright-cli/references/request-mocking.md +87 -0
  112. patchright/driver/package/lib/tools/skills/playwright-cli/references/running-code.md +241 -0
  113. patchright/driver/package/lib/tools/skills/playwright-cli/references/session-management.md +225 -0
  114. patchright/driver/package/lib/tools/skills/playwright-cli/references/storage-state.md +275 -0
  115. patchright/driver/package/lib/tools/skills/playwright-cli/references/test-generation.md +433 -0
  116. patchright/driver/package/lib/tools/skills/playwright-cli/references/tracing.md +139 -0
  117. patchright/driver/package/lib/tools/skills/playwright-cli/references/video-recording.md +143 -0
  118. patchright/driver/package/lib/tools/skills/playwright-component-testing/SKILL.md +143 -0
  119. patchright/driver/package/lib/tools/skills/playwright-component-testing/references/gallery-spec.md +144 -0
  120. patchright/driver/package/lib/tools/skills/playwright-component-testing/references/migration.md +85 -0
  121. patchright/driver/package/lib/tools/skills/playwright-component-testing/references/react.md +67 -0
  122. patchright/driver/package/lib/tools/skills/playwright-component-testing/references/vue.md +75 -0
  123. patchright/driver/package/lib/tools/skills/playwright-trace/SKILL.md +171 -0
  124. patchright/driver/package/lib/tools/utils/extension.js +101 -0
  125. patchright/driver/package/lib/tools/utils/socketConnection.js +108 -0
  126. patchright/driver/package/lib/utilsBundle.js +90764 -0
  127. patchright/driver/package/lib/utilsBundle.js.LICENSE +2179 -0
  128. patchright/driver/package/lib/webp_codec.LICENSE +173 -0
  129. patchright/driver/package/lib/webp_codec.wasm +0 -0
  130. patchright/driver/package/lib/xdg-open +1267 -0
  131. patchright/driver/package/package.json +34 -0
  132. patchright/py.typed +0 -0
  133. patchright/sync_api/__init__.py +234 -0
  134. patchright/sync_api/_context_manager.py +73 -0
  135. patchright/sync_api/_generated.py +23590 -0
  136. pure_patchright-1.62.3.dist-info/LICENSE +201 -0
  137. pure_patchright-1.62.3.dist-info/METADATA +96 -0
  138. pure_patchright-1.62.3.dist-info/RECORD +142 -0
  139. pure_patchright-1.62.3.dist-info/WHEEL +4 -0
  140. pure_patchright-1.62.3.dist-info/entry_points.txt +5 -0
  141. pure_patchright-1.62.3.dist-info/licenses/LICENSE +202 -0
  142. pure_patchright-1.62.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,336 @@
1
+ import asyncio
2
+ import json
3
+ import pathlib
4
+ from pathlib import Path
5
+ from typing import TYPE_CHECKING, Dict, List, Optional, Pattern, Sequence, Union, cast
6
+ from patchright._impl._api_structures import (
7
+ ClientCertificate,
8
+ Geolocation,
9
+ HttpCredentials,
10
+ ProxySettings,
11
+ ViewportSize,
12
+ )
13
+ from patchright._impl._browser import Browser
14
+ from patchright._impl._browser_context import BrowserContext
15
+ from patchright._impl._connection import ChannelOwner, Connection, from_channel
16
+ from patchright._impl._errors import Error
17
+ from patchright._impl._helper import (
18
+ PLAYWRIGHT_MAX_DEADLINE,
19
+ ColorScheme,
20
+ Contrast,
21
+ Env,
22
+ ForcedColors,
23
+ HarContentPolicy,
24
+ HarMode,
25
+ ReducedMotion,
26
+ ServiceWorkersPolicy,
27
+ TimeoutSettings,
28
+ async_readfile,
29
+ locals_to_params,
30
+ )
31
+ from patchright._impl._json_pipe import JsonPipeTransport
32
+ from patchright._impl._network import serialize_headers, to_client_certificates_protocol
33
+ from patchright._impl._waiter import throw_on_timeout
34
+
35
+ if TYPE_CHECKING:
36
+ from patchright._impl._playwright import Playwright
37
+
38
+
39
+ class BrowserType(ChannelOwner):
40
+ def __init__(
41
+ self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
42
+ ) -> None:
43
+ super().__init__(parent, type, guid, initializer)
44
+ self._playwright: "Playwright"
45
+
46
+ def __repr__(self) -> str:
47
+ return f"<BrowserType name={self.name} executable_path={self.executable_path}>"
48
+
49
+ @property
50
+ def name(self) -> str:
51
+ return self._initializer["name"]
52
+
53
+ @property
54
+ def executable_path(self) -> str:
55
+ return self._initializer["executablePath"]
56
+
57
+ async def launch(
58
+ self,
59
+ executablePath: Union[str, Path] = None,
60
+ channel: str = None,
61
+ args: Sequence[str] = None,
62
+ ignoreDefaultArgs: Union[bool, Sequence[str]] = None,
63
+ handleSIGINT: bool = None,
64
+ handleSIGTERM: bool = None,
65
+ handleSIGHUP: bool = None,
66
+ timeout: float = None,
67
+ env: Env = None,
68
+ headless: bool = None,
69
+ proxy: ProxySettings = None,
70
+ downloadsPath: Union[str, Path] = None,
71
+ slowMo: float = None,
72
+ tracesDir: Union[pathlib.Path, str] = None,
73
+ artifactsDir: Union[pathlib.Path, str] = None,
74
+ chromiumSandbox: bool = None,
75
+ firefoxUserPrefs: Dict[str, Union[str, float, bool]] = None,
76
+ ) -> Browser:
77
+ params = locals_to_params(locals())
78
+ normalize_launch_params(params)
79
+ browser = cast(
80
+ Browser,
81
+ from_channel(
82
+ await self._channel.send(
83
+ "launch", TimeoutSettings.launch_timeout, params
84
+ )
85
+ ),
86
+ )
87
+ browser._connect_to_browser_type(
88
+ self, str(tracesDir) if tracesDir is not None else None
89
+ )
90
+ return browser
91
+
92
+ async def launch_persistent_context(
93
+ self,
94
+ userDataDir: Union[str, Path],
95
+ channel: str = None,
96
+ executablePath: Union[str, Path] = None,
97
+ args: Sequence[str] = None,
98
+ ignoreDefaultArgs: Union[bool, Sequence[str]] = None,
99
+ handleSIGINT: bool = None,
100
+ handleSIGTERM: bool = None,
101
+ handleSIGHUP: bool = None,
102
+ timeout: float = None,
103
+ env: Env = None,
104
+ headless: bool = None,
105
+ proxy: ProxySettings = None,
106
+ downloadsPath: Union[str, Path] = None,
107
+ slowMo: float = None,
108
+ viewport: ViewportSize = None,
109
+ screen: ViewportSize = None,
110
+ noViewport: bool = None,
111
+ ignoreHTTPSErrors: bool = None,
112
+ javaScriptEnabled: bool = None,
113
+ bypassCSP: bool = None,
114
+ userAgent: str = None,
115
+ locale: str = None,
116
+ timezoneId: str = None,
117
+ geolocation: Geolocation = None,
118
+ permissions: Sequence[str] = None,
119
+ extraHTTPHeaders: Dict[str, str] = None,
120
+ offline: bool = None,
121
+ httpCredentials: HttpCredentials = None,
122
+ deviceScaleFactor: float = None,
123
+ isMobile: bool = None,
124
+ hasTouch: bool = None,
125
+ colorScheme: ColorScheme = None,
126
+ reducedMotion: ReducedMotion = None,
127
+ forcedColors: ForcedColors = None,
128
+ contrast: Contrast = None,
129
+ acceptDownloads: bool = None,
130
+ tracesDir: Union[pathlib.Path, str] = None,
131
+ artifactsDir: Union[pathlib.Path, str] = None,
132
+ chromiumSandbox: bool = None,
133
+ firefoxUserPrefs: Dict[str, Union[str, float, bool]] = None,
134
+ recordHarPath: Union[Path, str] = None,
135
+ recordHarOmitContent: bool = None,
136
+ recordVideoDir: Union[Path, str] = None,
137
+ recordVideoSize: ViewportSize = None,
138
+ baseURL: str = None,
139
+ strictSelectors: bool = None,
140
+ serviceWorkers: ServiceWorkersPolicy = None,
141
+ recordHarUrlFilter: Union[Pattern[str], str] = None,
142
+ recordHarMode: HarMode = None,
143
+ recordHarContent: HarContentPolicy = None,
144
+ clientCertificates: List[ClientCertificate] = None,
145
+ *,
146
+ focusControl: Optional[bool] = None,
147
+ ) -> BrowserContext:
148
+ userDataDir = self._user_data_dir(userDataDir)
149
+ params = locals_to_params(locals())
150
+ await self._prepare_browser_context_params(params)
151
+ normalize_launch_params(params)
152
+ result = await self._channel.send_return_as_dict(
153
+ "launchPersistentContext", TimeoutSettings.launch_timeout, params
154
+ )
155
+ browser = cast(Browser, from_channel(result["browser"]))
156
+ browser._connect_to_browser_type(
157
+ self, str(tracesDir) if tracesDir is not None else None
158
+ )
159
+ context = cast(BrowserContext, from_channel(result["context"]))
160
+ await context._initialize_har_from_options(
161
+ record_har_content=recordHarContent,
162
+ record_har_mode=recordHarMode,
163
+ record_har_omit_content=recordHarOmitContent,
164
+ record_har_path=recordHarPath,
165
+ record_har_url_filter=recordHarUrlFilter,
166
+ )
167
+ return context
168
+
169
+ def _user_data_dir(self, userDataDir: Optional[Union[str, Path]]) -> str:
170
+ if not userDataDir:
171
+ return ""
172
+ if not Path(userDataDir).is_absolute():
173
+ return str(Path(userDataDir).resolve())
174
+ return str(Path(userDataDir))
175
+
176
+ async def connect_over_cdp(
177
+ self,
178
+ endpointURL: str,
179
+ timeout: float = None,
180
+ slowMo: float = None,
181
+ headers: Dict[str, str] = None,
182
+ isLocal: bool = None,
183
+ noDefaults: bool = None,
184
+ artifactsDir: Union[str, Path] = None,
185
+ ) -> Browser:
186
+ params = locals_to_params(locals())
187
+ if params.get("headers"):
188
+ params["headers"] = serialize_headers(params["headers"])
189
+ response = await self._channel.send_return_as_dict(
190
+ "connectOverCDP", TimeoutSettings.launch_timeout, params
191
+ )
192
+ browser = cast(Browser, from_channel(response["browser"]))
193
+ browser._connect_to_browser_type(self, None)
194
+ return browser
195
+
196
+ async def connect(
197
+ self,
198
+ endpoint: str,
199
+ timeout: float = None,
200
+ slowMo: float = None,
201
+ headers: Dict[str, str] = None,
202
+ exposeNetwork: str = None,
203
+ ) -> Browser:
204
+ if slowMo is None:
205
+ slowMo = 0
206
+ if timeout is None:
207
+ timeout = 0
208
+ headers = {**(headers if headers else {}), "x-playwright-browser": self.name}
209
+ local_utils = self._connection.local_utils
210
+ pipe_channel = (
211
+ await local_utils._channel.send_return_as_dict(
212
+ "connect",
213
+ lambda t: t or 0,
214
+ {
215
+ "endpoint": endpoint,
216
+ "headers": headers,
217
+ "slowMo": slowMo,
218
+ "timeout": timeout,
219
+ "exposeNetwork": exposeNetwork,
220
+ },
221
+ )
222
+ )["pipe"]
223
+ transport = JsonPipeTransport(self._connection._loop, pipe_channel)
224
+ connection = Connection(
225
+ self._connection._dispatcher_fiber,
226
+ self._connection._object_factory,
227
+ transport,
228
+ self._connection._loop,
229
+ local_utils=self._connection.local_utils,
230
+ )
231
+ connection.mark_as_remote()
232
+ browser = None
233
+
234
+ def handle_transport_close(reason: Optional[str]) -> None:
235
+ if browser:
236
+ for context in browser.contexts:
237
+ for page in context.pages:
238
+ page._on_close()
239
+ context._on_close()
240
+ connection.cleanup(reason)
241
+ if browser:
242
+ connection._loop.call_soon(browser._on_close)
243
+
244
+ transport.once("close", handle_transport_close)
245
+ connection._is_sync = self._connection._is_sync
246
+ connection._loop.create_task(connection.run())
247
+ playwright_future = connection.playwright_future
248
+ timeout_future = throw_on_timeout(
249
+ timeout if timeout else PLAYWRIGHT_MAX_DEADLINE,
250
+ Error("Connection timed out"),
251
+ )
252
+ done, pending = await asyncio.wait(
253
+ {transport.on_error_future, playwright_future, timeout_future},
254
+ return_when=asyncio.FIRST_COMPLETED,
255
+ )
256
+ if not playwright_future.done():
257
+ playwright_future.cancel()
258
+ if not timeout_future.done():
259
+ timeout_future.cancel()
260
+ playwright: "Playwright" = next(iter(done)).result()
261
+ playwright._set_selectors(self._playwright.selectors)
262
+ self._connection._child_ws_connections.append(connection)
263
+ pre_launched_browser = playwright._initializer.get("preLaunchedBrowser")
264
+ assert pre_launched_browser
265
+ browser = cast(Browser, from_channel(pre_launched_browser))
266
+ browser._should_close_connection_on_close = True
267
+ browser._connect_to_browser_type(self, None)
268
+ return browser
269
+
270
+ async def _prepare_browser_context_params(self, params: Dict) -> None:
271
+ if params.get("noViewport"):
272
+ del params["noViewport"]
273
+ params["noDefaultViewport"] = True
274
+ if "defaultBrowserType" in params:
275
+ del params["defaultBrowserType"]
276
+ if "extraHTTPHeaders" in params:
277
+ params["extraHTTPHeaders"] = serialize_headers(params["extraHTTPHeaders"])
278
+ if "recordVideoDir" in params:
279
+ params["recordVideo"] = {"dir": Path(params["recordVideoDir"]).absolute()}
280
+ if "recordVideoSize" in params:
281
+ params["recordVideo"]["size"] = params["recordVideoSize"]
282
+ del params["recordVideoSize"]
283
+ del params["recordVideoDir"]
284
+ if "storageState" in params:
285
+ storageState = params["storageState"]
286
+ if not isinstance(storageState, dict):
287
+ params["storageState"] = json.loads(
288
+ (await async_readfile(storageState)).decode()
289
+ )
290
+ if params.get("colorScheme", None) == "null":
291
+ params["colorScheme"] = "no-override"
292
+ if params.get("reducedMotion", None) == "null":
293
+ params["reducedMotion"] = "no-override"
294
+ if params.get("forcedColors", None) == "null":
295
+ params["forcedColors"] = "no-override"
296
+ if params.get("contrast", None) == "null":
297
+ params["contrast"] = "no-override"
298
+ if "acceptDownloads" in params:
299
+ params["acceptDownloads"] = (
300
+ "accept" if params["acceptDownloads"] else "deny"
301
+ )
302
+ if "clientCertificates" in params:
303
+ params["clientCertificates"] = await to_client_certificates_protocol(
304
+ params["clientCertificates"]
305
+ )
306
+ params["selectorEngines"] = self._playwright.selectors._selector_engines
307
+ params["testIdAttributeName"] = (
308
+ self._playwright.selectors._test_id_attribute_name
309
+ )
310
+ params.pop("recordHarPath", None)
311
+ params.pop("recordHarOmitContent", None)
312
+ params.pop("recordHarUrlFilter", None)
313
+ params.pop("recordHarMode", None)
314
+ params.pop("recordHarContent", None)
315
+
316
+
317
+ def normalize_launch_params(params: Dict) -> None:
318
+ if "env" in params:
319
+ params["env"] = [
320
+ {"name": name, "value": str(value)}
321
+ for [name, value] in params["env"].items()
322
+ ]
323
+ if "ignoreDefaultArgs" in params:
324
+ if params["ignoreDefaultArgs"] is True:
325
+ params["ignoreAllDefaultArgs"] = True
326
+ del params["ignoreDefaultArgs"]
327
+ elif params["ignoreDefaultArgs"] is False:
328
+ del params["ignoreDefaultArgs"]
329
+ if "executablePath" in params:
330
+ params["executablePath"] = str(Path(params["executablePath"]))
331
+ if "downloadsPath" in params:
332
+ params["downloadsPath"] = str(Path(params["downloadsPath"]))
333
+ if "tracesDir" in params:
334
+ params["tracesDir"] = str(Path(params["tracesDir"]))
335
+ if "artifactsDir" in params:
336
+ params["artifactsDir"] = str(Path(params["artifactsDir"]))
@@ -0,0 +1,25 @@
1
+ from types import SimpleNamespace
2
+ from typing import Any, Dict
3
+ from patchright._impl._connection import ChannelOwner
4
+ from patchright._impl._helper import locals_to_params
5
+
6
+
7
+ class CDPSession(ChannelOwner):
8
+ Events = SimpleNamespace(Event="event", Close="close")
9
+
10
+ def __init__(
11
+ self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
12
+ ) -> None:
13
+ super().__init__(parent, type, guid, initializer)
14
+ self._channel.on("event", lambda params: self._on_event(params))
15
+ self._channel.on("close", lambda _: self.emit(CDPSession.Events.Close, self))
16
+
17
+ def _on_event(self, params: Any) -> None:
18
+ self.emit(params["method"], params.get("params"))
19
+ self.emit(CDPSession.Events.Event, params)
20
+
21
+ async def send(self, method: str, params: Dict = None) -> Dict:
22
+ return await self._channel.send("send", None, locals_to_params(locals()))
23
+
24
+ async def detach(self) -> None:
25
+ await self._channel.send("detach", None)
@@ -0,0 +1,62 @@
1
+ import datetime
2
+ from typing import TYPE_CHECKING, Dict, Union
3
+
4
+ if TYPE_CHECKING:
5
+ from patchright._impl._browser_context import BrowserContext
6
+
7
+
8
+ class Clock:
9
+ def __init__(self, browser_context: "BrowserContext") -> None:
10
+ self._browser_context = browser_context
11
+ self._loop = browser_context._loop
12
+ self._dispatcher_fiber = browser_context._dispatcher_fiber
13
+
14
+ async def install(self, time: Union[float, str, datetime.datetime] = None) -> None:
15
+ await self._browser_context.install_inject_route()
16
+ await self._browser_context._channel.send(
17
+ "clockInstall", None, parse_time(time) if time is not None else {}
18
+ )
19
+
20
+ async def fast_forward(self, ticks: Union[int, str]) -> None:
21
+ await self._browser_context._channel.send(
22
+ "clockFastForward", None, parse_ticks(ticks)
23
+ )
24
+
25
+ async def pause_at(self, time: Union[float, str, datetime.datetime]) -> None:
26
+ await self._browser_context._channel.send(
27
+ "clockPauseAt", None, parse_time(time)
28
+ )
29
+
30
+ async def resume(self) -> None:
31
+ await self._browser_context._channel.send("clockResume", None)
32
+
33
+ async def run_for(self, ticks: Union[int, str]) -> None:
34
+ await self._browser_context._channel.send(
35
+ "clockRunFor", None, parse_ticks(ticks)
36
+ )
37
+
38
+ async def set_fixed_time(self, time: Union[float, str, datetime.datetime]) -> None:
39
+ await self._browser_context._channel.send(
40
+ "clockSetFixedTime", None, parse_time(time)
41
+ )
42
+
43
+ async def set_system_time(self, time: Union[float, str, datetime.datetime]) -> None:
44
+ await self._browser_context._channel.send(
45
+ "clockSetSystemTime", None, parse_time(time)
46
+ )
47
+
48
+
49
+ def parse_time(
50
+ time: Union[float, str, datetime.datetime],
51
+ ) -> Dict[str, Union[int, str]]:
52
+ if isinstance(time, (float, int)):
53
+ return {"timeNumber": int(time * 1000)}
54
+ if isinstance(time, str):
55
+ return {"timeString": time}
56
+ return {"timeNumber": int(time.timestamp() * 1000)}
57
+
58
+
59
+ def parse_ticks(ticks: Union[int, str]) -> Dict[str, Union[int, str]]:
60
+ if isinstance(ticks, int):
61
+ return {"ticksNumber": ticks}
62
+ return {"ticksString": ticks}