pymobiledevice3 5.0.4__py3-none-any.whl → 7.0.6__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 (79) hide show
  1. misc/understanding_idevice_protocol_layers.md +10 -5
  2. pymobiledevice3/__main__.py +171 -46
  3. pymobiledevice3/_version.py +2 -2
  4. pymobiledevice3/bonjour.py +22 -21
  5. pymobiledevice3/cli/activation.py +24 -22
  6. pymobiledevice3/cli/afc.py +49 -41
  7. pymobiledevice3/cli/amfi.py +13 -18
  8. pymobiledevice3/cli/apps.py +71 -65
  9. pymobiledevice3/cli/backup.py +134 -93
  10. pymobiledevice3/cli/bonjour.py +31 -29
  11. pymobiledevice3/cli/cli_common.py +175 -232
  12. pymobiledevice3/cli/companion_proxy.py +12 -12
  13. pymobiledevice3/cli/crash.py +95 -52
  14. pymobiledevice3/cli/developer/__init__.py +62 -0
  15. pymobiledevice3/cli/developer/accessibility/__init__.py +65 -0
  16. pymobiledevice3/cli/developer/accessibility/settings.py +43 -0
  17. pymobiledevice3/cli/developer/arbitration.py +50 -0
  18. pymobiledevice3/cli/developer/condition.py +33 -0
  19. pymobiledevice3/cli/developer/core_device.py +294 -0
  20. pymobiledevice3/cli/developer/debugserver.py +244 -0
  21. pymobiledevice3/cli/developer/dvt/__init__.py +438 -0
  22. pymobiledevice3/cli/developer/dvt/core_profile_session.py +295 -0
  23. pymobiledevice3/cli/developer/dvt/simulate_location.py +56 -0
  24. pymobiledevice3/cli/developer/dvt/sysmon/__init__.py +69 -0
  25. pymobiledevice3/cli/developer/dvt/sysmon/process.py +188 -0
  26. pymobiledevice3/cli/developer/fetch_symbols.py +108 -0
  27. pymobiledevice3/cli/developer/simulate_location.py +51 -0
  28. pymobiledevice3/cli/diagnostics/__init__.py +75 -0
  29. pymobiledevice3/cli/diagnostics/battery.py +47 -0
  30. pymobiledevice3/cli/idam.py +42 -0
  31. pymobiledevice3/cli/lockdown.py +70 -75
  32. pymobiledevice3/cli/mounter.py +99 -57
  33. pymobiledevice3/cli/notification.py +38 -26
  34. pymobiledevice3/cli/pcap.py +36 -20
  35. pymobiledevice3/cli/power_assertion.py +15 -16
  36. pymobiledevice3/cli/processes.py +11 -17
  37. pymobiledevice3/cli/profile.py +120 -75
  38. pymobiledevice3/cli/provision.py +27 -26
  39. pymobiledevice3/cli/remote.py +109 -100
  40. pymobiledevice3/cli/restore.py +134 -129
  41. pymobiledevice3/cli/springboard.py +50 -50
  42. pymobiledevice3/cli/syslog.py +145 -65
  43. pymobiledevice3/cli/usbmux.py +66 -27
  44. pymobiledevice3/cli/version.py +2 -5
  45. pymobiledevice3/cli/webinspector.py +232 -156
  46. pymobiledevice3/exceptions.py +6 -2
  47. pymobiledevice3/lockdown.py +5 -1
  48. pymobiledevice3/lockdown_service_provider.py +5 -0
  49. pymobiledevice3/remote/remote_service_discovery.py +18 -10
  50. pymobiledevice3/restore/device.py +28 -4
  51. pymobiledevice3/restore/restore.py +2 -2
  52. pymobiledevice3/service_connection.py +15 -12
  53. pymobiledevice3/services/afc.py +731 -220
  54. pymobiledevice3/services/device_link.py +45 -31
  55. pymobiledevice3/services/idam.py +20 -0
  56. pymobiledevice3/services/lockdown_service.py +12 -9
  57. pymobiledevice3/services/mobile_config.py +1 -0
  58. pymobiledevice3/services/mobilebackup2.py +6 -3
  59. pymobiledevice3/services/os_trace.py +97 -55
  60. pymobiledevice3/services/remote_fetch_symbols.py +13 -8
  61. pymobiledevice3/services/screenshot.py +2 -2
  62. pymobiledevice3/services/web_protocol/alert.py +8 -8
  63. pymobiledevice3/services/web_protocol/automation_session.py +87 -79
  64. pymobiledevice3/services/web_protocol/cdp_screencast.py +2 -1
  65. pymobiledevice3/services/web_protocol/driver.py +71 -70
  66. pymobiledevice3/services/web_protocol/element.py +58 -56
  67. pymobiledevice3/services/web_protocol/selenium_api.py +47 -47
  68. pymobiledevice3/services/web_protocol/session_protocol.py +3 -2
  69. pymobiledevice3/services/web_protocol/switch_to.py +23 -19
  70. pymobiledevice3/services/webinspector.py +42 -67
  71. {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/METADATA +5 -3
  72. {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/RECORD +76 -61
  73. pymobiledevice3/cli/completions.py +0 -50
  74. pymobiledevice3/cli/developer.py +0 -1539
  75. pymobiledevice3/cli/diagnostics.py +0 -110
  76. {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/WHEEL +0 -0
  77. {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/entry_points.txt +0 -0
  78. {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/licenses/LICENSE +0 -0
  79. {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/top_level.txt +0 -0
@@ -44,6 +44,10 @@ class RemoteServiceDiscoveryService(LockdownServiceProvider):
44
44
  def product_version(self) -> str:
45
45
  return self.peer_info["Properties"]["OSVersion"]
46
46
 
47
+ @property
48
+ def product_build_version(self) -> str:
49
+ return self.peer_info["Properties"]["BuildVersion"]
50
+
47
51
  @property
48
52
  def ecid(self) -> int:
49
53
  return self.peer_info["Properties"]["UniqueChipID"]
@@ -101,6 +105,9 @@ class RemoteServiceDiscoveryService(LockdownServiceProvider):
101
105
  raise PyMobileDevice3Exception(
102
106
  f'Invalid response for RSDCheckIn: {response}. Expected "ServiceService"'
103
107
  )
108
+ error = response.get("Error")
109
+ if error is not None:
110
+ raise StartServiceError(name, error)
104
111
  except Exception:
105
112
  service.close()
106
113
  raise
@@ -162,17 +169,18 @@ class RemoteServiceDiscoveryService(LockdownServiceProvider):
162
169
 
163
170
  async def get_remoted_devices(timeout: float = DEFAULT_BONJOUR_TIMEOUT) -> list[RSDDevice]:
164
171
  result = []
165
- for hostname in await browse_remoted(timeout):
166
- with RemoteServiceDiscoveryService((hostname, RSD_PORT)) as rsd:
167
- properties = rsd.peer_info["Properties"]
168
- result.append(
169
- RSDDevice(
170
- hostname=hostname,
171
- udid=properties["UniqueDeviceID"],
172
- product_type=properties["ProductType"],
173
- os_version=properties["OSVersion"],
172
+ for instance in await browse_remoted(timeout):
173
+ for address in instance.addresses:
174
+ with RemoteServiceDiscoveryService((address.full_ip, RSD_PORT)) as rsd:
175
+ properties = rsd.peer_info["Properties"]
176
+ result.append(
177
+ RSDDevice(
178
+ hostname=address.full_ip,
179
+ udid=properties["UniqueDeviceID"],
180
+ product_type=properties["ProductType"],
181
+ os_version=properties["OSVersion"],
182
+ )
174
183
  )
175
- )
176
184
  return result
177
185
 
178
186
 
@@ -1,6 +1,6 @@
1
1
  from contextlib import suppress
2
2
  from functools import cached_property
3
- from typing import Optional
3
+ from typing import Optional, overload
4
4
 
5
5
  from pymobiledevice3.exceptions import MissingValueError
6
6
  from pymobiledevice3.irecv import IRecv
@@ -8,9 +8,15 @@ from pymobiledevice3.lockdown import LockdownClient
8
8
 
9
9
 
10
10
  class Device:
11
- def __init__(self, lockdown: LockdownClient = None, irecv: IRecv = None):
12
- self.lockdown = lockdown
13
- self.irecv = irecv
11
+ @overload
12
+ def __init__(self, lockdown: LockdownClient, irecv: None = None) -> None: ...
13
+
14
+ @overload
15
+ def __init__(self, lockdown: None = None, *, irecv: IRecv) -> None: ...
16
+
17
+ def __init__(self, lockdown: Optional[LockdownClient] = None, irecv: Optional[IRecv] = None) -> None:
18
+ self._lockdown: Optional[LockdownClient] = lockdown
19
+ self._irecv: Optional[IRecv] = irecv
14
20
 
15
21
  def __repr__(self) -> str:
16
22
  return (
@@ -20,6 +26,24 @@ class Device:
20
26
  f"image4-support: {self.is_image4_supported}>"
21
27
  )
22
28
 
29
+ @cached_property
30
+ def is_lockdown(self) -> bool:
31
+ return self._lockdown is not None
32
+
33
+ @cached_property
34
+ def is_irecv(self) -> bool:
35
+ return self._irecv is not None
36
+
37
+ @cached_property
38
+ def lockdown(self) -> LockdownClient:
39
+ assert self._lockdown is not None
40
+ return self._lockdown
41
+
42
+ @cached_property
43
+ def irecv(self) -> IRecv:
44
+ assert self._irecv is not None
45
+ return self._irecv
46
+
23
47
  @cached_property
24
48
  def ecid(self):
25
49
  if self.lockdown:
@@ -182,7 +182,7 @@ class Restore(BaseRestore):
182
182
  self.logger.info("Sending BuildIdentityDict now...")
183
183
  await service.aio_send_plist(req)
184
184
 
185
- async def extract_global_manifest(self) -> dict:
185
+ def extract_global_manifest(self) -> dict:
186
186
  build_info = self.build_identity.get("Info")
187
187
  if build_info is None:
188
188
  raise PyMobileDevice3Exception('build identity does not contain an "Info" element')
@@ -881,7 +881,7 @@ class Restore(BaseRestore):
881
881
  comp_name = "BMU,FirmwareMap"
882
882
 
883
883
  if "DeviceGeneratedTags" in arguments:
884
- response = self.get_device_generated_firmware_data(updater_name, info, arguments)
884
+ response = await self.get_device_generated_firmware_data(updater_name, info, arguments)
885
885
  else:
886
886
  # create Veridian request
887
887
  request = TSSRequest()
@@ -8,7 +8,7 @@ import struct
8
8
  import time
9
9
  import xml
10
10
  from enum import Enum
11
- from typing import Any, Optional
11
+ from typing import Any, Optional, Union
12
12
 
13
13
  import IPython
14
14
  from pygments import formatters, highlight, lexers
@@ -192,7 +192,7 @@ class ServiceConnection:
192
192
  except ssl.SSLEOFError as e:
193
193
  raise ConnectionTerminatedError from e
194
194
 
195
- def send_recv_plist(self, data: dict, endianity: str = ">", fmt: Enum = plistlib.FMT_XML) -> Any:
195
+ def send_recv_plist(self, data: Union[dict, list], endianity: str = ">", fmt: Enum = plistlib.FMT_XML) -> Any:
196
196
  """
197
197
  Send a plist to the socket and receive a plist response.
198
198
 
@@ -282,29 +282,29 @@ class ServiceConnection:
282
282
  msg = b"".join([hdr, data])
283
283
  return self.sendall(msg)
284
284
 
285
- def recv_plist(self, endianity: str = ">") -> dict:
285
+ def recv_plist(self, endianity: str = ">") -> Union[dict, list]:
286
286
  """
287
- Receive a plist from the socket and parse it into a dictionary.
287
+ Receive a plist from the socket and parse it into a native type.
288
288
 
289
289
  :param endianity: The byte order ('>' for big-endian, '<' for little-endian).
290
- :return: The received plist as a dictionary.
290
+ :return: The received plist as a native type.
291
291
  """
292
292
  return parse_plist(self.recv_prefixed(endianity=endianity))
293
293
 
294
294
  async def aio_recv_plist(self, endianity: str = ">") -> dict:
295
295
  """
296
- Asynchronously receive a plist from the socket and parse it into a dictionary.
296
+ Asynchronously receive a plist from the socket and parse it into a native type.
297
297
 
298
298
  :param endianity: The byte order ('>' for big-endian, '<' for little-endian).
299
- :return: The received plist as a dictionary.
299
+ :return: The received plist as a native type.
300
300
  """
301
301
  return parse_plist(await self.aio_recv_prefixed(endianity))
302
302
 
303
- def send_plist(self, d: dict, endianity: str = ">", fmt: Enum = plistlib.FMT_XML) -> None:
303
+ def send_plist(self, d: Union[dict, list], endianity: str = ">", fmt: Enum = plistlib.FMT_XML) -> None:
304
304
  """
305
- Send a dictionary as a plist to the socket.
305
+ Send a native type as a plist to the socket.
306
306
 
307
- :param d: The dictionary to send.
307
+ :param d: The native type to send.
308
308
  :param endianity: The byte order ('>' for big-endian, '<' for little-endian).
309
309
  :param fmt: The plist format (e.g., plistlib.FMT_XML).
310
310
  """
@@ -319,7 +319,7 @@ class ServiceConnection:
319
319
  self.writer.write(payload)
320
320
  await self.writer.drain()
321
321
 
322
- async def aio_send_plist(self, d: dict, endianity: str = ">", fmt: Enum = plistlib.FMT_XML) -> None:
322
+ async def aio_send_plist(self, d: Union[dict, list], endianity: str = ">", fmt: Enum = plistlib.FMT_XML) -> None:
323
323
  """
324
324
  Asynchronously send a dictionary as a plist to the socket.
325
325
 
@@ -357,7 +357,10 @@ class ServiceConnection:
357
357
  :param certfile: The path to the certificate file.
358
358
  :param keyfile: The path to the key file (optional).
359
359
  """
360
- self.socket = self.create_ssl_context(certfile, keyfile=keyfile).wrap_socket(self.socket)
360
+ try:
361
+ self.socket = self.create_ssl_context(certfile, keyfile=keyfile).wrap_socket(self.socket)
362
+ except OSError as e:
363
+ raise ConnectionAbortedError() from e
361
364
 
362
365
  async def aio_ssl_start(self, certfile: str, keyfile: Optional[str] = None) -> None:
363
366
  """