pymobiledevice3 5.0.1__py3-none-any.whl → 5.0.2__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.
Potentially problematic release.
This version of pymobiledevice3 might be problematic. Click here for more details.
- misc/plist_sniffer.py +15 -15
- misc/remotexpc_sniffer.py +29 -28
- pymobiledevice3/__main__.py +128 -102
- pymobiledevice3/_version.py +2 -2
- pymobiledevice3/bonjour.py +26 -49
- pymobiledevice3/ca.py +32 -24
- pymobiledevice3/cli/activation.py +7 -7
- pymobiledevice3/cli/afc.py +19 -19
- pymobiledevice3/cli/amfi.py +4 -4
- pymobiledevice3/cli/apps.py +51 -39
- pymobiledevice3/cli/backup.py +58 -32
- pymobiledevice3/cli/bonjour.py +25 -18
- pymobiledevice3/cli/cli_common.py +112 -81
- pymobiledevice3/cli/companion_proxy.py +4 -4
- pymobiledevice3/cli/completions.py +10 -10
- pymobiledevice3/cli/crash.py +37 -31
- pymobiledevice3/cli/developer.py +602 -520
- pymobiledevice3/cli/diagnostics.py +38 -33
- pymobiledevice3/cli/lockdown.py +79 -74
- pymobiledevice3/cli/mounter.py +85 -68
- pymobiledevice3/cli/notification.py +10 -10
- pymobiledevice3/cli/pcap.py +19 -14
- pymobiledevice3/cli/power_assertion.py +12 -10
- pymobiledevice3/cli/processes.py +10 -10
- pymobiledevice3/cli/profile.py +88 -77
- pymobiledevice3/cli/provision.py +17 -17
- pymobiledevice3/cli/remote.py +186 -110
- pymobiledevice3/cli/restore.py +43 -40
- pymobiledevice3/cli/springboard.py +30 -28
- pymobiledevice3/cli/syslog.py +85 -58
- pymobiledevice3/cli/usbmux.py +21 -20
- pymobiledevice3/cli/version.py +3 -2
- pymobiledevice3/cli/webinspector.py +157 -79
- pymobiledevice3/common.py +1 -1
- pymobiledevice3/exceptions.py +154 -60
- pymobiledevice3/irecv.py +49 -53
- pymobiledevice3/irecv_devices.py +1489 -492
- pymobiledevice3/lockdown.py +394 -241
- pymobiledevice3/lockdown_service_provider.py +5 -7
- pymobiledevice3/osu/os_utils.py +18 -9
- pymobiledevice3/osu/posix_util.py +28 -15
- pymobiledevice3/osu/win_util.py +14 -8
- pymobiledevice3/pair_records.py +19 -19
- pymobiledevice3/remote/common.py +4 -4
- pymobiledevice3/remote/core_device/app_service.py +94 -67
- pymobiledevice3/remote/core_device/core_device_service.py +17 -14
- pymobiledevice3/remote/core_device/device_info.py +5 -5
- pymobiledevice3/remote/core_device/diagnostics_service.py +10 -8
- pymobiledevice3/remote/core_device/file_service.py +47 -33
- pymobiledevice3/remote/remote_service_discovery.py +53 -35
- pymobiledevice3/remote/remotexpc.py +62 -41
- pymobiledevice3/remote/tunnel_service.py +371 -293
- pymobiledevice3/remote/utils.py +12 -11
- pymobiledevice3/remote/xpc_message.py +145 -125
- pymobiledevice3/resources/dsc_uuid_map.py +19 -19
- pymobiledevice3/resources/firmware_notifications.py +16 -16
- pymobiledevice3/restore/asr.py +27 -27
- pymobiledevice3/restore/base_restore.py +90 -47
- pymobiledevice3/restore/consts.py +87 -66
- pymobiledevice3/restore/device.py +11 -11
- pymobiledevice3/restore/fdr.py +46 -46
- pymobiledevice3/restore/ftab.py +19 -19
- pymobiledevice3/restore/img4.py +130 -133
- pymobiledevice3/restore/mbn.py +35 -54
- pymobiledevice3/restore/recovery.py +125 -135
- pymobiledevice3/restore/restore.py +524 -523
- pymobiledevice3/restore/restore_options.py +122 -115
- pymobiledevice3/restore/restored_client.py +25 -22
- pymobiledevice3/restore/tss.py +378 -270
- pymobiledevice3/service_connection.py +50 -46
- pymobiledevice3/services/accessibilityaudit.py +136 -126
- pymobiledevice3/services/afc.py +350 -291
- pymobiledevice3/services/amfi.py +21 -18
- pymobiledevice3/services/companion.py +23 -19
- pymobiledevice3/services/crash_reports.py +60 -46
- pymobiledevice3/services/debugserver_applist.py +3 -3
- pymobiledevice3/services/device_arbitration.py +8 -8
- pymobiledevice3/services/device_link.py +55 -47
- pymobiledevice3/services/diagnostics.py +971 -968
- pymobiledevice3/services/dtfetchsymbols.py +8 -8
- pymobiledevice3/services/dvt/dvt_secure_socket_proxy.py +4 -4
- pymobiledevice3/services/dvt/dvt_testmanaged_proxy.py +4 -4
- pymobiledevice3/services/dvt/instruments/activity_trace_tap.py +85 -74
- pymobiledevice3/services/dvt/instruments/application_listing.py +2 -3
- pymobiledevice3/services/dvt/instruments/condition_inducer.py +7 -6
- pymobiledevice3/services/dvt/instruments/core_profile_session_tap.py +442 -421
- pymobiledevice3/services/dvt/instruments/device_info.py +11 -11
- pymobiledevice3/services/dvt/instruments/energy_monitor.py +1 -1
- pymobiledevice3/services/dvt/instruments/graphics.py +1 -1
- pymobiledevice3/services/dvt/instruments/location_simulation.py +1 -1
- pymobiledevice3/services/dvt/instruments/location_simulation_base.py +10 -10
- pymobiledevice3/services/dvt/instruments/network_monitor.py +17 -17
- pymobiledevice3/services/dvt/instruments/notifications.py +1 -1
- pymobiledevice3/services/dvt/instruments/process_control.py +25 -10
- pymobiledevice3/services/dvt/instruments/screenshot.py +2 -2
- pymobiledevice3/services/dvt/instruments/sysmontap.py +15 -15
- pymobiledevice3/services/dvt/testmanaged/xcuitest.py +40 -50
- pymobiledevice3/services/file_relay.py +10 -10
- pymobiledevice3/services/heartbeat.py +8 -7
- pymobiledevice3/services/house_arrest.py +12 -15
- pymobiledevice3/services/installation_proxy.py +119 -100
- pymobiledevice3/services/lockdown_service.py +12 -5
- pymobiledevice3/services/misagent.py +22 -19
- pymobiledevice3/services/mobile_activation.py +84 -72
- pymobiledevice3/services/mobile_config.py +330 -301
- pymobiledevice3/services/mobile_image_mounter.py +137 -116
- pymobiledevice3/services/mobilebackup2.py +188 -150
- pymobiledevice3/services/notification_proxy.py +11 -11
- pymobiledevice3/services/os_trace.py +69 -51
- pymobiledevice3/services/pcapd.py +306 -306
- pymobiledevice3/services/power_assertion.py +10 -9
- pymobiledevice3/services/preboard.py +4 -4
- pymobiledevice3/services/remote_fetch_symbols.py +16 -14
- pymobiledevice3/services/remote_server.py +176 -146
- pymobiledevice3/services/restore_service.py +16 -16
- pymobiledevice3/services/screenshot.py +13 -10
- pymobiledevice3/services/simulate_location.py +7 -7
- pymobiledevice3/services/springboard.py +15 -15
- pymobiledevice3/services/syslog.py +5 -5
- pymobiledevice3/services/web_protocol/alert.py +3 -3
- pymobiledevice3/services/web_protocol/automation_session.py +180 -176
- pymobiledevice3/services/web_protocol/cdp_screencast.py +44 -36
- pymobiledevice3/services/web_protocol/cdp_server.py +19 -19
- pymobiledevice3/services/web_protocol/cdp_target.py +411 -373
- pymobiledevice3/services/web_protocol/driver.py +47 -45
- pymobiledevice3/services/web_protocol/element.py +74 -63
- pymobiledevice3/services/web_protocol/inspector_session.py +106 -102
- pymobiledevice3/services/web_protocol/selenium_api.py +2 -2
- pymobiledevice3/services/web_protocol/session_protocol.py +15 -10
- pymobiledevice3/services/web_protocol/switch_to.py +11 -12
- pymobiledevice3/services/webinspector.py +127 -116
- pymobiledevice3/tcp_forwarder.py +35 -22
- pymobiledevice3/tunneld/api.py +20 -15
- pymobiledevice3/tunneld/server.py +212 -133
- pymobiledevice3/usbmux.py +183 -138
- pymobiledevice3/utils.py +14 -11
- {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.2.dist-info}/METADATA +1 -1
- pymobiledevice3-5.0.2.dist-info/RECORD +173 -0
- pymobiledevice3-5.0.1.dist-info/RECORD +0 -173
- {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.2.dist-info}/WHEEL +0 -0
- {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.2.dist-info}/entry_points.txt +0 -0
- {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.2.dist-info}/licenses/LICENSE +0 -0
- {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.2.dist-info}/top_level.txt +0 -0
|
@@ -8,15 +8,15 @@ from pymobiledevice3.exceptions import InspectorEvaluateError
|
|
|
8
8
|
from pymobiledevice3.services.web_protocol.session_protocol import SessionProtocol
|
|
9
9
|
|
|
10
10
|
logger = logging.getLogger(__name__)
|
|
11
|
-
console_logger = logging.getLogger(
|
|
12
|
-
heap_logger = logging.getLogger(
|
|
11
|
+
console_logger = logging.getLogger("webinspector.console")
|
|
12
|
+
heap_logger = logging.getLogger("webinspector.heap")
|
|
13
13
|
|
|
14
14
|
webinspector_logger_handlers = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
"log": console_logger.info,
|
|
16
|
+
"info": console_logger.info,
|
|
17
|
+
"error": console_logger.error,
|
|
18
|
+
"debug": console_logger.debug,
|
|
19
|
+
"warning": console_logger.warning,
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
|
|
@@ -24,8 +24,8 @@ class JSObjectPreview(UserDict):
|
|
|
24
24
|
def __init__(self, properties: list[dict]):
|
|
25
25
|
super().__init__()
|
|
26
26
|
for p in properties:
|
|
27
|
-
name = p[
|
|
28
|
-
value = p[
|
|
27
|
+
name = p["name"]
|
|
28
|
+
value = p["value"]
|
|
29
29
|
self.data[name] = value
|
|
30
30
|
|
|
31
31
|
|
|
@@ -33,26 +33,25 @@ class JSObjectProperties(UserDict):
|
|
|
33
33
|
def __init__(self, properties: list[dict]):
|
|
34
34
|
super().__init__()
|
|
35
35
|
for p in properties:
|
|
36
|
-
name = p[
|
|
37
|
-
if name ==
|
|
38
|
-
self.class_name = p[
|
|
36
|
+
name = p["name"]
|
|
37
|
+
if name == "__proto__":
|
|
38
|
+
self.class_name = p["value"]["className"]
|
|
39
39
|
continue
|
|
40
40
|
# test if a getter/setter first
|
|
41
|
-
value = p.get(
|
|
41
|
+
value = p.get("get", p.get("set", p.get("value")))
|
|
42
42
|
if value is None:
|
|
43
43
|
continue
|
|
44
|
-
preview = value.get(
|
|
44
|
+
preview = value.get("preview")
|
|
45
45
|
if preview is not None:
|
|
46
|
-
value = JSObjectPreview(preview[
|
|
47
|
-
elif value.get(
|
|
48
|
-
value = value[
|
|
46
|
+
value = JSObjectPreview(preview["properties"])
|
|
47
|
+
elif value.get("className") == "Function":
|
|
48
|
+
value = value["description"]
|
|
49
49
|
else:
|
|
50
|
-
value = value.get(
|
|
50
|
+
value = value.get("value")
|
|
51
51
|
self.data[name] = value
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
class InspectorSession:
|
|
55
|
-
|
|
56
55
|
def __init__(self, protocol: SessionProtocol, target_id: Optional[str] = None):
|
|
57
56
|
"""
|
|
58
57
|
:param pymobiledevice3.services.web_protocol.session_protocol.SessionProtocol protocol: Session protocol.
|
|
@@ -64,14 +63,14 @@ class InspectorSession:
|
|
|
64
63
|
self._dispatch_message_responses = {}
|
|
65
64
|
|
|
66
65
|
self.response_methods = {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
66
|
+
"Target.targetCreated": self._target_created,
|
|
67
|
+
"Target.targetDestroyed": self._target_destroyed,
|
|
68
|
+
"Target.dispatchMessageFromTarget": self._target_dispatch_message_from_target,
|
|
69
|
+
"Target.didCommitProvisionalTarget": self._target_did_commit_provisional_target,
|
|
70
|
+
"Console.messageAdded": self._console_message_added,
|
|
71
|
+
"Console.messagesCleared": lambda _: _,
|
|
72
|
+
"Console.messageRepeatCountUpdated": self._console_message_repeated_count_updated,
|
|
73
|
+
"Heap.garbageCollected": self._heap_garbage_collected,
|
|
75
74
|
}
|
|
76
75
|
|
|
77
76
|
self._receive_task = asyncio.create_task(self._receive_loop())
|
|
@@ -88,64 +87,65 @@ class InspectorSession:
|
|
|
88
87
|
while not protocol.inspector.wir_events:
|
|
89
88
|
await asyncio.sleep(0)
|
|
90
89
|
created = protocol.inspector.wir_events.pop(0)
|
|
91
|
-
while
|
|
90
|
+
while "targetInfo" not in created["params"]:
|
|
92
91
|
created = protocol.inspector.wir_events.pop(0)
|
|
93
|
-
target_id = created[
|
|
94
|
-
logger.info(f
|
|
92
|
+
target_id = created["params"]["targetInfo"]["targetId"]
|
|
93
|
+
logger.info(f"Created: {target_id}")
|
|
95
94
|
target = cls(protocol, target_id)
|
|
96
95
|
return target
|
|
97
96
|
|
|
98
97
|
def set_target_id(self, target_id):
|
|
99
98
|
self.target_id = target_id
|
|
100
|
-
logger.info(f
|
|
99
|
+
logger.info(f"Changed to: {target_id}")
|
|
101
100
|
|
|
102
101
|
async def heap_gc(self):
|
|
103
|
-
return await self.send_command(
|
|
102
|
+
return await self.send_command("Heap.gc")
|
|
104
103
|
|
|
105
104
|
async def heap_snapshot(self):
|
|
106
|
-
snapshot = await self.send_command(
|
|
105
|
+
snapshot = await self.send_command("Heap.snapshot")
|
|
107
106
|
if self.target_id is not None:
|
|
108
|
-
snapshot = json.loads(snapshot[
|
|
109
|
-
snapshot = json.loads(snapshot)[
|
|
107
|
+
snapshot = json.loads(snapshot["params"]["message"])
|
|
108
|
+
snapshot = json.loads(snapshot)["result"]["snapshotData"]
|
|
110
109
|
return snapshot
|
|
111
110
|
|
|
112
111
|
async def heap_enable(self):
|
|
113
|
-
return await self.send_command(
|
|
112
|
+
return await self.send_command("Heap.enable")
|
|
114
113
|
|
|
115
114
|
async def console_enable(self):
|
|
116
|
-
return await self.send_command(
|
|
115
|
+
return await self.send_command("Console.enable")
|
|
117
116
|
|
|
118
117
|
async def runtime_enable(self):
|
|
119
|
-
return await self.send_command(
|
|
118
|
+
return await self.send_command("Runtime.enable")
|
|
120
119
|
|
|
121
120
|
async def send_command(self, method: str, **kwargs):
|
|
122
121
|
if self.target_id is None:
|
|
123
122
|
return await self.protocol.send_receive(method, **kwargs)
|
|
124
123
|
else:
|
|
125
|
-
return await self.send_and_receive({
|
|
124
|
+
return await self.send_and_receive({"method": method, "params": kwargs})
|
|
126
125
|
|
|
127
126
|
async def runtime_evaluate(self, exp: str, return_by_value: bool = False):
|
|
128
127
|
# if the expression is dict, it's needed to be in ()
|
|
129
128
|
exp = exp.strip()
|
|
130
|
-
if exp:
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
129
|
+
if exp and exp[0] == "{" and exp[-1] == "}":
|
|
130
|
+
exp = f"({exp})"
|
|
131
|
+
|
|
132
|
+
response = await self.send_and_receive({
|
|
133
|
+
"method": "Runtime.evaluate",
|
|
134
|
+
"params": {
|
|
135
|
+
"expression": exp,
|
|
136
|
+
"objectGroup": "console",
|
|
137
|
+
"includeCommandLineAPI": True,
|
|
138
|
+
"doNotPauseOnExceptionsAndMuteConsole": False,
|
|
139
|
+
"silent": False,
|
|
140
|
+
"returnByValue": return_by_value,
|
|
141
|
+
"generatePreview": True,
|
|
142
|
+
"userGesture": True,
|
|
143
|
+
"awaitPromise": False,
|
|
144
|
+
"replMode": True,
|
|
145
|
+
"allowUnsafeEvalBlockedByCSP": False,
|
|
146
|
+
"uniqueContextId": "0.1",
|
|
147
|
+
},
|
|
148
|
+
})
|
|
149
149
|
|
|
150
150
|
return await self._parse_runtime_evaluate(response)
|
|
151
151
|
|
|
@@ -154,18 +154,19 @@ class InspectorSession:
|
|
|
154
154
|
|
|
155
155
|
async def send_and_receive(self, message: dict) -> dict:
|
|
156
156
|
if self.target_id is None:
|
|
157
|
-
message_id = await self.protocol.send_command(message[
|
|
157
|
+
message_id = await self.protocol.send_command(message["method"], **message.get("params", {}))
|
|
158
158
|
return await self.protocol.wait_for_message(message_id)
|
|
159
159
|
else:
|
|
160
160
|
message_id = await self.send_message_to_target(message)
|
|
161
161
|
return await self.receive_response_by_id(message_id)
|
|
162
162
|
|
|
163
163
|
async def send_message_to_target(self, message: dict) -> int:
|
|
164
|
-
message[
|
|
164
|
+
message["id"] = self.message_id
|
|
165
165
|
self.message_id += 1
|
|
166
|
-
await self.protocol.send_command(
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
await self.protocol.send_command(
|
|
167
|
+
"Target.sendMessageToTarget", targetId=self.target_id, message=json.dumps(message)
|
|
168
|
+
)
|
|
169
|
+
return message["id"]
|
|
169
170
|
|
|
170
171
|
async def _receive_loop(self):
|
|
171
172
|
while True:
|
|
@@ -173,11 +174,11 @@ class InspectorSession:
|
|
|
173
174
|
await asyncio.sleep(0)
|
|
174
175
|
|
|
175
176
|
response = self.protocol.inspector.wir_events.pop(0)
|
|
176
|
-
response_method = response[
|
|
177
|
+
response_method = response["method"]
|
|
177
178
|
if response_method in self.response_methods:
|
|
178
179
|
self.response_methods[response_method](response)
|
|
179
180
|
else:
|
|
180
|
-
logger.error(f
|
|
181
|
+
logger.error(f"Unknown response: {response}")
|
|
181
182
|
|
|
182
183
|
async def receive_response_by_id(self, message_id: int) -> dict:
|
|
183
184
|
while True:
|
|
@@ -187,64 +188,67 @@ class InspectorSession:
|
|
|
187
188
|
|
|
188
189
|
async def get_properties(self, object_id: str) -> JSObjectProperties:
|
|
189
190
|
message = await self.send_command(
|
|
190
|
-
|
|
191
|
+
"Runtime.getProperties", objectId=object_id, ownProperties=True, generatePreview=True
|
|
192
|
+
)
|
|
191
193
|
if self.target_id is not None:
|
|
192
|
-
message = json.loads(message[
|
|
193
|
-
return JSObjectProperties(message[
|
|
194
|
+
message = json.loads(message["params"]["message"])["result"]
|
|
195
|
+
return JSObjectProperties(message["properties"])
|
|
194
196
|
|
|
195
197
|
async def _parse_runtime_evaluate(self, response: dict):
|
|
196
|
-
if self.target_id is None
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
elif result[
|
|
198
|
+
message = response if self.target_id is None else json.loads(response["params"]["message"])
|
|
199
|
+
result = message["result"]["result"]
|
|
200
|
+
if result.get("subtype", "") == "error":
|
|
201
|
+
properties = await self.get_properties(result["objectId"])
|
|
202
|
+
raise InspectorEvaluateError(
|
|
203
|
+
properties.class_name,
|
|
204
|
+
properties["message"],
|
|
205
|
+
properties.get("line"),
|
|
206
|
+
properties.get("column"),
|
|
207
|
+
properties.get("stack", "").split("\n"),
|
|
208
|
+
)
|
|
209
|
+
elif result["type"] == "bigint":
|
|
210
|
+
return result["description"]
|
|
211
|
+
elif result["type"] == "undefined":
|
|
208
212
|
pass
|
|
209
|
-
elif result[
|
|
210
|
-
value = result.get(
|
|
213
|
+
elif result["type"] == "object":
|
|
214
|
+
value = result.get("value")
|
|
211
215
|
if value is not None:
|
|
212
216
|
return value
|
|
213
217
|
|
|
214
218
|
# TODO: JSObjectProperties()
|
|
215
|
-
preview = result[
|
|
216
|
-
preview_buf =
|
|
217
|
-
for p in result[
|
|
218
|
-
value = p.get(
|
|
219
|
-
preview_buf += f
|
|
220
|
-
if preview.get(
|
|
221
|
-
preview_buf +=
|
|
222
|
-
preview_buf +=
|
|
223
|
-
return f
|
|
224
|
-
elif result[
|
|
225
|
-
return result[
|
|
219
|
+
preview = result["preview"]
|
|
220
|
+
preview_buf = "{\n"
|
|
221
|
+
for p in result["preview"]["properties"]:
|
|
222
|
+
value = p.get("value", "NOT_SUPPORTED_FOR_PREVIEW")
|
|
223
|
+
preview_buf += f"\t{p['name']}: {value}, // {p['type']}\n"
|
|
224
|
+
if preview.get("overflow"):
|
|
225
|
+
preview_buf += "\t// ...\n"
|
|
226
|
+
preview_buf += "}"
|
|
227
|
+
return f"[object {result['className']}]\n{preview_buf}"
|
|
228
|
+
elif result["type"] == "function":
|
|
229
|
+
return result["description"]
|
|
226
230
|
else:
|
|
227
|
-
return result[
|
|
231
|
+
return result["value"]
|
|
228
232
|
|
|
229
233
|
# response methods
|
|
230
234
|
def _target_dispatch_message_from_target(self, response: dict):
|
|
231
|
-
target_message = json.loads(response[
|
|
232
|
-
receive_message_id = target_message.get(
|
|
235
|
+
target_message = json.loads(response["params"]["message"])
|
|
236
|
+
receive_message_id = target_message.get("id")
|
|
233
237
|
if receive_message_id is None:
|
|
234
238
|
self._missing_id_in_message(target_message)
|
|
235
239
|
return
|
|
236
240
|
self._dispatch_message_responses[receive_message_id] = response
|
|
237
241
|
|
|
238
242
|
def _missing_id_in_message(self, message: dict):
|
|
239
|
-
handler = self.response_methods.get(message[
|
|
243
|
+
handler = self.response_methods.get(message["method"])
|
|
240
244
|
if handler is not None:
|
|
241
245
|
handler(message)
|
|
242
246
|
else:
|
|
243
|
-
logger.critical(f
|
|
247
|
+
logger.critical(f"unhandled message: {message}")
|
|
244
248
|
|
|
245
249
|
def _console_message_added(self, message: dict):
|
|
246
|
-
log_level = message[
|
|
247
|
-
text = message[
|
|
250
|
+
log_level = message["params"]["message"]["level"]
|
|
251
|
+
text = message["params"]["message"]["text"]
|
|
248
252
|
self._last_console_message = message
|
|
249
253
|
webinspector_logger_handlers[log_level](text)
|
|
250
254
|
|
|
@@ -252,7 +256,7 @@ class InspectorSession:
|
|
|
252
256
|
self._console_message_added(self._last_console_message)
|
|
253
257
|
|
|
254
258
|
def _heap_garbage_collected(self, message: dict):
|
|
255
|
-
heap_logger.debug(message[
|
|
259
|
+
heap_logger.debug(message["params"])
|
|
256
260
|
|
|
257
261
|
def _target_created(self, response: dict):
|
|
258
262
|
pass
|
|
@@ -261,4 +265,4 @@ class InspectorSession:
|
|
|
261
265
|
pass
|
|
262
266
|
|
|
263
267
|
def _target_did_commit_provisional_target(self, response: dict):
|
|
264
|
-
self.set_target_id(response[
|
|
268
|
+
self.set_target_id(response["params"]["newTargetId"])
|
|
@@ -69,14 +69,14 @@ class SeleniumApi(ABC):
|
|
|
69
69
|
def screenshot(self, filename):
|
|
70
70
|
png = self.screenshot_as_png()
|
|
71
71
|
try:
|
|
72
|
-
with open(filename,
|
|
72
|
+
with open(filename, "wb") as f:
|
|
73
73
|
f.write(png)
|
|
74
74
|
except IOError:
|
|
75
75
|
return False
|
|
76
76
|
return True
|
|
77
77
|
|
|
78
78
|
def screenshot_as_png(self):
|
|
79
|
-
return b64decode(self.screenshot_as_base64.encode(
|
|
79
|
+
return b64decode(self.screenshot_as_base64.encode("ascii"))
|
|
80
80
|
|
|
81
81
|
def get_screenshot_as_base64(self):
|
|
82
82
|
return self.screenshot_as_base64
|
|
@@ -5,7 +5,7 @@ from pymobiledevice3.exceptions import WirError
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class SessionProtocol:
|
|
8
|
-
def __init__(self, inspector, id_, app, page, method_prefix=
|
|
8
|
+
def __init__(self, inspector, id_, app, page, method_prefix="Automation"):
|
|
9
9
|
"""
|
|
10
10
|
:param pymobiledevice3.services.webinspector.WebinspectorService inspector:
|
|
11
11
|
"""
|
|
@@ -19,19 +19,24 @@ class SessionProtocol:
|
|
|
19
19
|
async def send_command(self, method, **kwargs):
|
|
20
20
|
wir_id = self._wir_messages_id
|
|
21
21
|
self._wir_messages_id += 1
|
|
22
|
-
await self.inspector.send_socket_data(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
await self.inspector.send_socket_data(
|
|
23
|
+
self.id_,
|
|
24
|
+
self.app.id_,
|
|
25
|
+
self.page.id_,
|
|
26
|
+
{
|
|
27
|
+
"method": f"{self.method_prefix}.{method}" if self.method_prefix else method,
|
|
28
|
+
"params": kwargs,
|
|
29
|
+
"id": wir_id,
|
|
30
|
+
},
|
|
31
|
+
)
|
|
27
32
|
return wir_id
|
|
28
33
|
|
|
29
34
|
async def get_response(self, wir_id):
|
|
30
35
|
response = await self.wait_for_message(wir_id)
|
|
31
|
-
if
|
|
32
|
-
return response[
|
|
33
|
-
elif
|
|
34
|
-
raise WirError(response[
|
|
36
|
+
if "result" in response:
|
|
37
|
+
return response["result"]
|
|
38
|
+
elif "error" in response:
|
|
39
|
+
raise WirError(response["error"]["message"])
|
|
35
40
|
|
|
36
41
|
async def send_receive(self, method, wait_for_response=True, **kwargs):
|
|
37
42
|
wir_id = await self.send_command(method, **kwargs)
|
|
@@ -12,19 +12,19 @@ class SwitchTo:
|
|
|
12
12
|
|
|
13
13
|
@property
|
|
14
14
|
def active_element(self) -> WebElement:
|
|
15
|
-
"""
|
|
15
|
+
"""Returns the element with focus, or BODY if nothing has focus."""
|
|
16
16
|
self.session.wait_for_navigation_to_complete()
|
|
17
|
-
elem = self.session.evaluate_js_function(
|
|
17
|
+
elem = self.session.evaluate_js_function("function() { return document.activeElement; }", include_frame=False)
|
|
18
18
|
return WebElement(self.session, elem)
|
|
19
19
|
|
|
20
20
|
@property
|
|
21
21
|
def alert(self) -> Alert:
|
|
22
|
-
"""
|
|
22
|
+
"""Switches focus to an alert on the page."""
|
|
23
23
|
return Alert(self.session)
|
|
24
24
|
|
|
25
25
|
def default_content(self):
|
|
26
|
-
"""
|
|
27
|
-
self.session.switch_to_browsing_context(
|
|
26
|
+
"""Switch focus to the default frame."""
|
|
27
|
+
self.session.switch_to_browsing_context("")
|
|
28
28
|
|
|
29
29
|
def frame(self, frame_reference):
|
|
30
30
|
"""
|
|
@@ -32,7 +32,7 @@ class SwitchTo:
|
|
|
32
32
|
:param frame_reference: The name of the window to switch to, an integer representing the index,
|
|
33
33
|
or a web element that is an (i)frame to switch to.
|
|
34
34
|
"""
|
|
35
|
-
if isinstance(frame_reference, int
|
|
35
|
+
if isinstance(frame_reference, (int, WebElement)):
|
|
36
36
|
frame = frame_reference
|
|
37
37
|
elif isinstance(frame_reference, str):
|
|
38
38
|
elem = self.session.find_elements(By.ID, frame_reference)
|
|
@@ -40,7 +40,7 @@ class SwitchTo:
|
|
|
40
40
|
elem = self.session.find_elements(By.NAME, frame_reference)
|
|
41
41
|
frame = WebElement(self.session, elem)
|
|
42
42
|
else:
|
|
43
|
-
raise
|
|
43
|
+
raise TypeError()
|
|
44
44
|
|
|
45
45
|
self.session.wait_for_navigation_to_complete()
|
|
46
46
|
if isinstance(frame, int):
|
|
@@ -48,8 +48,8 @@ class SwitchTo:
|
|
|
48
48
|
else:
|
|
49
49
|
self.session.switch_to_frame(frame_handle=frame)
|
|
50
50
|
|
|
51
|
-
def new_window(self, type_=
|
|
52
|
-
"""
|
|
51
|
+
def new_window(self, type_=""):
|
|
52
|
+
"""Switches to a new top-level browsing context."""
|
|
53
53
|
self.session.switch_to_window(self.session.create_window(type_))
|
|
54
54
|
|
|
55
55
|
def parent_frame(self):
|
|
@@ -58,10 +58,9 @@ class SwitchTo:
|
|
|
58
58
|
level browsing context, the context remains unchanged.
|
|
59
59
|
"""
|
|
60
60
|
self.session.wait_for_navigation_to_complete()
|
|
61
|
-
self.session.switch_to_browsing_context_frame(self.session.top_level_handle,
|
|
62
|
-
self.session.current_parent_handle)
|
|
61
|
+
self.session.switch_to_browsing_context_frame(self.session.top_level_handle, self.session.current_parent_handle)
|
|
63
62
|
self.session.switch_to_browsing_context(self.session.current_parent_handle)
|
|
64
63
|
|
|
65
64
|
def window(self, window_name):
|
|
66
|
-
"""
|
|
65
|
+
"""Switches focus to the specified window."""
|
|
67
66
|
self.session.switch_to_window(window_name)
|