pymobiledevice3 4.27.4__py3-none-any.whl → 5.1.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.
Files changed (143) hide show
  1. misc/plist_sniffer.py +15 -15
  2. misc/remotexpc_sniffer.py +29 -28
  3. pymobiledevice3/__main__.py +123 -98
  4. pymobiledevice3/_version.py +2 -2
  5. pymobiledevice3/bonjour.py +351 -117
  6. pymobiledevice3/ca.py +32 -24
  7. pymobiledevice3/cli/activation.py +7 -7
  8. pymobiledevice3/cli/afc.py +19 -19
  9. pymobiledevice3/cli/amfi.py +4 -4
  10. pymobiledevice3/cli/apps.py +51 -39
  11. pymobiledevice3/cli/backup.py +58 -32
  12. pymobiledevice3/cli/bonjour.py +27 -20
  13. pymobiledevice3/cli/cli_common.py +112 -81
  14. pymobiledevice3/cli/companion_proxy.py +4 -4
  15. pymobiledevice3/cli/completions.py +10 -10
  16. pymobiledevice3/cli/crash.py +37 -31
  17. pymobiledevice3/cli/developer.py +601 -519
  18. pymobiledevice3/cli/diagnostics.py +38 -33
  19. pymobiledevice3/cli/lockdown.py +82 -72
  20. pymobiledevice3/cli/mounter.py +84 -67
  21. pymobiledevice3/cli/notification.py +10 -10
  22. pymobiledevice3/cli/pcap.py +19 -14
  23. pymobiledevice3/cli/power_assertion.py +12 -10
  24. pymobiledevice3/cli/processes.py +10 -10
  25. pymobiledevice3/cli/profile.py +88 -77
  26. pymobiledevice3/cli/provision.py +17 -17
  27. pymobiledevice3/cli/remote.py +188 -111
  28. pymobiledevice3/cli/restore.py +43 -40
  29. pymobiledevice3/cli/springboard.py +30 -28
  30. pymobiledevice3/cli/syslog.py +85 -58
  31. pymobiledevice3/cli/usbmux.py +21 -20
  32. pymobiledevice3/cli/version.py +3 -2
  33. pymobiledevice3/cli/webinspector.py +156 -78
  34. pymobiledevice3/common.py +1 -1
  35. pymobiledevice3/exceptions.py +154 -60
  36. pymobiledevice3/irecv.py +49 -53
  37. pymobiledevice3/irecv_devices.py +1489 -492
  38. pymobiledevice3/lockdown.py +400 -251
  39. pymobiledevice3/lockdown_service_provider.py +5 -7
  40. pymobiledevice3/osu/os_utils.py +18 -9
  41. pymobiledevice3/osu/posix_util.py +28 -15
  42. pymobiledevice3/osu/win_util.py +14 -8
  43. pymobiledevice3/pair_records.py +19 -19
  44. pymobiledevice3/remote/common.py +4 -4
  45. pymobiledevice3/remote/core_device/app_service.py +94 -67
  46. pymobiledevice3/remote/core_device/core_device_service.py +17 -14
  47. pymobiledevice3/remote/core_device/device_info.py +5 -5
  48. pymobiledevice3/remote/core_device/diagnostics_service.py +10 -8
  49. pymobiledevice3/remote/core_device/file_service.py +47 -33
  50. pymobiledevice3/remote/remote_service_discovery.py +53 -35
  51. pymobiledevice3/remote/remotexpc.py +64 -42
  52. pymobiledevice3/remote/tunnel_service.py +383 -297
  53. pymobiledevice3/remote/utils.py +14 -13
  54. pymobiledevice3/remote/xpc_message.py +145 -125
  55. pymobiledevice3/resources/dsc_uuid_map.py +19 -19
  56. pymobiledevice3/resources/firmware_notifications.py +16 -16
  57. pymobiledevice3/restore/asr.py +27 -27
  58. pymobiledevice3/restore/base_restore.py +90 -47
  59. pymobiledevice3/restore/consts.py +87 -66
  60. pymobiledevice3/restore/device.py +11 -11
  61. pymobiledevice3/restore/fdr.py +46 -46
  62. pymobiledevice3/restore/ftab.py +19 -19
  63. pymobiledevice3/restore/img4.py +130 -133
  64. pymobiledevice3/restore/mbn.py +587 -0
  65. pymobiledevice3/restore/recovery.py +125 -135
  66. pymobiledevice3/restore/restore.py +535 -523
  67. pymobiledevice3/restore/restore_options.py +122 -115
  68. pymobiledevice3/restore/restored_client.py +25 -22
  69. pymobiledevice3/restore/tss.py +378 -270
  70. pymobiledevice3/service_connection.py +50 -46
  71. pymobiledevice3/services/accessibilityaudit.py +137 -127
  72. pymobiledevice3/services/afc.py +352 -292
  73. pymobiledevice3/services/amfi.py +21 -18
  74. pymobiledevice3/services/companion.py +23 -19
  75. pymobiledevice3/services/crash_reports.py +61 -47
  76. pymobiledevice3/services/debugserver_applist.py +3 -3
  77. pymobiledevice3/services/device_arbitration.py +8 -8
  78. pymobiledevice3/services/device_link.py +56 -48
  79. pymobiledevice3/services/diagnostics.py +971 -968
  80. pymobiledevice3/services/dtfetchsymbols.py +8 -8
  81. pymobiledevice3/services/dvt/dvt_secure_socket_proxy.py +4 -4
  82. pymobiledevice3/services/dvt/dvt_testmanaged_proxy.py +4 -4
  83. pymobiledevice3/services/dvt/instruments/activity_trace_tap.py +85 -74
  84. pymobiledevice3/services/dvt/instruments/application_listing.py +2 -3
  85. pymobiledevice3/services/dvt/instruments/condition_inducer.py +7 -6
  86. pymobiledevice3/services/dvt/instruments/core_profile_session_tap.py +466 -384
  87. pymobiledevice3/services/dvt/instruments/device_info.py +11 -11
  88. pymobiledevice3/services/dvt/instruments/energy_monitor.py +1 -1
  89. pymobiledevice3/services/dvt/instruments/graphics.py +1 -1
  90. pymobiledevice3/services/dvt/instruments/location_simulation.py +1 -1
  91. pymobiledevice3/services/dvt/instruments/location_simulation_base.py +10 -10
  92. pymobiledevice3/services/dvt/instruments/network_monitor.py +17 -17
  93. pymobiledevice3/services/dvt/instruments/notifications.py +1 -1
  94. pymobiledevice3/services/dvt/instruments/process_control.py +25 -10
  95. pymobiledevice3/services/dvt/instruments/screenshot.py +2 -2
  96. pymobiledevice3/services/dvt/instruments/sysmontap.py +15 -15
  97. pymobiledevice3/services/dvt/testmanaged/xcuitest.py +42 -52
  98. pymobiledevice3/services/file_relay.py +10 -10
  99. pymobiledevice3/services/heartbeat.py +8 -7
  100. pymobiledevice3/services/house_arrest.py +12 -15
  101. pymobiledevice3/services/installation_proxy.py +119 -100
  102. pymobiledevice3/services/lockdown_service.py +12 -5
  103. pymobiledevice3/services/misagent.py +22 -19
  104. pymobiledevice3/services/mobile_activation.py +84 -72
  105. pymobiledevice3/services/mobile_config.py +331 -301
  106. pymobiledevice3/services/mobile_image_mounter.py +137 -116
  107. pymobiledevice3/services/mobilebackup2.py +188 -150
  108. pymobiledevice3/services/notification_proxy.py +11 -11
  109. pymobiledevice3/services/os_trace.py +128 -74
  110. pymobiledevice3/services/pcapd.py +306 -306
  111. pymobiledevice3/services/power_assertion.py +10 -9
  112. pymobiledevice3/services/preboard.py +4 -4
  113. pymobiledevice3/services/remote_fetch_symbols.py +16 -14
  114. pymobiledevice3/services/remote_server.py +176 -146
  115. pymobiledevice3/services/restore_service.py +16 -16
  116. pymobiledevice3/services/screenshot.py +13 -10
  117. pymobiledevice3/services/simulate_location.py +7 -7
  118. pymobiledevice3/services/springboard.py +15 -15
  119. pymobiledevice3/services/syslog.py +5 -5
  120. pymobiledevice3/services/web_protocol/alert.py +3 -3
  121. pymobiledevice3/services/web_protocol/automation_session.py +183 -179
  122. pymobiledevice3/services/web_protocol/cdp_screencast.py +44 -36
  123. pymobiledevice3/services/web_protocol/cdp_server.py +19 -19
  124. pymobiledevice3/services/web_protocol/cdp_target.py +411 -373
  125. pymobiledevice3/services/web_protocol/driver.py +47 -45
  126. pymobiledevice3/services/web_protocol/element.py +74 -63
  127. pymobiledevice3/services/web_protocol/inspector_session.py +106 -102
  128. pymobiledevice3/services/web_protocol/selenium_api.py +3 -3
  129. pymobiledevice3/services/web_protocol/session_protocol.py +15 -10
  130. pymobiledevice3/services/web_protocol/switch_to.py +11 -12
  131. pymobiledevice3/services/webinspector.py +142 -116
  132. pymobiledevice3/tcp_forwarder.py +35 -22
  133. pymobiledevice3/tunneld/api.py +20 -15
  134. pymobiledevice3/tunneld/server.py +310 -193
  135. pymobiledevice3/usbmux.py +197 -148
  136. pymobiledevice3/utils.py +14 -11
  137. {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/METADATA +1 -2
  138. pymobiledevice3-5.1.2.dist-info/RECORD +173 -0
  139. pymobiledevice3-4.27.4.dist-info/RECORD +0 -172
  140. {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/WHEEL +0 -0
  141. {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/entry_points.txt +0 -0
  142. {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/licenses/LICENSE +0 -0
  143. {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/top_level.txt +0 -0
pymobiledevice3/usbmux.py CHANGED
@@ -5,76 +5,115 @@ import time
5
5
  from dataclasses import dataclass
6
6
  from typing import Optional
7
7
 
8
- from construct import Const, CString, Enum, FixedSized, GreedyBytes, Int16ul, Int32ul, Padding, Prefixed, StreamError, \
9
- Struct, Switch, this
8
+ from construct import (
9
+ Const,
10
+ CString,
11
+ Enum,
12
+ FixedSized,
13
+ GreedyBytes,
14
+ Int16ul,
15
+ Int32ul,
16
+ Padding,
17
+ Prefixed,
18
+ StreamError,
19
+ Struct,
20
+ Switch,
21
+ this,
22
+ )
10
23
 
11
- from pymobiledevice3.exceptions import BadCommandError, BadDevError, ConnectionFailedError, \
12
- ConnectionFailedToUsbmuxdError, MuxException, MuxVersionError, NotPairedError
24
+ from pymobiledevice3.exceptions import (
25
+ BadCommandError,
26
+ BadDevError,
27
+ ConnectionFailedError,
28
+ ConnectionFailedToUsbmuxdError,
29
+ MuxException,
30
+ MuxVersionError,
31
+ NotPairedError,
32
+ )
13
33
  from pymobiledevice3.osu.os_utils import get_os_utils
14
34
 
15
- usbmuxd_version = Enum(Int32ul,
16
- BINARY=0,
17
- PLIST=1,
18
- )
19
-
20
- usbmuxd_result = Enum(Int32ul,
21
- OK=0,
22
- BADCOMMAND=1,
23
- BADDEV=2,
24
- CONNREFUSED=3,
25
- NOSUCHSERVICE=4,
26
- BADVERSION=6,
27
- )
28
-
29
- usbmuxd_msgtype = Enum(Int32ul,
30
- RESULT=1,
31
- CONNECT=2,
32
- LISTEN=3,
33
- ADD=4,
34
- REMOVE=5,
35
- PAIRED=6,
36
- PLIST=8,
37
- )
35
+ usbmuxd_version = Enum(
36
+ Int32ul,
37
+ BINARY=0,
38
+ PLIST=1,
39
+ )
40
+
41
+ usbmuxd_result = Enum(
42
+ Int32ul,
43
+ OK=0,
44
+ BADCOMMAND=1,
45
+ BADDEV=2,
46
+ CONNREFUSED=3,
47
+ NOSUCHSERVICE=4,
48
+ BADVERSION=6,
49
+ )
50
+
51
+ usbmuxd_msgtype = Enum(
52
+ Int32ul,
53
+ RESULT=1,
54
+ CONNECT=2,
55
+ LISTEN=3,
56
+ ADD=4,
57
+ REMOVE=5,
58
+ PAIRED=6,
59
+ PLIST=8,
60
+ )
38
61
 
39
62
  usbmuxd_header = Struct(
40
- 'version' / usbmuxd_version, # protocol version
41
- 'message' / usbmuxd_msgtype, # message type
42
- 'tag' / Int32ul, # responses to this query will echo back this tag
63
+ "version" / usbmuxd_version, # protocol version
64
+ "message" / usbmuxd_msgtype, # message type
65
+ "tag" / Int32ul, # responses to this query will echo back this tag
43
66
  )
44
67
 
45
- usbmuxd_request = Prefixed(Int32ul, Struct(
46
- 'header' / usbmuxd_header,
47
- 'data' / Switch(this.header.message, {
48
- usbmuxd_msgtype.CONNECT: Struct(
49
- 'device_id' / Int32ul,
50
- 'port' / Int16ul, # TCP port number
51
- 'reserved' / Const(0, Int16ul),
68
+ usbmuxd_request = Prefixed(
69
+ Int32ul,
70
+ Struct(
71
+ "header" / usbmuxd_header,
72
+ "data"
73
+ / Switch(
74
+ this.header.message,
75
+ {
76
+ usbmuxd_msgtype.CONNECT: Struct(
77
+ "device_id" / Int32ul,
78
+ "port" / Int16ul, # TCP port number
79
+ "reserved" / Const(0, Int16ul),
80
+ ),
81
+ usbmuxd_msgtype.PLIST: GreedyBytes,
82
+ },
52
83
  ),
53
- usbmuxd_msgtype.PLIST: GreedyBytes,
54
- }),
55
- ), includelength=True)
84
+ ),
85
+ includelength=True,
86
+ )
56
87
 
57
88
  usbmuxd_device_record = Struct(
58
- 'device_id' / Int32ul,
59
- 'product_id' / Int16ul,
60
- 'serial_number' / FixedSized(256, CString('ascii')),
89
+ "device_id" / Int32ul,
90
+ "product_id" / Int16ul,
91
+ "serial_number" / FixedSized(256, CString("ascii")),
61
92
  Padding(2),
62
- 'location' / Int32ul
93
+ "location" / Int32ul,
63
94
  )
64
95
 
65
- usbmuxd_response = Prefixed(Int32ul, Struct(
66
- 'header' / usbmuxd_header,
67
- 'data' / Switch(this.header.message, {
68
- usbmuxd_msgtype.RESULT: Struct(
69
- 'result' / usbmuxd_result,
96
+ usbmuxd_response = Prefixed(
97
+ Int32ul,
98
+ Struct(
99
+ "header" / usbmuxd_header,
100
+ "data"
101
+ / Switch(
102
+ this.header.message,
103
+ {
104
+ usbmuxd_msgtype.RESULT: Struct(
105
+ "result" / usbmuxd_result,
106
+ ),
107
+ usbmuxd_msgtype.ADD: usbmuxd_device_record,
108
+ usbmuxd_msgtype.REMOVE: Struct(
109
+ "device_id" / Int32ul,
110
+ ),
111
+ usbmuxd_msgtype.PLIST: GreedyBytes,
112
+ },
70
113
  ),
71
- usbmuxd_msgtype.ADD: usbmuxd_device_record,
72
- usbmuxd_msgtype.REMOVE: Struct(
73
- 'device_id' / Int32ul,
74
- ),
75
- usbmuxd_msgtype.PLIST: GreedyBytes,
76
- }),
77
- ), includelength=True)
114
+ ),
115
+ includelength=True,
116
+ )
78
117
 
79
118
 
80
119
  @dataclass
@@ -87,24 +126,24 @@ class MuxDevice:
87
126
  mux = create_mux(usbmux_address=usbmux_address)
88
127
  try:
89
128
  return mux.connect(self, port)
90
- except: # noqa: E722
129
+ except:
91
130
  mux.close()
92
131
  raise
93
132
 
94
133
  @property
95
134
  def is_usb(self) -> bool:
96
- return self.connection_type == 'USB'
135
+ return self.connection_type == "USB"
97
136
 
98
137
  @property
99
138
  def is_network(self) -> bool:
100
- return self.connection_type == 'Network'
139
+ return self.connection_type == "Network"
101
140
 
102
141
  def matches_udid(self, udid: str) -> bool:
103
- return self.serial.replace('-', '') == udid.replace('-', '')
142
+ return self.serial.replace("-", "") == udid.replace("-", "")
104
143
 
105
144
 
106
145
  class SafeStreamSocket:
107
- """ wrapper to native python socket object to be used with construct as a stream """
146
+ """wrapper to native python socket object to be used with construct as a stream"""
108
147
 
109
148
  def __init__(self, address, family):
110
149
  self._offset = 0
@@ -117,12 +156,12 @@ class SafeStreamSocket:
117
156
  return len(msg)
118
157
 
119
158
  def recv(self, size: int) -> bytes:
120
- msg = b''
159
+ msg = b""
121
160
  while len(msg) < size:
122
161
  chunk = self.sock.recv(size - len(msg))
123
162
  self._offset += len(chunk)
124
163
  if not chunk:
125
- raise MuxException('socket connection broken')
164
+ raise MuxException("socket connection broken")
126
165
  msg += chunk
127
166
  return msg
128
167
 
@@ -144,18 +183,18 @@ class SafeStreamSocket:
144
183
 
145
184
  class MuxConnection:
146
185
  # used on Windows
147
- ITUNES_HOST = ('127.0.0.1', 27015)
186
+ ITUNES_HOST = ("127.0.0.1", 27015)
148
187
 
149
188
  # used for macOS and Linux
150
- USBMUXD_PIPE = '/var/run/usbmuxd'
189
+ USBMUXD_PIPE = "/var/run/usbmuxd"
151
190
 
152
191
  @staticmethod
153
192
  def create_usbmux_socket(usbmux_address: Optional[str] = None) -> SafeStreamSocket:
154
193
  try:
155
194
  if usbmux_address is not None:
156
- if ':' in usbmux_address:
195
+ if ":" in usbmux_address:
157
196
  # assume tcp address
158
- hostname, port = usbmux_address.split(':')
197
+ hostname, port = usbmux_address.split(":")
159
198
  port = int(port)
160
199
  address = (hostname, port)
161
200
  family = socket.AF_INET
@@ -166,23 +205,25 @@ class MuxConnection:
166
205
  else:
167
206
  address, family = get_os_utils().usbmux_address
168
207
  return SafeStreamSocket(address, family)
169
- except ConnectionRefusedError:
170
- raise ConnectionFailedToUsbmuxdError()
208
+ except ConnectionRefusedError as e:
209
+ raise ConnectionFailedToUsbmuxdError() from e
171
210
 
172
211
  @staticmethod
173
212
  def create(usbmux_address: Optional[str] = None):
174
213
  # first attempt to connect with possibly the wrong version header (plist protocol)
175
214
  sock = MuxConnection.create_usbmux_socket(usbmux_address=usbmux_address)
176
215
 
177
- message = usbmuxd_request.build({
178
- 'header': {'version': usbmuxd_version.PLIST, 'message': usbmuxd_msgtype.PLIST, 'tag': 1},
179
- 'data': plistlib.dumps({'MessageType': 'ReadBUID'})
180
- })
181
- sock.send(message)
182
- response = usbmuxd_response.parse_stream(sock)
183
-
184
- # if we sent a bad request, we should re-create the socket in the correct version this time
185
- sock.close()
216
+ try:
217
+ message = usbmuxd_request.build({
218
+ "header": {"version": usbmuxd_version.PLIST, "message": usbmuxd_msgtype.PLIST, "tag": 1},
219
+ "data": plistlib.dumps({"MessageType": "ReadBUID"}),
220
+ })
221
+ sock.send(message)
222
+ response = usbmuxd_response.parse_stream(sock)
223
+
224
+ finally:
225
+ # If we sent a bad request, we should re-create the socket in the correct version this time
226
+ sock.close()
186
227
  sock = MuxConnection.create_usbmux_socket(usbmux_address=usbmux_address)
187
228
 
188
229
  if response.header.version == usbmuxd_version.BINARY:
@@ -190,7 +231,7 @@ class MuxConnection:
190
231
  elif response.header.version == usbmuxd_version.PLIST:
191
232
  return PlistMuxConnection(sock)
192
233
 
193
- raise MuxVersionError(f'usbmuxd returned unsupported version: {response.version}')
234
+ raise MuxVersionError(f"usbmuxd returned unsupported version: {response.version}")
194
235
 
195
236
  def __init__(self, sock: SafeStreamSocket):
196
237
  self._sock = sock
@@ -207,30 +248,30 @@ class MuxConnection:
207
248
 
208
249
  @abc.abstractmethod
209
250
  def _connect(self, device_id: int, port: int):
210
- """ initiate a "Connect" request to target port """
251
+ """initiate a "Connect" request to target port"""
211
252
  pass
212
253
 
213
254
  @abc.abstractmethod
214
- def get_device_list(self, timeout: float = None):
255
+ def get_device_list(self, timeout: Optional[float] = None):
215
256
  """
216
257
  request an update to current device list
217
258
  """
218
259
  pass
219
260
 
220
261
  def connect(self, device: MuxDevice, port: int) -> socket.socket:
221
- """ connect to a relay port on target machine and get a raw python socket object for the connection """
262
+ """connect to a relay port on target machine and get a raw python socket object for the connection"""
222
263
  self._connect(device.devid, socket.htons(port))
223
264
  self._connected = True
224
265
  return self._sock.sock
225
266
 
226
267
  def close(self):
227
- """ close current socket """
268
+ """close current socket"""
228
269
  self._sock.close()
229
270
 
230
271
  def _assert_not_connected(self):
231
- """ verify active state is in state for control messages """
272
+ """verify active state is in state for control messages"""
232
273
  if self._connected:
233
- raise MuxException('Mux is connected, cannot issue control packets')
274
+ raise MuxException("Mux is connected, cannot issue control packets")
234
275
 
235
276
  def _raise_mux_exception(self, result: int, message: Optional[str] = None) -> None:
236
277
  exceptions = {
@@ -251,14 +292,14 @@ class MuxConnection:
251
292
 
252
293
 
253
294
  class BinaryMuxConnection(MuxConnection):
254
- """ old binary protocol """
295
+ """old binary protocol"""
255
296
 
256
297
  def __init__(self, sock: SafeStreamSocket):
257
298
  super().__init__(sock)
258
299
  self._version = usbmuxd_version.BINARY
259
300
 
260
- def get_device_list(self, timeout: float = None):
261
- """ use timeout to wait for the device list to be fully populated """
301
+ def get_device_list(self, timeout: Optional[float] = None):
302
+ """use timeout to wait for the device list to be fully populated"""
262
303
  self._assert_not_connected()
263
304
  end = time.time() + timeout
264
305
  self.listen()
@@ -268,55 +309,54 @@ class BinaryMuxConnection(MuxConnection):
268
309
  self._receive_device_state_update()
269
310
  except (BlockingIOError, StreamError):
270
311
  continue
271
- except IOError:
312
+ except OSError as e:
272
313
  try:
273
314
  self._sock.setblocking(True)
274
315
  self.close()
275
316
  except OSError:
276
317
  pass
277
- raise MuxException('Exception in listener socket')
318
+ raise MuxException("Exception in listener socket") from e
278
319
 
279
320
  def listen(self):
280
- """ start listening for events of attached and detached devices """
321
+ """start listening for events of attached and detached devices"""
281
322
  self._send_receive(usbmuxd_msgtype.LISTEN)
282
323
 
283
324
  def _connect(self, device_id: int, port: int):
284
- self._send({'header': {'version': self._version,
285
- 'message': usbmuxd_msgtype.CONNECT,
286
- 'tag': self._tag},
287
- 'data': {'device_id': device_id, 'port': port},
288
- })
325
+ self._send({
326
+ "header": {"version": self._version, "message": usbmuxd_msgtype.CONNECT, "tag": self._tag},
327
+ "data": {"device_id": device_id, "port": port},
328
+ })
289
329
  response = self._receive()
290
330
  if response.header.message != usbmuxd_msgtype.RESULT:
291
- raise MuxException(f'unexpected message type received: {response}')
331
+ raise MuxException(f"unexpected message type received: {response}")
292
332
 
293
333
  if response.data.result != usbmuxd_result.OK:
294
- raise self._raise_mux_exception(int(response.data.result),
295
- f'failed to connect to device: {device_id} at port: {port}. reason: '
296
- f'{response.data.result}')
334
+ raise self._raise_mux_exception(
335
+ int(response.data.result),
336
+ f"failed to connect to device: {device_id} at port: {port}. reason: {response.data.result}",
337
+ )
297
338
 
298
339
  def _send(self, data: dict) -> None:
299
340
  self._assert_not_connected()
300
341
  self._sock.send(usbmuxd_request.build(data))
301
342
  self._tag += 1
302
343
 
303
- def _receive(self, expected_tag: int = None):
344
+ def _receive(self, expected_tag: Optional[int] = None):
304
345
  self._assert_not_connected()
305
346
  response = usbmuxd_response.parse_stream(self._sock)
306
347
  if expected_tag and response.header.tag != expected_tag:
307
- raise MuxException(f'Reply tag mismatch: expected {expected_tag}, got {response.header.tag}')
348
+ raise MuxException(f"Reply tag mismatch: expected {expected_tag}, got {response.header.tag}")
308
349
  return response
309
350
 
310
351
  def _send_receive(self, message_type: int):
311
- self._send({'header': {'version': self._version, 'message': message_type, 'tag': self._tag},
312
- 'data': b''})
352
+ self._send({"header": {"version": self._version, "message": message_type, "tag": self._tag}, "data": b""})
313
353
  response = self._receive(self._tag - 1)
314
354
  if response.header.message != usbmuxd_msgtype.RESULT:
315
- raise MuxException(f'unexpected message type received: {response}')
355
+ raise MuxException(f"unexpected message type received: {response}")
316
356
 
317
357
  result = response.data.result
318
358
  if result != usbmuxd_result.OK:
319
- raise self._raise_mux_exception(int(result), f'{message_type} failed: error {result}')
359
+ raise self._raise_mux_exception(int(result), f"{message_type} failed: error {result}")
320
360
 
321
361
  def _add_device(self, device: MuxDevice):
322
362
  self.devices.append(device)
@@ -328,11 +368,11 @@ class BinaryMuxConnection(MuxConnection):
328
368
  response = self._receive()
329
369
  if response.header.message == usbmuxd_msgtype.ADD:
330
370
  # old protocol only supported USB devices
331
- self._add_device(MuxDevice(response.data.device_id, response.data.serial_number, 'USB'))
371
+ self._add_device(MuxDevice(response.data.device_id, response.data.serial_number, "USB"))
332
372
  elif response.header.message == usbmuxd_msgtype.REMOVE:
333
373
  self._remove_device(response.data.device_id)
334
374
  else:
335
- raise MuxException(f'Invalid packet type received: {response}')
375
+ raise MuxException(f"Invalid packet type received: {response}")
336
376
 
337
377
 
338
378
  class PlistMuxConnection(BinaryMuxConnection):
@@ -341,71 +381,77 @@ class PlistMuxConnection(BinaryMuxConnection):
341
381
  self._version = usbmuxd_version.PLIST
342
382
 
343
383
  def listen(self) -> None:
344
- self._send_receive({'MessageType': 'Listen'})
384
+ self._send_receive({"MessageType": "Listen"})
345
385
 
346
386
  def get_pair_record(self, serial: str) -> dict:
347
387
  # serials are saved inside usbmuxd without '-'
348
- self._send({'MessageType': 'ReadPairRecord', 'PairRecordID': serial})
388
+ self._send({"MessageType": "ReadPairRecord", "PairRecordID": serial})
349
389
  response = self._receive(self._tag - 1)
350
- pair_record = response.get('PairRecordData')
390
+ pair_record = response.get("PairRecordData")
351
391
  if pair_record is None:
352
- raise NotPairedError('device should be paired first')
392
+ raise NotPairedError("device should be paired first")
353
393
  return plistlib.loads(pair_record)
354
394
 
355
- def get_device_list(self, timeout: float = None) -> None:
356
- """ get device list synchronously without waiting the timeout """
395
+ def get_device_list(self, timeout: Optional[float] = None) -> None:
396
+ """get device list synchronously without waiting the timeout"""
357
397
  self.devices = []
358
- self._send({'MessageType': 'ListDevices'})
398
+ self._send({"MessageType": "ListDevices"})
359
399
  response = self._receive(self._tag - 1)
360
- device_list = response.get('DeviceList')
400
+ device_list = response.get("DeviceList")
361
401
  if device_list is None:
362
- raise MuxException(f'Got an invalid response from usbmux: {response}')
402
+ raise MuxException(f"Got an invalid response from usbmux: {response}")
363
403
  for response in device_list:
364
- if response['MessageType'] == 'Attached':
365
- super()._add_device(MuxDevice(response['DeviceID'], response['Properties']['SerialNumber'],
366
- response['Properties']['ConnectionType']))
367
- elif response['MessageType'] == 'Detached':
368
- super()._remove_device(response['DeviceID'])
404
+ if response["MessageType"] == "Attached":
405
+ super()._add_device(
406
+ MuxDevice(
407
+ response["DeviceID"],
408
+ response["Properties"]["SerialNumber"],
409
+ response["Properties"]["ConnectionType"],
410
+ )
411
+ )
412
+ elif response["MessageType"] == "Detached":
413
+ super()._remove_device(response["DeviceID"])
369
414
  else:
370
- raise MuxException(f'Invalid packet type received: {response}')
415
+ raise MuxException(f"Invalid packet type received: {response}")
371
416
 
372
417
  def get_buid(self) -> str:
373
- """ get SystemBUID """
374
- self._send({'MessageType': 'ReadBUID'})
375
- return self._receive(self._tag - 1)['BUID']
418
+ """get SystemBUID"""
419
+ self._send({"MessageType": "ReadBUID"})
420
+ return self._receive(self._tag - 1)["BUID"]
376
421
 
377
422
  def save_pair_record(self, serial: str, device_id: int, record_data: bytes):
378
423
  # serials are saved inside usbmuxd without '-'
379
- self._send_receive({'MessageType': 'SavePairRecord',
380
- 'PairRecordID': serial,
381
- 'PairRecordData': record_data,
382
- 'DeviceID': device_id})
424
+ self._send_receive({
425
+ "MessageType": "SavePairRecord",
426
+ "PairRecordID": serial,
427
+ "PairRecordData": record_data,
428
+ "DeviceID": device_id,
429
+ })
383
430
 
384
431
  def _connect(self, device_id: int, port: int):
385
- self._send_receive({'MessageType': 'Connect', 'DeviceID': device_id, 'PortNumber': port})
432
+ self._send_receive({"MessageType": "Connect", "DeviceID": device_id, "PortNumber": port})
386
433
 
387
434
  def _send(self, data: dict):
388
- request = {'ClientVersionString': 'qt4i-usbmuxd', 'ProgName': 'pymobiledevice3', 'kLibUSBMuxVersion': 3}
435
+ request = {"ClientVersionString": "qt4i-usbmuxd", "ProgName": "pymobiledevice3", "kLibUSBMuxVersion": 3}
389
436
  request.update(data)
390
- super()._send({'header': {'version': self._version,
391
- 'message': usbmuxd_msgtype.PLIST,
392
- 'tag': self._tag},
393
- 'data': plistlib.dumps(request),
394
- })
437
+ super()._send({
438
+ "header": {"version": self._version, "message": usbmuxd_msgtype.PLIST, "tag": self._tag},
439
+ "data": plistlib.dumps(request),
440
+ })
395
441
 
396
- def _receive(self, expected_tag: int = None) -> dict:
442
+ def _receive(self, expected_tag: Optional[int] = None) -> dict:
397
443
  response = super()._receive(expected_tag=expected_tag)
398
444
  if response.header.message != usbmuxd_msgtype.PLIST:
399
- raise MuxException(f'Received non-plist type {response}')
445
+ raise MuxException(f"Received non-plist type {response}")
400
446
  return plistlib.loads(response.data)
401
447
 
402
448
  def _send_receive(self, data: dict):
403
449
  self._send(data)
404
450
  response = self._receive(self._tag - 1)
405
- if response['MessageType'] != 'Result':
406
- raise MuxException(f'got an invalid message: {response}')
407
- if response['Number'] != 0:
408
- raise self._raise_mux_exception(response['Number'], f'got an error message: {response}')
451
+ if response["MessageType"] != "Result":
452
+ raise MuxException(f"got an invalid message: {response}")
453
+ if response["Number"] != 0:
454
+ raise self._raise_mux_exception(response["Number"], f"got an error message: {response}")
409
455
 
410
456
 
411
457
  def create_mux(usbmux_address: Optional[str] = None) -> MuxConnection:
@@ -414,14 +460,17 @@ def create_mux(usbmux_address: Optional[str] = None) -> MuxConnection:
414
460
 
415
461
  def list_devices(usbmux_address: Optional[str] = None) -> list[MuxDevice]:
416
462
  mux = create_mux(usbmux_address=usbmux_address)
417
- mux.get_device_list(0.1)
418
- devices = mux.devices
419
- mux.close()
463
+ try:
464
+ mux.get_device_list(0.1)
465
+ devices = mux.devices
466
+ finally:
467
+ mux.close()
420
468
  return devices
421
469
 
422
470
 
423
- def select_device(udid: str = None, connection_type: str = None, usbmux_address: Optional[str] = None) \
424
- -> Optional[MuxDevice]:
471
+ def select_device(
472
+ udid: Optional[str] = None, connection_type: Optional[str] = None, usbmux_address: Optional[str] = None
473
+ ) -> Optional[MuxDevice]:
425
474
  """
426
475
  select a UsbMux device according to given arguments.
427
476
  if more than one device could be selected, always prefer the usb one.
pymobiledevice3/utils.py CHANGED
@@ -15,16 +15,16 @@ def plist_access_path(d, path: tuple, type_=None, required=False):
15
15
  if d is None:
16
16
  break
17
17
 
18
- if type_ == bool and isinstance(d, str):
19
- if d.lower() not in ('true', 'false'):
18
+ if type_ is bool and isinstance(d, str):
19
+ if d.lower() not in ("true", "false"):
20
20
  raise ValueError()
21
- d = 'true' == d.lower()
21
+ d = d.lower() == "true"
22
22
  elif type_ is not None and not isinstance(d, type_):
23
23
  # wrong type
24
24
  d = None
25
25
 
26
26
  if d is None and required:
27
- raise KeyError(f'path: {path} doesn\'t exist in given plist object')
27
+ raise KeyError(f"path: {path} doesn't exist in given plist object")
28
28
 
29
29
  return d
30
30
 
@@ -35,7 +35,7 @@ def bytes_to_uint(b: bytes):
35
35
 
36
36
  def try_decode(s: bytes):
37
37
  try:
38
- return s.decode('utf8')
38
+ return s.decode("utf8")
39
39
  except UnicodeDecodeError:
40
40
  return s
41
41
 
@@ -45,7 +45,7 @@ def asyncio_print_traceback(f: Callable):
45
45
  async def wrapper(*args, **kwargs):
46
46
  try:
47
47
  return await f(*args, **kwargs)
48
- except Exception as e: # noqa: E72
48
+ except (Exception, RuntimeError) as e:
49
49
  if not isinstance(e, asyncio.CancelledError):
50
50
  traceback.print_exc()
51
51
  raise
@@ -57,7 +57,7 @@ def get_asyncio_loop() -> asyncio.AbstractEventLoop:
57
57
  try:
58
58
  loop = asyncio.get_running_loop()
59
59
  if loop.is_closed():
60
- raise RuntimeError('The existing loop is closed.')
60
+ raise RuntimeError("The existing loop is closed.")
61
61
  except RuntimeError:
62
62
  # This happens when there is no current event loop
63
63
  loop = asyncio.new_event_loop()
@@ -67,14 +67,17 @@ def get_asyncio_loop() -> asyncio.AbstractEventLoop:
67
67
 
68
68
  def file_download(url: str, outfile: Path, chunk_size=1024) -> None:
69
69
  resp = requests.get(url, stream=True)
70
- total = int(resp.headers.get('content-length', 0))
71
- with outfile.open('wb') as file, tqdm(
70
+ total = int(resp.headers.get("content-length", 0))
71
+ with (
72
+ outfile.open("wb") as file,
73
+ tqdm(
72
74
  desc=outfile.name,
73
75
  total=total,
74
- unit='iB',
76
+ unit="iB",
75
77
  unit_scale=True,
76
78
  unit_divisor=1024,
77
- ) as bar:
79
+ ) as bar,
80
+ ):
78
81
  for data in resp.iter_content(chunk_size=chunk_size):
79
82
  size = file.write(data)
80
83
  bar.update(size)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pymobiledevice3
3
- Version: 4.27.4
3
+ Version: 5.1.2
4
4
  Summary: Pure python3 implementation for working with iDevices (iPhone, etc...)
5
5
  Author-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>
6
6
  Maintainer-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>
@@ -47,7 +47,6 @@ Requires-Dist: nest_asyncio>=1.5.5
47
47
  Requires-Dist: Pillow
48
48
  Requires-Dist: inquirer3>=0.6.0
49
49
  Requires-Dist: ipsw_parser>=1.3.4
50
- Requires-Dist: zeroconf>=0.132.2
51
50
  Requires-Dist: ifaddr
52
51
  Requires-Dist: hyperframe
53
52
  Requires-Dist: srptools