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.
- playwright/__init__.py +19 -0
- playwright/__main__.py +33 -0
- playwright/_impl/__init__.py +0 -0
- playwright/_impl/__pyinstaller/__init__.py +20 -0
- playwright/_impl/__pyinstaller/hook-playwright.async_api.py +17 -0
- playwright/_impl/__pyinstaller/hook-playwright.sync_api.py +17 -0
- playwright/_impl/_android.py +704 -0
- playwright/_impl/_api_structures.py +365 -0
- playwright/_impl/_artifact.py +87 -0
- playwright/_impl/_assertions.py +1124 -0
- playwright/_impl/_async_base.py +105 -0
- playwright/_impl/_browser.py +293 -0
- playwright/_impl/_browser_context.py +754 -0
- playwright/_impl/_browser_type.py +368 -0
- playwright/_impl/_cdp_session.py +46 -0
- playwright/_impl/_clock.py +104 -0
- playwright/_impl/_connection.py +764 -0
- playwright/_impl/_console_message.py +98 -0
- playwright/_impl/_credentials.py +57 -0
- playwright/_impl/_debugger.py +54 -0
- playwright/_impl/_dialog.py +63 -0
- playwright/_impl/_disposable.py +96 -0
- playwright/_impl/_download.py +64 -0
- playwright/_impl/_driver.py +41 -0
- playwright/_impl/_element_handle.py +480 -0
- playwright/_impl/_errors.py +64 -0
- playwright/_impl/_event_context_manager.py +33 -0
- playwright/_impl/_fetch.py +626 -0
- playwright/_impl/_file_chooser.py +57 -0
- playwright/_impl/_form_data.py +34 -0
- playwright/_impl/_frame.py +985 -0
- playwright/_impl/_glob.py +65 -0
- playwright/_impl/_greenlets.py +49 -0
- playwright/_impl/_har_router.py +122 -0
- playwright/_impl/_helper.py +601 -0
- playwright/_impl/_impl_to_api_mapping.py +158 -0
- playwright/_impl/_input.py +111 -0
- playwright/_impl/_js_handle.py +336 -0
- playwright/_impl/_json_pipe.py +97 -0
- playwright/_impl/_local_utils.py +95 -0
- playwright/_impl/_locator.py +1024 -0
- playwright/_impl/_map.py +31 -0
- playwright/_impl/_network.py +1017 -0
- playwright/_impl/_object_factory.py +116 -0
- playwright/_impl/_page.py +1637 -0
- playwright/_impl/_path_utils.py +27 -0
- playwright/_impl/_playwright.py +68 -0
- playwright/_impl/_screencast.py +177 -0
- playwright/_impl/_selectors.py +67 -0
- playwright/_impl/_set_input_files_helpers.py +158 -0
- playwright/_impl/_str_utils.py +76 -0
- playwright/_impl/_stream.py +46 -0
- playwright/_impl/_sync_base.py +151 -0
- playwright/_impl/_tracing.py +281 -0
- playwright/_impl/_transport.py +184 -0
- playwright/_impl/_video.py +56 -0
- playwright/_impl/_waiter.py +197 -0
- playwright/_impl/_web_error.py +48 -0
- playwright/_impl/_web_storage.py +58 -0
- playwright/_impl/_writable_stream.py +42 -0
- playwright/_repo_version.py +24 -0
- playwright/async_api/__init__.py +275 -0
- playwright/async_api/_android_generated.py +462 -0
- playwright/async_api/_context_manager.py +57 -0
- playwright/async_api/_generated.py +23875 -0
- playwright/driver/LICENSE +2946 -0
- playwright/driver/README.md +1 -0
- playwright/driver/node.exe +0 -0
- playwright/driver/package/LICENSE +202 -0
- playwright/driver/package/NOTICE +5 -0
- playwright/driver/package/README.md +3 -0
- playwright/driver/package/ThirdPartyNotices.txt +13 -0
- playwright/driver/package/bin/install_media_pack.ps1 +5 -0
- playwright/driver/package/bin/install_webkit_wsl.ps1 +33 -0
- playwright/driver/package/bin/reinstall_chrome_beta_linux.sh +42 -0
- playwright/driver/package/bin/reinstall_chrome_beta_mac.sh +13 -0
- playwright/driver/package/bin/reinstall_chrome_beta_win.ps1 +24 -0
- playwright/driver/package/bin/reinstall_chrome_stable_linux.sh +42 -0
- playwright/driver/package/bin/reinstall_chrome_stable_mac.sh +12 -0
- playwright/driver/package/bin/reinstall_chrome_stable_win.ps1 +24 -0
- playwright/driver/package/bin/reinstall_msedge_beta_linux.sh +48 -0
- playwright/driver/package/bin/reinstall_msedge_beta_mac.sh +11 -0
- playwright/driver/package/bin/reinstall_msedge_beta_win.ps1 +23 -0
- playwright/driver/package/bin/reinstall_msedge_dev_linux.sh +48 -0
- playwright/driver/package/bin/reinstall_msedge_dev_mac.sh +11 -0
- playwright/driver/package/bin/reinstall_msedge_dev_win.ps1 +23 -0
- playwright/driver/package/bin/reinstall_msedge_stable_linux.sh +48 -0
- playwright/driver/package/bin/reinstall_msedge_stable_mac.sh +11 -0
- playwright/driver/package/bin/reinstall_msedge_stable_win.ps1 +24 -0
- playwright/driver/package/browsers.json +75 -0
- playwright/driver/package/cli.js +21 -0
- playwright/driver/package/index.d.ts +17 -0
- playwright/driver/package/index.js +17 -0
- playwright/driver/package/index.mjs +28 -0
- playwright/driver/package/lib/bootstrap.js +88 -0
- playwright/driver/package/lib/coreBundle.js +74830 -0
- playwright/driver/package/lib/entry/cliDaemon.js +5 -0
- playwright/driver/package/lib/entry/dashboardApp.js +3 -0
- playwright/driver/package/lib/entry/mcp.js +10 -0
- playwright/driver/package/lib/entry/oopBrowserDownload.js +3 -0
- playwright/driver/package/lib/package.js +50 -0
- playwright/driver/package/lib/server/chromium/appIcon.png +0 -0
- playwright/driver/package/lib/server/electron/loader.js +118 -0
- playwright/driver/package/lib/serverRegistry.js +7347 -0
- playwright/driver/package/lib/serverRegistry.js.LICENSE +354 -0
- playwright/driver/package/lib/tools/cli-client/channelSessions.js +141 -0
- playwright/driver/package/lib/tools/cli-client/cli.js +6 -0
- playwright/driver/package/lib/tools/cli-client/help.json +708 -0
- playwright/driver/package/lib/tools/cli-client/minimist.js +128 -0
- playwright/driver/package/lib/tools/cli-client/output.js +343 -0
- playwright/driver/package/lib/tools/cli-client/program.js +404 -0
- playwright/driver/package/lib/tools/cli-client/registry.js +176 -0
- playwright/driver/package/lib/tools/cli-client/session.js +258 -0
- playwright/driver/package/lib/tools/dashboard/appIcon.png +0 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/SKILL.md +420 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/element-attributes.md +23 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/playwright-tests.md +39 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/request-mocking.md +87 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/running-code.md +241 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/session-management.md +225 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/storage-state.md +275 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/test-generation.md +433 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/tracing.md +139 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/video-recording.md +143 -0
- playwright/driver/package/lib/tools/skills/playwright-component-testing/SKILL.md +143 -0
- playwright/driver/package/lib/tools/skills/playwright-component-testing/references/gallery-spec.md +144 -0
- playwright/driver/package/lib/tools/skills/playwright-component-testing/references/migration.md +85 -0
- playwright/driver/package/lib/tools/skills/playwright-component-testing/references/react.md +67 -0
- playwright/driver/package/lib/tools/skills/playwright-component-testing/references/vue.md +75 -0
- playwright/driver/package/lib/tools/skills/playwright-trace/SKILL.md +171 -0
- playwright/driver/package/lib/tools/utils/extension.js +101 -0
- playwright/driver/package/lib/tools/utils/socketConnection.js +108 -0
- playwright/driver/package/lib/utilsBundle.js +90764 -0
- playwright/driver/package/lib/utilsBundle.js.LICENSE +2179 -0
- playwright/driver/package/lib/vite/dashboard/assets/codicon-DCmgc-ay.ttf +0 -0
- playwright/driver/package/lib/vite/dashboard/assets/firefox-1bWoP6pv.svg +1 -0
- playwright/driver/package/lib/vite/dashboard/assets/firefox-beta-k3eOH_eK.svg +1 -0
- playwright/driver/package/lib/vite/dashboard/assets/firefox-nightly-Cp5nfeDT.svg +1 -0
- playwright/driver/package/lib/vite/dashboard/assets/index-CyWAfh-p.js +11 -0
- playwright/driver/package/lib/vite/dashboard/assets/index-DhC616m4.css +1 -0
- playwright/driver/package/lib/vite/dashboard/assets/safari-na3_-uQk.svg +1 -0
- playwright/driver/package/lib/vite/dashboard/index.html +29 -0
- playwright/driver/package/lib/vite/dashboard/playwright-logo.svg +24 -0
- playwright/driver/package/lib/vite/htmlReport/index.html +16 -0
- playwright/driver/package/lib/vite/htmlReport/report.css +2 -0
- playwright/driver/package/lib/vite/htmlReport/report.js +32 -0
- playwright/driver/package/lib/vite/recorder/assets/codeMirrorModule--QdMvsKi.css +1 -0
- playwright/driver/package/lib/vite/recorder/assets/codeMirrorModule-CwYYHbcZ.js +32 -0
- playwright/driver/package/lib/vite/recorder/assets/codicon-DCmgc-ay.ttf +0 -0
- playwright/driver/package/lib/vite/recorder/assets/index-DYjdXIbE.js +129 -0
- playwright/driver/package/lib/vite/recorder/assets/index-l_lX622x.css +1 -0
- playwright/driver/package/lib/vite/recorder/index.html +29 -0
- playwright/driver/package/lib/vite/recorder/playwright-logo.svg +9 -0
- playwright/driver/package/lib/vite/traceViewer/assets/codeMirrorModule-By56iMx7.js +32 -0
- playwright/driver/package/lib/vite/traceViewer/assets/defaultSettingsView-B34OrIms.js +181 -0
- playwright/driver/package/lib/vite/traceViewer/assets/urlMatch-L3liM589.js +1 -0
- playwright/driver/package/lib/vite/traceViewer/assets/xtermModule-COQkjINf.js +7 -0
- playwright/driver/package/lib/vite/traceViewer/codeMirrorModule.-QdMvsKi.css +1 -0
- playwright/driver/package/lib/vite/traceViewer/codicon.DCmgc-ay.ttf +0 -0
- playwright/driver/package/lib/vite/traceViewer/defaultSettingsView.BLFoOugd.css +1 -0
- playwright/driver/package/lib/vite/traceViewer/index.B_TqY17P.css +1 -0
- playwright/driver/package/lib/vite/traceViewer/index.Dl36UVQT.js +1 -0
- playwright/driver/package/lib/vite/traceViewer/index.html +44 -0
- playwright/driver/package/lib/vite/traceViewer/manifest.webmanifest +16 -0
- playwright/driver/package/lib/vite/traceViewer/playwright-logo.svg +9 -0
- playwright/driver/package/lib/vite/traceViewer/snapshot.B_Jk1wbt.js +1 -0
- playwright/driver/package/lib/vite/traceViewer/snapshot.html +10 -0
- playwright/driver/package/lib/vite/traceViewer/sw.bundle.js +4 -0
- playwright/driver/package/lib/vite/traceViewer/uiMode.C7UW1sC9.css +1 -0
- playwright/driver/package/lib/vite/traceViewer/uiMode.D962mr9b.js +5 -0
- playwright/driver/package/lib/vite/traceViewer/uiMode.html +18 -0
- playwright/driver/package/lib/vite/traceViewer/xtermModule.kHJ-D0s7.css +1 -0
- playwright/driver/package/lib/webp_codec.LICENSE +173 -0
- playwright/driver/package/lib/webp_codec.wasm +0 -0
- playwright/driver/package/lib/xdg-open +1267 -0
- playwright/driver/package/package.json +34 -0
- playwright/driver/package/types/protocol.d.ts +24842 -0
- playwright/driver/package/types/structs.d.ts +47 -0
- playwright/driver/package/types/types.d.ts +26188 -0
- playwright/py.typed +0 -0
- playwright/sync_api/__init__.py +275 -0
- playwright/sync_api/_android_generated.py +494 -0
- playwright/sync_api/_context_manager.py +98 -0
- playwright/sync_api/_generated.py +24045 -0
- playwright_browserstack-1.62.0.dist-info/METADATA +82 -0
- playwright_browserstack-1.62.0.dist-info/RECORD +192 -0
- playwright_browserstack-1.62.0.dist-info/WHEEL +5 -0
- playwright_browserstack-1.62.0.dist-info/entry_points.txt +5 -0
- playwright_browserstack-1.62.0.dist-info/licenses/LICENSE +202 -0
- playwright_browserstack-1.62.0.dist-info/licenses/LICENSE.txt +51 -0
- playwright_browserstack-1.62.0.dist-info/licenses/NOTICE +18 -0
- playwright_browserstack-1.62.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,158 @@
|
|
|
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 inspect
|
|
16
|
+
from typing import Any, Callable, Dict, List, Optional, Sequence, Union
|
|
17
|
+
|
|
18
|
+
from playwright._impl._errors import Error
|
|
19
|
+
from playwright._impl._map import Map
|
|
20
|
+
|
|
21
|
+
API_ATTR = "_pw_api_instance_"
|
|
22
|
+
IMPL_ATTR = "_pw_impl_instance_"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ImplWrapper:
|
|
26
|
+
def __init__(self, impl_obj: Any) -> None:
|
|
27
|
+
self._impl_obj = impl_obj
|
|
28
|
+
|
|
29
|
+
def __repr__(self) -> str:
|
|
30
|
+
return self._impl_obj.__repr__()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ImplToApiMapping:
|
|
34
|
+
def __init__(self) -> None:
|
|
35
|
+
self._mapping: Dict[type, type] = {}
|
|
36
|
+
|
|
37
|
+
def register(self, impl_class: type, api_class: type) -> None:
|
|
38
|
+
self._mapping[impl_class] = api_class
|
|
39
|
+
|
|
40
|
+
def from_maybe_impl(
|
|
41
|
+
self, obj: Any, visited: Optional[Map[Any, Union[List, Dict]]] = None
|
|
42
|
+
) -> Any:
|
|
43
|
+
# Python does share default arguments between calls, so we need to
|
|
44
|
+
# create a new map if it is not provided.
|
|
45
|
+
if not visited:
|
|
46
|
+
visited = Map()
|
|
47
|
+
if not obj:
|
|
48
|
+
return obj
|
|
49
|
+
if isinstance(obj, dict):
|
|
50
|
+
if obj in visited:
|
|
51
|
+
return visited[obj]
|
|
52
|
+
o: Dict = {}
|
|
53
|
+
visited[obj] = o
|
|
54
|
+
for name, value in obj.items():
|
|
55
|
+
o[name] = self.from_maybe_impl(value, visited)
|
|
56
|
+
return o
|
|
57
|
+
if isinstance(obj, list):
|
|
58
|
+
if obj in visited:
|
|
59
|
+
return visited[obj]
|
|
60
|
+
a: List = []
|
|
61
|
+
visited[obj] = a
|
|
62
|
+
for item in obj:
|
|
63
|
+
a.append(self.from_maybe_impl(item, visited))
|
|
64
|
+
return a
|
|
65
|
+
api_class = self._mapping.get(type(obj))
|
|
66
|
+
if api_class:
|
|
67
|
+
api_instance = getattr(obj, API_ATTR, None)
|
|
68
|
+
if not api_instance:
|
|
69
|
+
api_instance = api_class(obj)
|
|
70
|
+
setattr(obj, API_ATTR, api_instance)
|
|
71
|
+
return api_instance
|
|
72
|
+
else:
|
|
73
|
+
return obj
|
|
74
|
+
|
|
75
|
+
def from_impl(self, obj: Any) -> Any:
|
|
76
|
+
assert obj
|
|
77
|
+
result = self.from_maybe_impl(obj)
|
|
78
|
+
assert result
|
|
79
|
+
return result
|
|
80
|
+
|
|
81
|
+
def from_impl_nullable(self, obj: Any = None) -> Optional[Any]:
|
|
82
|
+
return self.from_impl(obj) if obj else None
|
|
83
|
+
|
|
84
|
+
def from_impl_list(self, items: Sequence[Any]) -> List[Any]:
|
|
85
|
+
return list(map(lambda a: self.from_impl(a), items))
|
|
86
|
+
|
|
87
|
+
def from_impl_dict(self, map: Dict[str, Any]) -> Dict[str, Any]:
|
|
88
|
+
return {name: self.from_impl(value) for name, value in map.items()}
|
|
89
|
+
|
|
90
|
+
def to_impl(
|
|
91
|
+
self, obj: Any, visited: Optional[Map[Any, Union[List, Dict]]] = None
|
|
92
|
+
) -> Any:
|
|
93
|
+
if visited is None:
|
|
94
|
+
visited = Map()
|
|
95
|
+
try:
|
|
96
|
+
if not obj:
|
|
97
|
+
return obj
|
|
98
|
+
if isinstance(obj, dict):
|
|
99
|
+
if obj in visited:
|
|
100
|
+
return visited[obj]
|
|
101
|
+
o: Dict = {}
|
|
102
|
+
visited[obj] = o
|
|
103
|
+
for name, value in obj.items():
|
|
104
|
+
o[name] = self.to_impl(value, visited)
|
|
105
|
+
return o
|
|
106
|
+
if isinstance(obj, list):
|
|
107
|
+
if obj in visited:
|
|
108
|
+
return visited[obj]
|
|
109
|
+
a: List = []
|
|
110
|
+
visited[obj] = a
|
|
111
|
+
for item in obj:
|
|
112
|
+
a.append(self.to_impl(item, visited))
|
|
113
|
+
return a
|
|
114
|
+
if isinstance(obj, ImplWrapper):
|
|
115
|
+
return obj._impl_obj
|
|
116
|
+
return obj
|
|
117
|
+
except RecursionError:
|
|
118
|
+
raise Error("Maximum argument depth exceeded")
|
|
119
|
+
|
|
120
|
+
def wrap_handler(self, handler: Callable[..., Any]) -> Callable[..., None]:
|
|
121
|
+
def wrapper_func(*args: Any) -> Any:
|
|
122
|
+
parameters = inspect.signature(handler).parameters
|
|
123
|
+
has_varargs = any(
|
|
124
|
+
parameter.kind == inspect.Parameter.VAR_POSITIONAL
|
|
125
|
+
for parameter in parameters.values()
|
|
126
|
+
)
|
|
127
|
+
arg_count = (
|
|
128
|
+
len(args)
|
|
129
|
+
if has_varargs
|
|
130
|
+
else sum(
|
|
131
|
+
parameter.kind
|
|
132
|
+
in (
|
|
133
|
+
inspect.Parameter.POSITIONAL_ONLY,
|
|
134
|
+
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
135
|
+
)
|
|
136
|
+
for parameter in parameters.values()
|
|
137
|
+
)
|
|
138
|
+
)
|
|
139
|
+
return handler(
|
|
140
|
+
*list(map(lambda a: self.from_maybe_impl(a), args))[:arg_count]
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
if inspect.ismethod(handler):
|
|
144
|
+
wrapper = getattr(handler.__self__, IMPL_ATTR + handler.__name__, None)
|
|
145
|
+
if not wrapper:
|
|
146
|
+
wrapper = wrapper_func
|
|
147
|
+
setattr(
|
|
148
|
+
handler.__self__,
|
|
149
|
+
IMPL_ATTR + handler.__name__,
|
|
150
|
+
wrapper,
|
|
151
|
+
)
|
|
152
|
+
return wrapper
|
|
153
|
+
|
|
154
|
+
wrapper = getattr(handler, IMPL_ATTR, None)
|
|
155
|
+
if not wrapper:
|
|
156
|
+
wrapper = wrapper_func
|
|
157
|
+
setattr(handler, IMPL_ATTR, wrapper)
|
|
158
|
+
return wrapper
|
|
@@ -0,0 +1,111 @@
|
|
|
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
|
+
from playwright._impl._connection import Channel
|
|
16
|
+
from playwright._impl._helper import MouseButton, locals_to_params
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Keyboard:
|
|
20
|
+
def __init__(self, channel: Channel) -> None:
|
|
21
|
+
self._channel = channel
|
|
22
|
+
self._loop = channel._connection._loop
|
|
23
|
+
self._dispatcher_fiber = channel._connection._dispatcher_fiber
|
|
24
|
+
|
|
25
|
+
async def down(self, key: str) -> None:
|
|
26
|
+
await self._channel.send("keyboardDown", None, locals_to_params(locals()))
|
|
27
|
+
|
|
28
|
+
async def up(self, key: str) -> None:
|
|
29
|
+
await self._channel.send("keyboardUp", None, locals_to_params(locals()))
|
|
30
|
+
|
|
31
|
+
async def insert_text(self, text: str) -> None:
|
|
32
|
+
await self._channel.send("keyboardInsertText", None, locals_to_params(locals()))
|
|
33
|
+
|
|
34
|
+
async def type(self, text: str, delay: float = None) -> None:
|
|
35
|
+
await self._channel.send("keyboardType", None, locals_to_params(locals()))
|
|
36
|
+
|
|
37
|
+
async def press(self, key: str, delay: float = None) -> None:
|
|
38
|
+
await self._channel.send("keyboardPress", None, locals_to_params(locals()))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Mouse:
|
|
42
|
+
def __init__(self, channel: Channel) -> None:
|
|
43
|
+
self._channel = channel
|
|
44
|
+
self._loop = channel._connection._loop
|
|
45
|
+
self._dispatcher_fiber = channel._connection._dispatcher_fiber
|
|
46
|
+
|
|
47
|
+
async def move(self, x: float, y: float, steps: int = None) -> None:
|
|
48
|
+
await self._channel.send("mouseMove", None, locals_to_params(locals()))
|
|
49
|
+
|
|
50
|
+
async def down(
|
|
51
|
+
self,
|
|
52
|
+
button: MouseButton = None,
|
|
53
|
+
clickCount: int = None,
|
|
54
|
+
) -> None:
|
|
55
|
+
await self._channel.send("mouseDown", None, locals_to_params(locals()))
|
|
56
|
+
|
|
57
|
+
async def up(
|
|
58
|
+
self,
|
|
59
|
+
button: MouseButton = None,
|
|
60
|
+
clickCount: int = None,
|
|
61
|
+
) -> None:
|
|
62
|
+
await self._channel.send("mouseUp", None, locals_to_params(locals()))
|
|
63
|
+
|
|
64
|
+
async def _click(
|
|
65
|
+
self,
|
|
66
|
+
x: float,
|
|
67
|
+
y: float,
|
|
68
|
+
delay: float = None,
|
|
69
|
+
button: MouseButton = None,
|
|
70
|
+
clickCount: int = None,
|
|
71
|
+
title: str = None,
|
|
72
|
+
) -> None:
|
|
73
|
+
await self._channel.send(
|
|
74
|
+
"mouseClick", None, locals_to_params(locals()), title=title
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
async def click(
|
|
78
|
+
self,
|
|
79
|
+
x: float,
|
|
80
|
+
y: float,
|
|
81
|
+
delay: float = None,
|
|
82
|
+
button: MouseButton = None,
|
|
83
|
+
clickCount: int = None,
|
|
84
|
+
) -> None:
|
|
85
|
+
params = locals()
|
|
86
|
+
del params["self"]
|
|
87
|
+
await self._click(**params)
|
|
88
|
+
|
|
89
|
+
async def dblclick(
|
|
90
|
+
self,
|
|
91
|
+
x: float,
|
|
92
|
+
y: float,
|
|
93
|
+
delay: float = None,
|
|
94
|
+
button: MouseButton = None,
|
|
95
|
+
) -> None:
|
|
96
|
+
await self._click(
|
|
97
|
+
x, y, delay=delay, button=button, clickCount=2, title="Double click"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
async def wheel(self, deltaX: float, deltaY: float) -> None:
|
|
101
|
+
await self._channel.send("mouseWheel", None, locals_to_params(locals()))
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class Touchscreen:
|
|
105
|
+
def __init__(self, channel: Channel) -> None:
|
|
106
|
+
self._channel = channel
|
|
107
|
+
self._loop = channel._connection._loop
|
|
108
|
+
self._dispatcher_fiber = channel._connection._dispatcher_fiber
|
|
109
|
+
|
|
110
|
+
async def tap(self, x: float, y: float) -> None:
|
|
111
|
+
await self._channel.send("touchscreenTap", None, locals_to_params(locals()))
|
|
@@ -0,0 +1,336 @@
|
|
|
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 base64
|
|
16
|
+
import collections.abc
|
|
17
|
+
import datetime
|
|
18
|
+
import math
|
|
19
|
+
import struct
|
|
20
|
+
import traceback
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
|
|
23
|
+
from urllib.parse import ParseResult, urlparse, urlunparse
|
|
24
|
+
|
|
25
|
+
from playwright._impl._connection import Channel, ChannelOwner, from_channel
|
|
26
|
+
from playwright._impl._errors import Error, is_target_closed_error
|
|
27
|
+
from playwright._impl._map import Map
|
|
28
|
+
|
|
29
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
30
|
+
from playwright._impl._element_handle import ElementHandle
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
Serializable = Any
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class VisitorInfo:
|
|
37
|
+
visited: Map[Any, int]
|
|
38
|
+
last_id: int
|
|
39
|
+
|
|
40
|
+
def __init__(self) -> None:
|
|
41
|
+
self.visited = Map()
|
|
42
|
+
self.last_id = 0
|
|
43
|
+
|
|
44
|
+
def visit(self, obj: Any) -> int:
|
|
45
|
+
assert obj not in self.visited
|
|
46
|
+
self.last_id += 1
|
|
47
|
+
self.visited[obj] = self.last_id
|
|
48
|
+
return self.last_id
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class JSHandle(ChannelOwner):
|
|
52
|
+
def __init__(
|
|
53
|
+
self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
|
|
54
|
+
) -> None:
|
|
55
|
+
super().__init__(parent, type, guid, initializer)
|
|
56
|
+
self._preview = self._initializer["preview"]
|
|
57
|
+
self._channel.on(
|
|
58
|
+
"previewUpdated", lambda params: self._on_preview_updated(params["preview"])
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
def __repr__(self) -> str:
|
|
62
|
+
return f"<JSHandle preview={self._preview}>"
|
|
63
|
+
|
|
64
|
+
def __str__(self) -> str:
|
|
65
|
+
return self._preview
|
|
66
|
+
|
|
67
|
+
def _on_preview_updated(self, preview: str) -> None:
|
|
68
|
+
self._preview = preview
|
|
69
|
+
|
|
70
|
+
async def evaluate(self, expression: str, arg: Serializable = None) -> Any:
|
|
71
|
+
return parse_result(
|
|
72
|
+
await self._channel.send(
|
|
73
|
+
"evaluateExpression",
|
|
74
|
+
None,
|
|
75
|
+
dict(
|
|
76
|
+
expression=expression,
|
|
77
|
+
arg=serialize_argument(arg),
|
|
78
|
+
),
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
async def evaluate_handle(
|
|
83
|
+
self, expression: str, arg: Serializable = None
|
|
84
|
+
) -> "JSHandle":
|
|
85
|
+
return from_channel(
|
|
86
|
+
await self._channel.send(
|
|
87
|
+
"evaluateExpressionHandle",
|
|
88
|
+
None,
|
|
89
|
+
dict(
|
|
90
|
+
expression=expression,
|
|
91
|
+
arg=serialize_argument(arg),
|
|
92
|
+
),
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
async def get_property(self, propertyName: str) -> "JSHandle":
|
|
97
|
+
return from_channel(
|
|
98
|
+
await self._channel.send("getProperty", None, dict(name=propertyName))
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
async def get_properties(self) -> Dict[str, "JSHandle"]:
|
|
102
|
+
return {
|
|
103
|
+
prop["name"]: from_channel(prop["value"])
|
|
104
|
+
for prop in await self._channel.send(
|
|
105
|
+
"getPropertyList",
|
|
106
|
+
None,
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
def as_element(self) -> Optional["ElementHandle"]:
|
|
111
|
+
return None
|
|
112
|
+
|
|
113
|
+
async def dispose(self) -> None:
|
|
114
|
+
try:
|
|
115
|
+
await self._channel.send(
|
|
116
|
+
"dispose",
|
|
117
|
+
None,
|
|
118
|
+
)
|
|
119
|
+
except Exception as e:
|
|
120
|
+
if not is_target_closed_error(e):
|
|
121
|
+
raise e
|
|
122
|
+
|
|
123
|
+
async def json_value(self) -> Any:
|
|
124
|
+
return parse_result(
|
|
125
|
+
await self._channel.send(
|
|
126
|
+
"jsonValue",
|
|
127
|
+
None,
|
|
128
|
+
)
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def serialize_value(
|
|
133
|
+
value: Any, handles: List[Channel], visitor_info: Optional[VisitorInfo] = None
|
|
134
|
+
) -> Any:
|
|
135
|
+
if visitor_info is None:
|
|
136
|
+
visitor_info = VisitorInfo()
|
|
137
|
+
if isinstance(value, JSHandle):
|
|
138
|
+
h = len(handles)
|
|
139
|
+
handles.append(value._channel)
|
|
140
|
+
return dict(h=h)
|
|
141
|
+
if value is None:
|
|
142
|
+
return dict(v="null")
|
|
143
|
+
if isinstance(value, float):
|
|
144
|
+
if value == float("inf"):
|
|
145
|
+
return dict(v="Infinity")
|
|
146
|
+
if value == float("-inf"):
|
|
147
|
+
return dict(v="-Infinity")
|
|
148
|
+
if value == float("-0"):
|
|
149
|
+
return dict(v="-0")
|
|
150
|
+
if math.isnan(value):
|
|
151
|
+
return dict(v="NaN")
|
|
152
|
+
if isinstance(value, datetime.datetime):
|
|
153
|
+
# Node.js Date objects are always in UTC.
|
|
154
|
+
return {
|
|
155
|
+
"d": datetime.datetime.strftime(
|
|
156
|
+
value.astimezone(datetime.timezone.utc), "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
if isinstance(value, Exception):
|
|
160
|
+
return {
|
|
161
|
+
"e": {
|
|
162
|
+
"m": str(value),
|
|
163
|
+
"n": (
|
|
164
|
+
(value.name or "")
|
|
165
|
+
if isinstance(value, Error)
|
|
166
|
+
else value.__class__.__name__
|
|
167
|
+
),
|
|
168
|
+
"s": (
|
|
169
|
+
(value.stack or "")
|
|
170
|
+
if isinstance(value, Error)
|
|
171
|
+
else "".join(
|
|
172
|
+
traceback.format_exception(type(value), value=value, tb=None)
|
|
173
|
+
)
|
|
174
|
+
),
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if isinstance(value, bool):
|
|
178
|
+
return {"b": value}
|
|
179
|
+
if isinstance(value, (int, float)):
|
|
180
|
+
return {"n": value}
|
|
181
|
+
if isinstance(value, str):
|
|
182
|
+
return {"s": value}
|
|
183
|
+
if isinstance(value, ParseResult):
|
|
184
|
+
return {"u": urlunparse(value)}
|
|
185
|
+
|
|
186
|
+
if value in visitor_info.visited:
|
|
187
|
+
return dict(ref=visitor_info.visited[value])
|
|
188
|
+
|
|
189
|
+
if isinstance(value, collections.abc.Sequence) and not isinstance(value, str):
|
|
190
|
+
id = visitor_info.visit(value)
|
|
191
|
+
a = []
|
|
192
|
+
for e in value:
|
|
193
|
+
a.append(serialize_value(e, handles, visitor_info))
|
|
194
|
+
return dict(a=a, id=id)
|
|
195
|
+
|
|
196
|
+
if isinstance(value, dict):
|
|
197
|
+
id = visitor_info.visit(value)
|
|
198
|
+
o = []
|
|
199
|
+
for name in value:
|
|
200
|
+
o.append(
|
|
201
|
+
{"k": name, "v": serialize_value(value[name], handles, visitor_info)}
|
|
202
|
+
)
|
|
203
|
+
return dict(o=o, id=id)
|
|
204
|
+
return dict(v="undefined")
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def serialize_argument(arg: Serializable = None) -> Any:
|
|
208
|
+
handles: List[Channel] = []
|
|
209
|
+
value = serialize_value(arg, handles)
|
|
210
|
+
return dict(value=value, handles=handles)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def parse_value(value: Any, refs: Optional[Dict[int, Any]] = None) -> Any:
|
|
214
|
+
if refs is None:
|
|
215
|
+
refs = {}
|
|
216
|
+
if value is None:
|
|
217
|
+
return None
|
|
218
|
+
if isinstance(value, dict):
|
|
219
|
+
if "ref" in value:
|
|
220
|
+
return refs[value["ref"]]
|
|
221
|
+
|
|
222
|
+
if "v" in value:
|
|
223
|
+
v = value["v"]
|
|
224
|
+
if v == "Infinity":
|
|
225
|
+
return float("inf")
|
|
226
|
+
if v == "-Infinity":
|
|
227
|
+
return float("-inf")
|
|
228
|
+
if v == "-0":
|
|
229
|
+
return float("-0")
|
|
230
|
+
if v == "NaN":
|
|
231
|
+
return float("nan")
|
|
232
|
+
if v == "undefined":
|
|
233
|
+
return None
|
|
234
|
+
if v == "null":
|
|
235
|
+
return None
|
|
236
|
+
return v
|
|
237
|
+
|
|
238
|
+
if "u" in value:
|
|
239
|
+
return urlparse(value["u"])
|
|
240
|
+
|
|
241
|
+
if "bi" in value:
|
|
242
|
+
return int(value["bi"])
|
|
243
|
+
|
|
244
|
+
if "e" in value:
|
|
245
|
+
error = Error(value["e"]["m"])
|
|
246
|
+
error._name = value["e"]["n"]
|
|
247
|
+
error._stack = value["e"]["s"]
|
|
248
|
+
return error
|
|
249
|
+
|
|
250
|
+
if "a" in value:
|
|
251
|
+
a: List = []
|
|
252
|
+
refs[value["id"]] = a
|
|
253
|
+
for e in value["a"]:
|
|
254
|
+
a.append(parse_value(e, refs))
|
|
255
|
+
return a
|
|
256
|
+
|
|
257
|
+
if "d" in value:
|
|
258
|
+
# Node.js Date objects are always in UTC.
|
|
259
|
+
return datetime.datetime.strptime(
|
|
260
|
+
value["d"], "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
261
|
+
).replace(tzinfo=datetime.timezone.utc)
|
|
262
|
+
|
|
263
|
+
if "o" in value:
|
|
264
|
+
o: Dict = {}
|
|
265
|
+
refs[value["id"]] = o
|
|
266
|
+
for e in value["o"]:
|
|
267
|
+
o[e["k"]] = parse_value(e["v"], refs)
|
|
268
|
+
return o
|
|
269
|
+
|
|
270
|
+
if "n" in value:
|
|
271
|
+
return value["n"]
|
|
272
|
+
|
|
273
|
+
if "s" in value:
|
|
274
|
+
return value["s"]
|
|
275
|
+
|
|
276
|
+
if "b" in value:
|
|
277
|
+
return value["b"]
|
|
278
|
+
|
|
279
|
+
if "ta" in value:
|
|
280
|
+
encoded_bytes = value["ta"]["b"]
|
|
281
|
+
decoded_bytes = base64.b64decode(encoded_bytes)
|
|
282
|
+
array_type = value["ta"]["k"]
|
|
283
|
+
if array_type == "i8":
|
|
284
|
+
word_size = 1
|
|
285
|
+
fmt = "b"
|
|
286
|
+
elif array_type == "ui8" or array_type == "ui8c":
|
|
287
|
+
word_size = 1
|
|
288
|
+
fmt = "B"
|
|
289
|
+
elif array_type == "i16":
|
|
290
|
+
word_size = 2
|
|
291
|
+
fmt = "h"
|
|
292
|
+
elif array_type == "ui16":
|
|
293
|
+
word_size = 2
|
|
294
|
+
fmt = "H"
|
|
295
|
+
elif array_type == "i32":
|
|
296
|
+
word_size = 4
|
|
297
|
+
fmt = "i"
|
|
298
|
+
elif array_type == "ui32":
|
|
299
|
+
word_size = 4
|
|
300
|
+
fmt = "I"
|
|
301
|
+
elif array_type == "f32":
|
|
302
|
+
word_size = 4
|
|
303
|
+
fmt = "f"
|
|
304
|
+
elif array_type == "f64":
|
|
305
|
+
word_size = 8
|
|
306
|
+
fmt = "d"
|
|
307
|
+
elif array_type == "bi64":
|
|
308
|
+
word_size = 8
|
|
309
|
+
fmt = "q"
|
|
310
|
+
elif array_type == "bui64":
|
|
311
|
+
word_size = 8
|
|
312
|
+
fmt = "Q"
|
|
313
|
+
else:
|
|
314
|
+
raise ValueError(f"Unsupported array type: {array_type}")
|
|
315
|
+
|
|
316
|
+
byte_len = len(decoded_bytes)
|
|
317
|
+
if byte_len % word_size != 0:
|
|
318
|
+
raise ValueError(
|
|
319
|
+
f"Decoded bytes length {byte_len} is not a multiple of word size {word_size}"
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
if byte_len == 0:
|
|
323
|
+
return []
|
|
324
|
+
array_len = byte_len // word_size
|
|
325
|
+
# "<" denotes little-endian
|
|
326
|
+
format_string = f"<{array_len}{fmt}"
|
|
327
|
+
return list(struct.unpack(format_string, decoded_bytes))
|
|
328
|
+
return value
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def parse_result(result: Any) -> Any:
|
|
332
|
+
return parse_value(result)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def add_source_url_to_script(source: str, path: Union[str, Path]) -> str:
|
|
336
|
+
return source + "\n//# sourceURL=" + str(path).replace("\n", "")
|
|
@@ -0,0 +1,97 @@
|
|
|
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 logging
|
|
17
|
+
from typing import Dict, Optional, cast
|
|
18
|
+
|
|
19
|
+
from pyee.asyncio import AsyncIOEventEmitter
|
|
20
|
+
|
|
21
|
+
from playwright._impl._connection import Channel
|
|
22
|
+
from playwright._impl._errors import TargetClosedError
|
|
23
|
+
from playwright._impl._helper import Error, ParsedMessagePayload
|
|
24
|
+
from playwright._impl._transport import Transport
|
|
25
|
+
|
|
26
|
+
_logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class JsonPipeTransport(AsyncIOEventEmitter, Transport):
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
loop: asyncio.AbstractEventLoop,
|
|
33
|
+
pipe_channel: Channel,
|
|
34
|
+
) -> None:
|
|
35
|
+
super().__init__(loop)
|
|
36
|
+
Transport.__init__(self, loop)
|
|
37
|
+
self._stop_requested = False
|
|
38
|
+
self._pipe_channel = pipe_channel
|
|
39
|
+
|
|
40
|
+
def request_stop(self) -> None:
|
|
41
|
+
self._stop_requested = True
|
|
42
|
+
self._pipe_channel.send_no_reply("close", None, {})
|
|
43
|
+
|
|
44
|
+
def dispose(self) -> None:
|
|
45
|
+
self.on_error_future.cancel()
|
|
46
|
+
self._stopped_future.cancel()
|
|
47
|
+
|
|
48
|
+
async def wait_until_stopped(self) -> None:
|
|
49
|
+
await self._stopped_future
|
|
50
|
+
|
|
51
|
+
async def connect(self) -> None:
|
|
52
|
+
self._stopped_future: asyncio.Future = asyncio.Future()
|
|
53
|
+
|
|
54
|
+
def handle_message(message: Dict) -> None:
|
|
55
|
+
if self._stop_requested:
|
|
56
|
+
return
|
|
57
|
+
self.on_message(cast(ParsedMessagePayload, message))
|
|
58
|
+
|
|
59
|
+
def handle_closed(reason: Optional[str]) -> None:
|
|
60
|
+
# Set the close error before notifying listeners, so a listener
|
|
61
|
+
# that raises cannot stop callers from observing the reason.
|
|
62
|
+
if reason and not self.on_error_future.done():
|
|
63
|
+
self.on_error_future.set_exception(TargetClosedError(reason))
|
|
64
|
+
try:
|
|
65
|
+
self.emit("close", reason)
|
|
66
|
+
except Exception:
|
|
67
|
+
# Never propagate a listener's exception into _stopped_future:
|
|
68
|
+
# run() and wait_until_stopped() await it, and
|
|
69
|
+
# Connection.stop_async() awaits it *before* cleanup(), so
|
|
70
|
+
# resolving it with an exception would skip cleanup entirely
|
|
71
|
+
# and surface as an unretrieved exception from the bare
|
|
72
|
+
# create_task(connection.run()).
|
|
73
|
+
_logger.exception("Error in JsonPipeTransport close listener")
|
|
74
|
+
finally:
|
|
75
|
+
# Guarded because "closed" can arrive more than once (e.g. a
|
|
76
|
+
# server-initiated close racing request_stop()); an
|
|
77
|
+
# unguarded set_result raised InvalidStateError, leaving
|
|
78
|
+
# run() awaiting a future nothing would ever resolve.
|
|
79
|
+
if not self._stopped_future.done():
|
|
80
|
+
self._stopped_future.set_result(None)
|
|
81
|
+
|
|
82
|
+
self._pipe_channel.on(
|
|
83
|
+
"message",
|
|
84
|
+
lambda params: handle_message(params["message"]),
|
|
85
|
+
)
|
|
86
|
+
self._pipe_channel.on(
|
|
87
|
+
"closed",
|
|
88
|
+
lambda params: handle_closed(params.get("reason")),
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
async def run(self) -> None:
|
|
92
|
+
await self._stopped_future
|
|
93
|
+
|
|
94
|
+
def send(self, message: Dict) -> None:
|
|
95
|
+
if self._stop_requested:
|
|
96
|
+
raise Error("Playwright connection closed")
|
|
97
|
+
self._pipe_channel.send_no_reply("send", None, {"message": message})
|