pymobiledevice3 5.0.0__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.

Files changed (143) hide show
  1. misc/plist_sniffer.py +15 -15
  2. misc/remotexpc_sniffer.py +29 -28
  3. pymobiledevice3/__main__.py +128 -102
  4. pymobiledevice3/_version.py +2 -2
  5. pymobiledevice3/bonjour.py +26 -49
  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 +25 -18
  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 +602 -520
  18. pymobiledevice3/cli/diagnostics.py +38 -33
  19. pymobiledevice3/cli/lockdown.py +79 -74
  20. pymobiledevice3/cli/mounter.py +85 -68
  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 +186 -110
  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 +157 -79
  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 +394 -241
  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 +62 -41
  52. pymobiledevice3/remote/tunnel_service.py +371 -293
  53. pymobiledevice3/remote/utils.py +12 -11
  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 +35 -54
  65. pymobiledevice3/restore/recovery.py +125 -135
  66. pymobiledevice3/restore/restore.py +524 -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 +136 -126
  72. pymobiledevice3/services/afc.py +350 -291
  73. pymobiledevice3/services/amfi.py +21 -18
  74. pymobiledevice3/services/companion.py +23 -19
  75. pymobiledevice3/services/crash_reports.py +60 -46
  76. pymobiledevice3/services/debugserver_applist.py +3 -3
  77. pymobiledevice3/services/device_arbitration.py +8 -8
  78. pymobiledevice3/services/device_link.py +55 -47
  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 +40 -50
  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 +330 -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 +69 -51
  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 +180 -176
  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 +2 -2
  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 +127 -116
  132. pymobiledevice3/tcp_forwarder.py +35 -22
  133. pymobiledevice3/tunneld/api.py +20 -15
  134. pymobiledevice3/tunneld/server.py +212 -133
  135. pymobiledevice3/usbmux.py +183 -138
  136. pymobiledevice3/utils.py +14 -11
  137. {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/METADATA +1 -1
  138. pymobiledevice3-5.0.2.dist-info/RECORD +173 -0
  139. pymobiledevice3-5.0.0.dist-info/RECORD +0 -173
  140. {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/WHEEL +0 -0
  141. {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/entry_points.txt +0 -0
  142. {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/licenses/LICENSE +0 -0
  143. {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/top_level.txt +0 -0
@@ -7,7 +7,7 @@ from pymobiledevice3.services.remote_server import MessageAux
7
7
 
8
8
 
9
9
  class DeviceInfo:
10
- IDENTIFIER = 'com.apple.instruments.server.services.deviceinfo'
10
+ IDENTIFIER = "com.apple.instruments.server.services.deviceinfo"
11
11
 
12
12
  def __init__(self, dvt):
13
13
  self._channel = dvt.make_channel(self.IDENTIFIER)
@@ -41,8 +41,8 @@ class DeviceInfo:
41
41
  result = self._channel.receive_plist()
42
42
  assert isinstance(result, list)
43
43
  for process in result:
44
- if 'startDate' in process:
45
- process['startDate'] = datetime.fromtimestamp(process['startDate'])
44
+ if "startDate" in process:
45
+ process["startDate"] = datetime.fromtimestamp(process["startDate"])
46
46
  return result
47
47
 
48
48
  def is_running_pid(self, pid: int) -> bool:
@@ -55,28 +55,28 @@ class DeviceInfo:
55
55
  return self._channel.receive_plist()
56
56
 
57
57
  def system_information(self):
58
- return self.request_information('systemInformation')
58
+ return self.request_information("systemInformation")
59
59
 
60
60
  def hardware_information(self):
61
- return self.request_information('hardwareInformation')
61
+ return self.request_information("hardwareInformation")
62
62
 
63
63
  def network_information(self):
64
- return self.request_information('networkInformation')
64
+ return self.request_information("networkInformation")
65
65
 
66
66
  def mach_time_info(self):
67
- return self.request_information('machTimeInfo')
67
+ return self.request_information("machTimeInfo")
68
68
 
69
69
  def mach_kernel_name(self) -> str:
70
- return self.request_information('machKernelName')
70
+ return self.request_information("machKernelName")
71
71
 
72
72
  def kpep_database(self) -> typing.Optional[dict]:
73
- kpep_database = self.request_information('kpepDatabase')
73
+ kpep_database = self.request_information("kpepDatabase")
74
74
  if kpep_database is not None:
75
75
  return plistlib.loads(kpep_database)
76
76
 
77
77
  def trace_codes(self):
78
- codes_file = self.request_information('traceCodesFile')
79
- return {int(k, 16): v for k, v in map(lambda line: line.split(), codes_file.splitlines())}
78
+ codes_file = self.request_information("traceCodesFile")
79
+ return {int(k, 16): v for k, v in (line.split() for line in codes_file.splitlines())}
80
80
 
81
81
  def request_information(self, selector_name):
82
82
  self._channel[selector_name]()
@@ -2,7 +2,7 @@ from pymobiledevice3.services.remote_server import MessageAux
2
2
 
3
3
 
4
4
  class EnergyMonitor:
5
- IDENTIFIER = 'com.apple.xcode.debug-gauge-data-providers.Energy'
5
+ IDENTIFIER = "com.apple.xcode.debug-gauge-data-providers.Energy"
6
6
 
7
7
  def __init__(self, dvt, pid_list: list):
8
8
  self._channel = dvt.make_channel(self.IDENTIFIER)
@@ -2,7 +2,7 @@ from pymobiledevice3.services.remote_server import MessageAux
2
2
 
3
3
 
4
4
  class Graphics:
5
- IDENTIFIER = 'com.apple.instruments.server.services.graphics.opengl'
5
+ IDENTIFIER = "com.apple.instruments.server.services.graphics.opengl"
6
6
 
7
7
  def __init__(self, dvt):
8
8
  self._channel = dvt.make_channel(self.IDENTIFIER)
@@ -3,7 +3,7 @@ from pymobiledevice3.services.remote_server import MessageAux
3
3
 
4
4
 
5
5
  class LocationSimulation(LocationSimulationBase):
6
- IDENTIFIER = 'com.apple.instruments.server.services.LocationSimulation'
6
+ IDENTIFIER = "com.apple.instruments.server.services.LocationSimulation"
7
7
 
8
8
  def __init__(self, dvt):
9
9
  super().__init__()
@@ -29,15 +29,15 @@ class LocationSimulationBase:
29
29
  for point in segment.points:
30
30
  if last_time is not None:
31
31
  duration = (point.time - last_time).total_seconds()
32
- if duration >= 0:
33
- if not disable_sleep:
34
-
35
- if timing_randomness_range:
36
- gpx_timing_noise = random.randint(-timing_randomness_range, timing_randomness_range) / 1000
37
- duration += gpx_timing_noise
38
-
39
- self.logger.info(f'waiting for {duration:.3f}s')
40
- time.sleep(duration)
32
+ if duration >= 0 and not disable_sleep:
33
+ if timing_randomness_range:
34
+ gpx_timing_noise = (
35
+ random.randint(-timing_randomness_range, timing_randomness_range) / 1000
36
+ )
37
+ duration += gpx_timing_noise
38
+
39
+ self.logger.info(f"waiting for {duration:.3f}s")
40
+ time.sleep(duration)
41
41
  last_time = point.time
42
- self.logger.info(f'set location to {point.latitude} {point.longitude}')
42
+ self.logger.info(f"set location to {point.latitude} {point.longitude}")
43
43
  self.set(point.latitude, point.longitude)
@@ -11,21 +11,21 @@ class IpAddressAdapter(Adapter):
11
11
 
12
12
 
13
13
  address_t = Struct(
14
- 'len' / Int8ul,
15
- 'family' / Int8ul,
16
- 'port' / Int16ub,
17
- 'data' / Switch(this.len, {
18
- 0x1c: Struct(
19
- 'flow_info' / Int32ul,
20
- 'address' / IpAddressAdapter(Bytes(16)),
21
- 'scope_id' / Int32ul,
22
- ),
23
- 0x10: Struct(
24
- 'address' / IpAddressAdapter(Bytes(4)),
25
- '_zero' / Bytes(8)
26
- )
27
- })
28
-
14
+ "len" / Int8ul,
15
+ "family" / Int8ul,
16
+ "port" / Int16ub,
17
+ "data"
18
+ / Switch(
19
+ this.len,
20
+ {
21
+ 0x1C: Struct(
22
+ "flow_info" / Int32ul,
23
+ "address" / IpAddressAdapter(Bytes(16)),
24
+ "scope_id" / Int32ul,
25
+ ),
26
+ 0x10: Struct("address" / IpAddressAdapter(Bytes(4)), "_zero" / Bytes(8)),
27
+ },
28
+ ),
29
29
  )
30
30
 
31
31
  MESSAGE_TYPE_INTERFACE_DETECTION = 0
@@ -67,7 +67,7 @@ class ConnectionUpdateEvent:
67
67
 
68
68
 
69
69
  class NetworkMonitor:
70
- IDENTIFIER = 'com.apple.instruments.server.services.networking'
70
+ IDENTIFIER = "com.apple.instruments.server.services.networking"
71
71
 
72
72
  def __init__(self, dvt):
73
73
  self.logger = logging.getLogger(__name__)
@@ -98,5 +98,5 @@ class NetworkMonitor:
98
98
  elif message[0] == MESSAGE_TYPE_CONNECTION_UPDATE:
99
99
  event = ConnectionUpdateEvent(*message[1])
100
100
  else:
101
- self.logger.warning(f'unsupported event type: {message[0]}')
101
+ self.logger.warning(f"unsupported event type: {message[0]}")
102
102
  yield event
@@ -2,7 +2,7 @@ from pymobiledevice3.services.remote_server import MessageAux
2
2
 
3
3
 
4
4
  class Notifications:
5
- IDENTIFIER = 'com.apple.instruments.server.services.mobilenotifications'
5
+ IDENTIFIER = "com.apple.instruments.server.services.mobilenotifications"
6
6
 
7
7
  def __init__(self, dvt):
8
8
  self._dvt = dvt
@@ -17,7 +17,7 @@ class OutputReceivedEvent:
17
17
  message: str
18
18
 
19
19
  @classmethod
20
- def create(cls, message) -> 'OutputReceivedEvent':
20
+ def create(cls, message) -> "OutputReceivedEvent":
21
21
  try:
22
22
  date = OSUTIL.parse_timestamp(message[2].value)
23
23
  except (ValueError, OSError):
@@ -27,7 +27,7 @@ class OutputReceivedEvent:
27
27
 
28
28
 
29
29
  class ProcessControl:
30
- IDENTIFIER = 'com.apple.instruments.server.services.processcontrol'
30
+ IDENTIFIER = "com.apple.instruments.server.services.processcontrol"
31
31
 
32
32
  def __init__(self, dvt: DvtSecureSocketProxyService):
33
33
  self._channel = dvt.make_channel(self.IDENTIFIER)
@@ -58,11 +58,20 @@ class ProcessControl:
58
58
  self._channel.killPid_(MessageAux().append_obj(pid), expects_reply=False)
59
59
 
60
60
  def process_identifier_for_bundle_identifier(self, app_bundle_identifier: str) -> int:
61
- self._channel.processIdentifierForBundleIdentifier_(MessageAux().append_obj(app_bundle_identifier), expects_reply=True)
61
+ self._channel.processIdentifierForBundleIdentifier_(
62
+ MessageAux().append_obj(app_bundle_identifier), expects_reply=True
63
+ )
62
64
  return self._channel.receive_plist()
63
65
 
64
- def launch(self, bundle_id: str, arguments=None, kill_existing: bool = True, start_suspended: bool = False,
65
- environment: Optional[dict] = None, extra_options: Optional[dict] = None) -> int:
66
+ def launch(
67
+ self,
68
+ bundle_id: str,
69
+ arguments=None,
70
+ kill_existing: bool = True,
71
+ start_suspended: bool = False,
72
+ environment: Optional[dict] = None,
73
+ extra_options: Optional[dict] = None,
74
+ ) -> int:
66
75
  """
67
76
  Launch a process.
68
77
  :param bundle_id: Bundle id of the process.
@@ -76,13 +85,19 @@ class ProcessControl:
76
85
  arguments = [] if arguments is None else arguments
77
86
  environment = {} if environment is None else environment
78
87
  options = {
79
- 'StartSuspendedKey': start_suspended,
80
- 'KillExisting': kill_existing,
88
+ "StartSuspendedKey": start_suspended,
89
+ "KillExisting": kill_existing,
81
90
  }
82
91
  if extra_options:
83
92
  options.update(extra_options)
84
- args = MessageAux().append_obj('').append_obj(bundle_id).append_obj(environment).append_obj(
85
- arguments).append_obj(options)
93
+ args = (
94
+ MessageAux()
95
+ .append_obj("")
96
+ .append_obj(bundle_id)
97
+ .append_obj(environment)
98
+ .append_obj(arguments)
99
+ .append_obj(options)
100
+ )
86
101
  self._channel.launchSuspendedProcessWithDevicePath_bundleIdentifier_environment_arguments_options_(args)
87
102
  result = self._channel.receive_plist()
88
103
  assert result
@@ -90,5 +105,5 @@ class ProcessControl:
90
105
 
91
106
  def __iter__(self) -> typing.Generator[OutputReceivedEvent, None, None]:
92
107
  key, value = self._channel.receive_key_value()
93
- if key == 'outputReceived:fromProcess:atTime:':
108
+ if key == "outputReceived:fromProcess:atTime:":
94
109
  yield OutputReceivedEvent.create(value)
@@ -2,12 +2,12 @@ from pymobiledevice3.services.dvt.dvt_secure_socket_proxy import DvtSecureSocket
2
2
 
3
3
 
4
4
  class Screenshot:
5
- IDENTIFIER = 'com.apple.instruments.server.services.screenshot'
5
+ IDENTIFIER = "com.apple.instruments.server.services.screenshot"
6
6
 
7
7
  def __init__(self, dvt: DvtSecureSocketProxyService):
8
8
  self._channel = dvt.make_channel(self.IDENTIFIER)
9
9
 
10
10
  def get_screenshot(self) -> bytes:
11
- """ get device screenshot """
11
+ """get device screenshot"""
12
12
  self._channel.takeScreenshot(expects_reply=True)
13
13
  return self._channel.receive_plist()
@@ -5,25 +5,25 @@ from pymobiledevice3.services.remote_server import Tap
5
5
 
6
6
 
7
7
  class Sysmontap(Tap):
8
- IDENTIFIER = 'com.apple.instruments.server.services.sysmontap'
8
+ IDENTIFIER = "com.apple.instruments.server.services.sysmontap"
9
9
 
10
10
  def __init__(self, dvt):
11
11
  self._device_info = DeviceInfo(dvt)
12
12
 
13
- process_attributes = list(self._device_info.request_information('sysmonProcessAttributes'))
14
- system_attributes = list(self._device_info.request_information('sysmonSystemAttributes'))
13
+ process_attributes = list(self._device_info.request_information("sysmonProcessAttributes"))
14
+ system_attributes = list(self._device_info.request_information("sysmonSystemAttributes"))
15
15
 
16
- self.process_attributes_cls = dataclasses.make_dataclass('SysmonProcessAttributes', process_attributes)
17
- self.system_attributes_cls = dataclasses.make_dataclass('SysmonSystemAttributes', system_attributes)
16
+ self.process_attributes_cls = dataclasses.make_dataclass("SysmonProcessAttributes", process_attributes)
17
+ self.system_attributes_cls = dataclasses.make_dataclass("SysmonSystemAttributes", system_attributes)
18
18
 
19
19
  config = {
20
- 'ur': 500, # Output frequency ms
21
- 'bm': 0,
22
- 'procAttrs': process_attributes,
23
- 'sysAttrs': system_attributes,
24
- 'cpuUsage': True,
25
- 'physFootprint': True, # memory value
26
- 'sampleInterval': 500000000
20
+ "ur": 500, # Output frequency ms
21
+ "bm": 0,
22
+ "procAttrs": process_attributes,
23
+ "sysAttrs": system_attributes,
24
+ "cpuUsage": True,
25
+ "physFootprint": True, # memory value
26
+ "sampleInterval": 500000000,
27
27
  }
28
28
 
29
29
  super().__init__(dvt, self.IDENTIFIER, config)
@@ -34,13 +34,13 @@ class Sysmontap(Tap):
34
34
 
35
35
  def iter_processes(self):
36
36
  for row in self:
37
- if 'Processes' not in row:
37
+ if "Processes" not in row:
38
38
  continue
39
39
 
40
40
  entries = []
41
41
 
42
- processes = row['Processes'].items()
43
- for pid, process_info in processes:
42
+ processes = row["Processes"].items()
43
+ for _pid, process_info in processes:
44
44
  entry = dataclasses.asdict(self.process_attributes_cls(*process_info))
45
45
  entries.append(entry)
46
46
 
@@ -13,8 +13,16 @@ from pymobiledevice3.services.dvt.dvt_testmanaged_proxy import DvtTestmanagedPro
13
13
  from pymobiledevice3.services.dvt.instruments.process_control import ProcessControl
14
14
  from pymobiledevice3.services.house_arrest import HouseArrestService
15
15
  from pymobiledevice3.services.installation_proxy import InstallationProxyService
16
- from pymobiledevice3.services.remote_server import NSURL, NSUUID, Channel, ChannelFragmenter, MessageAux, \
17
- XCTestConfiguration, dtx_message_header_struct, dtx_message_payload_header_struct
16
+ from pymobiledevice3.services.remote_server import (
17
+ NSURL,
18
+ NSUUID,
19
+ Channel,
20
+ ChannelFragmenter,
21
+ MessageAux,
22
+ XCTestConfiguration,
23
+ dtx_message_header_struct,
24
+ dtx_message_payload_header_struct,
25
+ )
18
26
 
19
27
  logger = logging.getLogger(__name__)
20
28
 
@@ -52,9 +60,7 @@ class XCUITestService:
52
60
  self.setup_xcuitest(bundle_id, xctest_path, xctest_configuration)
53
61
  dvt1, chan1, dvt2, chan2 = self.init_ide_channels(session_identifier)
54
62
 
55
- pid = self.launch_test_app(
56
- app_info, bundle_id, xctest_path, test_runner_env, test_runner_args
57
- )
63
+ pid = self.launch_test_app(app_info, bundle_id, xctest_path, test_runner_env, test_runner_args)
58
64
  logger.info("Runner started with pid:%d, waiting for testBundleReady", pid)
59
65
 
60
66
  time.sleep(1)
@@ -95,24 +101,18 @@ class XCUITestService:
95
101
  # - _XCT_didFinishExecutingTestPlan
96
102
  logger.info("unhandled %s %r", key, value)
97
103
 
98
- def send_response_capabilities(
99
- self, dvt: DvtTestmanagedProxyService, chan: Channel, cur_message: int
100
- ):
101
- pheader = dtx_message_payload_header_struct.build(
102
- dict(flags=3, auxiliaryLength=0, totalLength=0)
103
- )
104
- mheader = dtx_message_header_struct.build(
105
- dict(
106
- cb=dtx_message_header_struct.sizeof(),
107
- fragmentId=0,
108
- fragmentCount=1,
109
- length=dtx_message_payload_header_struct.sizeof(),
110
- identifier=cur_message,
111
- conversationIndex=1,
112
- channelCode=chan,
113
- expectsReply=int(0),
114
- )
115
- )
104
+ def send_response_capabilities(self, dvt: DvtTestmanagedProxyService, chan: Channel, cur_message: int):
105
+ pheader = dtx_message_payload_header_struct.build({"flags": 3, "auxiliaryLength": 0, "totalLength": 0})
106
+ mheader = dtx_message_header_struct.build({
107
+ "cb": dtx_message_header_struct.sizeof(),
108
+ "fragmentId": 0,
109
+ "fragmentCount": 1,
110
+ "length": dtx_message_payload_header_struct.sizeof(),
111
+ "identifier": cur_message,
112
+ "conversationIndex": 1,
113
+ "channelCode": chan,
114
+ "expectsReply": (0),
115
+ })
116
116
  msg = mheader + pheader
117
117
  dvt.service.sendall(msg)
118
118
 
@@ -160,9 +160,7 @@ class XCUITestService:
160
160
  xctest_configuration: XCTestConfiguration,
161
161
  ):
162
162
  """push xctestconfiguration to app VendDocuments"""
163
- with HouseArrestService(
164
- lockdown=self.service_provider, bundle_id=bundle_id, documents_only=False
165
- ) as afc:
163
+ with HouseArrestService(lockdown=self.service_provider, bundle_id=bundle_id, documents_only=False) as afc:
166
164
  for name in afc.listdir("/tmp"):
167
165
  if name.endswith(".xctestconfiguration"):
168
166
  logger.debug("remove /tmp/%s", name)
@@ -212,9 +210,7 @@ class XCUITestService:
212
210
  exec_name = app_info["CFBundleExecutable"]
213
211
  # # logger.info('CFBundleExecutable: %s', exec_name)
214
212
  # # CFBundleName always endswith -Runner
215
- assert exec_name.endswith("-Runner"), (
216
- "Invalid CFBundleExecutable: %s" % exec_name
217
- )
213
+ assert exec_name.endswith("-Runner"), "Invalid CFBundleExecutable: %s" % exec_name
218
214
  target_name = exec_name[: -len("-Runner")]
219
215
 
220
216
  app_env = {
@@ -226,7 +222,7 @@ class XCUITestService:
226
222
  "NSUnbufferedIO": "YES",
227
223
  "SQLITE_ENABLE_THREAD_ASSERTIONS": "1",
228
224
  "WDA_PRODUCT_BUNDLE_IDENTIFIER": "",
229
- "XCTestBundlePath": f'{app_info["Path"]}/PlugIns/{target_name}.xctest',
225
+ "XCTestBundlePath": f"{app_info['Path']}/PlugIns/{target_name}.xctest",
230
226
  "XCTestConfigurationFilePath": app_container + xctest_path,
231
227
  "XCODE_DBG_XPC_EXCLUSIONS": "com.apple.dt.xctestSymbolicator",
232
228
  # the following maybe no needed
@@ -238,9 +234,7 @@ class XCUITestService:
238
234
  app_env.update(test_runner_env)
239
235
 
240
236
  if self.product_major_version >= 11:
241
- app_env[
242
- "DYLD_INSERT_LIBRARIES"
243
- ] = "/Developer/usr/lib/libMainThreadChecker.dylib"
237
+ app_env["DYLD_INSERT_LIBRARIES"] = "/Developer/usr/lib/libMainThreadChecker.dylib"
244
238
  app_env["OS_ACTIVITY_DT_MODE"] = "YES"
245
239
 
246
240
  app_args = [
@@ -276,7 +270,7 @@ def get_app_info(service_provider: LockdownClient, bundle_id: str) -> dict[str,
276
270
  def generate_xctestconfiguration(
277
271
  app_info: dict,
278
272
  session_identifier: NSUUID,
279
- target_app_bundle_id: str = None,
273
+ target_app_bundle_id: Optional[str] = None,
280
274
  target_app_env: Optional[dict] = None,
281
275
  target_app_args: Optional[list] = None,
282
276
  tests_to_run: Optional[list] = None,
@@ -285,19 +279,15 @@ def generate_xctestconfiguration(
285
279
  assert exec_name.endswith("-Runner"), "Invalid CFBundleExecutable: %s" % exec_name
286
280
  config_name = exec_name[: -len("-Runner")]
287
281
 
288
- return XCTestConfiguration(
289
- {
290
- "testBundleURL": NSURL(
291
- None, f'file://{app_info["Path"]}/PlugIns/{config_name}.xctest'
292
- ),
293
- "sessionIdentifier": session_identifier,
294
- "targetApplicationBundleID": target_app_bundle_id,
295
- "targetApplicationEnvironment": target_app_env or {},
296
- "targetApplicationArguments": target_app_args or [],
297
- "testsToRun": tests_to_run or set(),
298
- "testsMustRunOnMainThread": True,
299
- "reportResultsToIDE": True,
300
- "reportActivities": True,
301
- "automationFrameworkPath": "/Developer/Library/PrivateFrameworks/XCTAutomationSupport.framework",
302
- }
303
- )
282
+ return XCTestConfiguration({
283
+ "testBundleURL": NSURL(None, f"file://{app_info['Path']}/PlugIns/{config_name}.xctest"),
284
+ "sessionIdentifier": session_identifier,
285
+ "targetApplicationBundleID": target_app_bundle_id,
286
+ "targetApplicationEnvironment": target_app_env or {},
287
+ "targetApplicationArguments": target_app_args or [],
288
+ "testsToRun": tests_to_run or set(),
289
+ "testsMustRunOnMainThread": True,
290
+ "reportResultsToIDE": True,
291
+ "reportActivities": True,
292
+ "automationFrameworkPath": "/Developer/Library/PrivateFrameworks/XCTAutomationSupport.framework",
293
+ })
@@ -1,7 +1,7 @@
1
1
  from pymobiledevice3.lockdown import LockdownClient
2
2
  from pymobiledevice3.services.lockdown_service import LockdownService
3
3
 
4
- SRCFILES = '''Baseband
4
+ SRCFILES = """Baseband
5
5
  CrashReporter
6
6
  MobileAsset
7
7
  VARFS
@@ -19,30 +19,30 @@ NANDDebugInfo
19
19
  SystemConfiguration
20
20
  Ubiquity
21
21
  tmp
22
- WirelessAutomation'''
22
+ WirelessAutomation"""
23
23
 
24
24
 
25
25
  class FileRelayService(LockdownService):
26
- SERVICE_NAME = 'com.apple.mobile.file_relay'
26
+ SERVICE_NAME = "com.apple.mobile.file_relay"
27
27
 
28
28
  def __init__(self, lockdown: LockdownClient):
29
29
  super().__init__(lockdown, self.SERVICE_NAME)
30
30
  self.packet_num = 0
31
31
 
32
32
  def stop_session(self):
33
- self.logger.info('Disconecting...')
33
+ self.logger.info("Disconecting...")
34
34
  self.service.close()
35
35
 
36
36
  def request_sources(self, sources=None):
37
37
  if sources is None:
38
- sources = ['UserDatabases']
39
- self.service.send_plist({'Sources': sources})
38
+ sources = ["UserDatabases"]
39
+ self.service.send_plist({"Sources": sources})
40
40
  while 1:
41
41
  res = self.service.recv_plist()
42
42
  if res:
43
- s = res.get('Status')
44
- if s == 'Acknowledged':
45
- z = ''
43
+ s = res.get("Status")
44
+ if s == "Acknowledged":
45
+ z = ""
46
46
  while True:
47
47
  x = self.service.recv()
48
48
  if not x:
@@ -50,6 +50,6 @@ class FileRelayService(LockdownService):
50
50
  z += x
51
51
  return z
52
52
  else:
53
- print(res.get('Error'))
53
+ print(res.get("Error"))
54
54
  break
55
55
  return None
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env python3
2
2
  import logging
3
3
  import time
4
+ from typing import Optional
4
5
 
5
6
  from pymobiledevice3.lockdown import LockdownClient
6
7
  from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
@@ -10,8 +11,9 @@ class HeartbeatService:
10
11
  """
11
12
  Use to keep an active connection with lockdownd
12
13
  """
13
- SERVICE_NAME = 'com.apple.mobile.heartbeat'
14
- RSD_SERVICE_NAME = 'com.apple.mobile.heartbeat.shim.remote'
14
+
15
+ SERVICE_NAME = "com.apple.mobile.heartbeat"
16
+ RSD_SERVICE_NAME = "com.apple.mobile.heartbeat.shim.remote"
15
17
 
16
18
  def __init__(self, lockdown: LockdownServiceProvider):
17
19
  self.logger = logging.getLogger(__name__)
@@ -22,7 +24,7 @@ class HeartbeatService:
22
24
  else:
23
25
  self.service_name = self.RSD_SERVICE_NAME
24
26
 
25
- def start(self, interval: float = None) -> None:
27
+ def start(self, interval: Optional[float] = None) -> None:
26
28
  start = time.time()
27
29
  service = self.lockdown.start_lockdown_service(self.service_name)
28
30
 
@@ -30,8 +32,7 @@ class HeartbeatService:
30
32
  response = service.recv_plist()
31
33
  self.logger.debug(response)
32
34
 
33
- if interval is not None:
34
- if time.time() >= start + interval:
35
- break
35
+ if interval is not None and time.time() >= start + interval:
36
+ break
36
37
 
37
- service.send_plist({'Command': 'Polo'})
38
+ service.send_plist({"Command": "Polo"})
@@ -3,25 +3,22 @@ from pymobiledevice3.lockdown import LockdownClient
3
3
  from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
4
4
  from pymobiledevice3.services.afc import AfcService, AfcShell
5
5
 
6
- VEND_CONTAINER = 'VendContainer'
7
- VEND_DOCUMENTS = 'VendDocuments'
6
+ VEND_CONTAINER = "VendContainer"
7
+ VEND_DOCUMENTS = "VendDocuments"
8
8
 
9
- DOCUMENTS_ROOT = '/Documents'
9
+ DOCUMENTS_ROOT = "/Documents"
10
10
 
11
11
 
12
12
  class HouseArrestService(AfcService):
13
- SERVICE_NAME = 'com.apple.mobile.house_arrest'
14
- RSD_SERVICE_NAME = 'com.apple.mobile.house_arrest.shim.remote'
13
+ SERVICE_NAME = "com.apple.mobile.house_arrest"
14
+ RSD_SERVICE_NAME = "com.apple.mobile.house_arrest.shim.remote"
15
15
 
16
16
  def __init__(self, lockdown: LockdownServiceProvider, bundle_id: str, documents_only: bool = False):
17
17
  if isinstance(lockdown, LockdownClient):
18
18
  super().__init__(lockdown, self.SERVICE_NAME)
19
19
  else:
20
20
  super().__init__(lockdown, self.RSD_SERVICE_NAME)
21
- if documents_only:
22
- cmd = VEND_DOCUMENTS
23
- else:
24
- cmd = VEND_CONTAINER
21
+ cmd = VEND_DOCUMENTS if documents_only else VEND_CONTAINER
25
22
  self.documents_only = documents_only
26
23
  try:
27
24
  self.send_command(bundle_id, cmd)
@@ -29,14 +26,14 @@ class HouseArrestService(AfcService):
29
26
  self.close()
30
27
  raise
31
28
 
32
- def send_command(self, bundle_id: str, cmd: str = 'VendContainer') -> None:
33
- response = self.service.send_recv_plist({'Command': cmd, 'Identifier': bundle_id})
34
- error = response.get('Error')
29
+ def send_command(self, bundle_id: str, cmd: str = "VendContainer") -> None:
30
+ response = self.service.send_recv_plist({"Command": cmd, "Identifier": bundle_id})
31
+ error = response.get("Error")
35
32
  if error:
36
- if error == 'ApplicationLookupFailed':
37
- raise AppNotInstalledError(f'No app with bundle id {bundle_id} found')
33
+ if error == "ApplicationLookupFailed":
34
+ raise AppNotInstalledError(f"No app with bundle id {bundle_id} found")
38
35
  else:
39
36
  raise PyMobileDevice3Exception(error)
40
37
 
41
38
  def shell(self) -> None:
42
- AfcShell.create(self.lockdown, service=self, auto_cd=DOCUMENTS_ROOT if self.documents_only else '/')
39
+ AfcShell.create(self.lockdown, service=self, auto_cd=DOCUMENTS_ROOT if self.documents_only else "/")