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
@@ -14,16 +14,16 @@ from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
14
14
  from pymobiledevice3.services.afc import AfcService
15
15
  from pymobiledevice3.services.lockdown_service import LockdownService
16
16
 
17
- GET_APPS_ADDITIONAL_INFO = {'ReturnAttributes': ['CFBundleIdentifier', 'StaticDiskUsage', 'DynamicDiskUsage']}
17
+ GET_APPS_ADDITIONAL_INFO = {"ReturnAttributes": ["CFBundleIdentifier", "StaticDiskUsage", "DynamicDiskUsage"]}
18
18
 
19
- TEMP_REMOTE_BASEDIR = '/PublicStaging'
20
- TEMP_REMOTE_IPA_FILE = f'{TEMP_REMOTE_BASEDIR}/pymobiledevice3.ipa'
21
- TEMP_REMOTE_IPCC_FOLDER = f'{TEMP_REMOTE_BASEDIR}/pymobiledevice3.ipcc'
19
+ TEMP_REMOTE_BASEDIR = "/PublicStaging"
20
+ TEMP_REMOTE_IPA_FILE = f"{TEMP_REMOTE_BASEDIR}/pymobiledevice3.ipa"
21
+ TEMP_REMOTE_IPCC_FOLDER = f"{TEMP_REMOTE_BASEDIR}/pymobiledevice3.ipcc"
22
22
 
23
23
 
24
24
  class ZipFileType(Enum):
25
- IPCC = 'ipcc'
26
- IPA = 'ipa'
25
+ IPCC = "ipcc"
26
+ IPA = "ipa"
27
27
 
28
28
  def is_ipcc(self) -> bool:
29
29
  return self == ZipFileType.IPCC
@@ -33,42 +33,41 @@ class ZipFileType(Enum):
33
33
 
34
34
 
35
35
  def create_ipa_contents_from_directory(directory: str) -> bytes:
36
- payload_prefix = 'Payload/' + os.path.basename(directory)
36
+ payload_prefix = "Payload/" + os.path.basename(directory)
37
37
  with TemporaryDirectory() as temp_dir:
38
- zip_path = Path(temp_dir) / 'ipa'
39
- with ZipFile(zip_path, 'w', ZIP_DEFLATED) as zip_file:
40
- for root, dirs, files in os.walk(directory):
38
+ zip_path = Path(temp_dir) / "ipa"
39
+ with ZipFile(zip_path, "w", ZIP_DEFLATED) as zip_file:
40
+ for root, _dirs, files in os.walk(directory):
41
41
  for file in files:
42
42
  full_path = Path(root) / file
43
43
  full_path.touch()
44
- zip_file.write(full_path,
45
- arcname=f'{payload_prefix}/{os.path.relpath(full_path, directory)}')
44
+ zip_file.write(full_path, arcname=f"{payload_prefix}/{os.path.relpath(full_path, directory)}")
46
45
  return zip_path.read_bytes()
47
46
 
48
47
 
49
48
  def classify_zip_file(zip_bytes: bytes) -> ZipFileType:
50
- """ checks the zipped bytes if it's a .ipcc or .ipa """
49
+ """checks the zipped bytes if it's a .ipcc or .ipa"""
51
50
  try:
52
- with ZipFile(BytesIO(zip_bytes), 'r') as zip_file:
51
+ with ZipFile(BytesIO(zip_bytes), "r") as zip_file:
53
52
  # sometimes packages at first index don't have enough infos to check
54
- dirs = zip_file.namelist()[1].split('/')
53
+ dirs = zip_file.namelist()[1].split("/")
55
54
 
56
- if dirs[0] != 'Payload':
57
- raise AppInstallError('package does not have a payload')
58
- if dirs[1].endswith('.app'):
55
+ if dirs[0] != "Payload":
56
+ raise AppInstallError("package does not have a payload")
57
+ if dirs[1].endswith(".app"):
59
58
  return ZipFileType.IPA
60
- elif dirs[1].endswith('.bundle'):
59
+ elif dirs[1].endswith(".bundle"):
61
60
  return ZipFileType.IPCC
62
61
  else:
63
- raise AppInstallError('package does not have the appropriate folders structure')
62
+ raise AppInstallError("package does not have the appropriate folders structure")
64
63
 
65
- except BadZipFile:
66
- raise AppInstallError('invalid bytes package')
64
+ except BadZipFile as e:
65
+ raise AppInstallError("Invalid bytes package") from e
67
66
 
68
67
 
69
68
  class InstallationProxyService(LockdownService):
70
- SERVICE_NAME = 'com.apple.mobile.installation_proxy'
71
- RSD_SERVICE_NAME = 'com.apple.mobile.installation_proxy.shim.remote'
69
+ SERVICE_NAME = "com.apple.mobile.installation_proxy"
70
+ RSD_SERVICE_NAME = "com.apple.mobile.installation_proxy.shim.remote"
72
71
 
73
72
  def __init__(self, lockdown: LockdownServiceProvider):
74
73
  if isinstance(lockdown, LockdownClient):
@@ -76,69 +75,84 @@ class InstallationProxyService(LockdownService):
76
75
  else:
77
76
  super().__init__(lockdown, self.RSD_SERVICE_NAME)
78
77
 
79
- def _watch_completion(self, handler: Callable = None, ipcc: bool = False, *args) -> None:
78
+ def _watch_completion(self, handler: Optional[Callable] = None, ipcc: bool = False, *args) -> None:
80
79
  while True:
81
80
  response = self.service.recv_plist()
82
81
  if not response:
83
82
  break
84
- error = response.get('Error')
83
+ error = response.get("Error")
85
84
  if error:
86
- raise AppInstallError(f'{error}: {response.get("ErrorDescription")}')
87
- completion = response.get('PercentComplete')
85
+ raise AppInstallError(f"{error}: {response.get('ErrorDescription')}")
86
+ completion = response.get("PercentComplete")
88
87
  if completion:
89
88
  if handler:
90
- self.logger.debug('calling handler')
89
+ self.logger.debug("calling handler")
91
90
  handler(completion, *args)
92
- self.logger.info(f'{response.get("PercentComplete")}% Complete')
93
- if response.get('Status') == 'Complete':
91
+ self.logger.info(f"{response.get('PercentComplete')}% Complete")
92
+ if response.get("Status") == "Complete":
94
93
  if ipcc:
95
94
  # there is no progress when installing a .ipcc file,
96
95
  # so we just put a simple message indicating it's done
97
- self.logger.info('Installation succeed.')
96
+ self.logger.info("Installation succeed.")
98
97
  return
99
98
  raise AppInstallError()
100
99
 
101
- def send_cmd_for_bundle_identifier(self, bundle_identifier: str, cmd: str = 'Archive',
102
- options: Optional[dict] = None,
103
- handler: Optional[dict] = None, *args) -> None:
104
- """ send a low-level command to installation relay """
105
- cmd = {'Command': cmd,
106
- 'ApplicationIdentifier': bundle_identifier}
100
+ def send_cmd_for_bundle_identifier(
101
+ self,
102
+ bundle_identifier: str,
103
+ cmd: str = "Archive",
104
+ options: Optional[dict] = None,
105
+ handler: Optional[dict] = None,
106
+ *args,
107
+ ) -> None:
108
+ """send a low-level command to installation relay"""
109
+ cmd = {"Command": cmd, "ApplicationIdentifier": bundle_identifier}
107
110
 
108
111
  if options is None:
109
112
  options = {}
110
113
 
111
- cmd.update({'ClientOptions': options})
114
+ cmd.update({"ClientOptions": options})
112
115
  self.service.send_plist(cmd)
113
116
  self._watch_completion(handler, *args)
114
117
 
115
- def install(self, package_path: str, options: Optional[dict] = None, handler: Callable = None, *args) -> None:
116
- """ install given ipa/ipcc from device path """
117
- self.install_from_local(package_path, 'Install', options, handler, args)
118
-
119
- def upgrade(self, ipa_path: str, options: Optional[dict] = None, handler: Callable = None, *args) -> None:
120
- """ upgrade given ipa from device path """
121
- self.install_from_local(ipa_path, 'Upgrade', options, handler, args)
122
-
123
- def restore(self, bundle_identifier: str, options: Optional[dict] = None, handler: Callable = None, *args) -> None:
124
- """ no longer supported on newer iOS versions """
125
- self.send_cmd_for_bundle_identifier(bundle_identifier, 'Restore', options, handler, args)
126
-
127
- def uninstall(self, bundle_identifier: str, options: Optional[dict] = None, handler: Callable = None,
128
- *args) -> None:
129
- """ uninstall given bundle_identifier """
130
- self.send_cmd_for_bundle_identifier(bundle_identifier, 'Uninstall', options, handler, args)
131
-
132
- def install_from_bytes(self, package_bytes: bytes, cmd: str = 'Install', options: Optional[dict] = None,
133
- handler: Callable = None, *args) -> None:
134
- """ upload given ipa/ipcc bytes object onto device and install it """
118
+ def install(
119
+ self, package_path: str, options: Optional[dict] = None, handler: Optional[Callable] = None, *args
120
+ ) -> None:
121
+ """install given ipa/ipcc from device path"""
122
+ self.install_from_local(package_path, "Install", options, handler, args)
123
+
124
+ def upgrade(self, ipa_path: str, options: Optional[dict] = None, handler: Optional[Callable] = None, *args) -> None:
125
+ """upgrade given ipa from device path"""
126
+ self.install_from_local(ipa_path, "Upgrade", options, handler, args)
127
+
128
+ def restore(
129
+ self, bundle_identifier: str, options: Optional[dict] = None, handler: Optional[Callable] = None, *args
130
+ ) -> None:
131
+ """no longer supported on newer iOS versions"""
132
+ self.send_cmd_for_bundle_identifier(bundle_identifier, "Restore", options, handler, args)
133
+
134
+ def uninstall(
135
+ self, bundle_identifier: str, options: Optional[dict] = None, handler: Optional[Callable] = None, *args
136
+ ) -> None:
137
+ """uninstall given bundle_identifier"""
138
+ self.send_cmd_for_bundle_identifier(bundle_identifier, "Uninstall", options, handler, args)
139
+
140
+ def install_from_bytes(
141
+ self,
142
+ package_bytes: bytes,
143
+ cmd: str = "Install",
144
+ options: Optional[dict] = None,
145
+ handler: Optional[Callable] = None,
146
+ *args,
147
+ ) -> None:
148
+ """upload given ipa/ipcc bytes object onto device and install it"""
135
149
  ipcc_mode = classify_zip_file(package_bytes).is_ipcc()
136
150
 
137
151
  if options is None:
138
152
  options = {}
139
153
 
140
154
  if ipcc_mode:
141
- options['PackageType'] = 'CarrierBundle'
155
+ options["PackageType"] = "CarrierBundle"
142
156
 
143
157
  with AfcService(self.lockdown) as afc:
144
158
  if not ipcc_mode:
@@ -148,17 +162,24 @@ class InstallationProxyService(LockdownService):
148
162
 
149
163
  self.send_package(cmd, options, handler, ipcc_mode, *args)
150
164
 
151
- @str_to_path('package_path')
152
- def install_from_local(self, package_path: Path, cmd: str = 'Install', options: Optional[dict] = None,
153
- handler: Callable = None, developer: bool = False, *args) -> None:
154
- """ upload given ipa/ipcc onto device and install it """
155
- ipcc_mode = package_path.suffix == '.ipcc'
165
+ @str_to_path("package_path")
166
+ def install_from_local(
167
+ self,
168
+ package_path: Path,
169
+ cmd: str = "Install",
170
+ options: Optional[dict] = None,
171
+ handler: Optional[Callable] = None,
172
+ developer: bool = False,
173
+ *args,
174
+ ) -> None:
175
+ """upload given ipa/ipcc onto device and install it"""
176
+ ipcc_mode = package_path.suffix == ".ipcc"
156
177
 
157
178
  if options is None:
158
179
  options = {}
159
180
 
160
181
  if ipcc_mode:
161
- options['PackageType'] = 'CarrierBundle'
182
+ options["PackageType"] = "CarrierBundle"
162
183
  else:
163
184
  if package_path.is_dir():
164
185
  # treat as app, convert into an ipa
@@ -168,7 +189,7 @@ class InstallationProxyService(LockdownService):
168
189
  ipa_contents = package_path.read_bytes()
169
190
 
170
191
  if developer:
171
- options['PackageType'] = 'Developer'
192
+ options["PackageType"] = "Developer"
172
193
 
173
194
  with AfcService(self.lockdown) as afc:
174
195
  if not ipcc_mode:
@@ -182,19 +203,16 @@ class InstallationProxyService(LockdownService):
182
203
 
183
204
  def send_package(self, cmd: str, options: Optional[dict], handler: Callable, ipcc_mode: bool = False, *args):
184
205
  self.service.send_plist({
185
- 'Command': cmd,
186
- 'ClientOptions': options,
187
- 'PackagePath': (
188
- TEMP_REMOTE_IPCC_FOLDER if ipcc_mode
189
- else TEMP_REMOTE_IPA_FILE
190
- )
206
+ "Command": cmd,
207
+ "ClientOptions": options,
208
+ "PackagePath": (TEMP_REMOTE_IPCC_FOLDER if ipcc_mode else TEMP_REMOTE_IPA_FILE),
191
209
  })
192
210
 
193
211
  self._watch_completion(handler, ipcc_mode, args)
194
212
 
195
213
  def upload_ipcc_from_path(self, file: Path, afc_client: AfcService) -> None:
196
214
  """Used to upload a .ipcc file to an iPhone as a folder"""
197
- with file.open('rb') as fb:
215
+ with file.open("rb") as fb:
198
216
  file_name = file.name
199
217
  file_stream = BytesIO(fb.read())
200
218
  self._upload_ipcc(file_stream, afc_client, file_name)
@@ -206,44 +224,41 @@ class InstallationProxyService(LockdownService):
206
224
  self._upload_ipcc(file_stream, afc_client, file_name)
207
225
 
208
226
  def _upload_ipcc(self, file_stream: BytesIO, afc_client: AfcService, file_name: str) -> None:
209
- self.logger.info(f'Uploading {file_name} contents..')
227
+ self.logger.info(f"Uploading {file_name} contents..")
210
228
 
211
229
  afc_client.makedirs(TEMP_REMOTE_IPCC_FOLDER)
212
230
 
213
231
  # we unpack it and upload it directly instead of saving it in a temp folder
214
- with ZipFile(file_stream, 'r') as file_zip:
232
+ with ZipFile(file_stream, "r") as file_zip:
215
233
  for file_name in file_zip.namelist():
216
-
217
- if file_name.endswith(('/', '\\')):
218
- afc_client.makedirs(f'{TEMP_REMOTE_IPCC_FOLDER}/{file_name}')
234
+ if file_name.endswith(("/", "\\")):
235
+ afc_client.makedirs(f"{TEMP_REMOTE_IPCC_FOLDER}/{file_name}")
219
236
  continue
220
237
 
221
238
  with file_zip.open(file_name) as inside_file_zip:
222
239
  file_data = inside_file_zip.read()
223
240
  afc_client.makedirs(TEMP_REMOTE_BASEDIR)
224
- afc_client.set_file_contents(f'{TEMP_REMOTE_IPCC_FOLDER}/{file_name}', file_data)
241
+ afc_client.set_file_contents(f"{TEMP_REMOTE_IPCC_FOLDER}/{file_name}", file_data)
225
242
 
226
- self.logger.info('Upload complete.')
243
+ self.logger.info("Upload complete.")
227
244
 
228
245
  def check_capabilities_match(self, capabilities: Optional[dict] = None, options: Optional[dict] = None) -> dict:
229
246
  if options is None:
230
247
  options = {}
231
- cmd = {'Command': 'CheckCapabilitiesMatch',
232
- 'ClientOptions': options}
248
+ cmd = {"Command": "CheckCapabilitiesMatch", "ClientOptions": options}
233
249
 
234
250
  if capabilities:
235
- cmd['Capabilities'] = capabilities
251
+ cmd["Capabilities"] = capabilities
236
252
 
237
- return self.service.send_recv_plist(cmd).get('LookupResult')
253
+ return self.service.send_recv_plist(cmd).get("LookupResult")
238
254
 
239
- def browse(self, options: Optional[dict] = None, attributes: list[str] = None) -> list[dict]:
255
+ def browse(self, options: Optional[dict] = None, attributes: Optional[list[str]] = None) -> list[dict]:
240
256
  if options is None:
241
257
  options = {}
242
258
  if attributes:
243
- options['ReturnAttributes'] = attributes
259
+ options["ReturnAttributes"] = attributes
244
260
 
245
- cmd = {'Command': 'Browse',
246
- 'ClientOptions': options}
261
+ cmd = {"Command": "Browse", "ClientOptions": options}
247
262
 
248
263
  self.service.send_plist(cmd)
249
264
 
@@ -253,30 +268,34 @@ class InstallationProxyService(LockdownService):
253
268
  if not response:
254
269
  break
255
270
 
256
- data = response.get('CurrentList')
271
+ data = response.get("CurrentList")
257
272
  if data is not None:
258
273
  result += data
259
274
 
260
- if response.get('Status') == 'Complete':
275
+ if response.get("Status") == "Complete":
261
276
  break
262
277
 
263
278
  return result
264
279
 
265
280
  def lookup(self, options: Optional[dict] = None) -> dict:
266
- """ search installation database """
281
+ """search installation database"""
267
282
  if options is None:
268
283
  options = {}
269
- cmd = {'Command': 'Lookup', 'ClientOptions': options}
270
- return self.service.send_recv_plist(cmd).get('LookupResult')
271
-
272
- def get_apps(self, application_type: str = 'Any', calculate_sizes: bool = False,
273
- bundle_identifiers: Optional[list[str]] = None) -> dict[str, dict]:
274
- """ get applications according to given criteria """
284
+ cmd = {"Command": "Lookup", "ClientOptions": options}
285
+ return self.service.send_recv_plist(cmd).get("LookupResult")
286
+
287
+ def get_apps(
288
+ self,
289
+ application_type: str = "Any",
290
+ calculate_sizes: bool = False,
291
+ bundle_identifiers: Optional[list[str]] = None,
292
+ ) -> dict[str, dict]:
293
+ """get applications according to given criteria"""
275
294
  options = {}
276
295
  if bundle_identifiers is not None:
277
- options['BundleIDs'] = bundle_identifiers
296
+ options["BundleIDs"] = bundle_identifiers
278
297
 
279
- options['ApplicationType'] = application_type
298
+ options["ApplicationType"] = application_type
280
299
  result = self.lookup(options)
281
300
  if calculate_sizes:
282
301
  options.update(GET_APPS_ADDITIONAL_INFO)
@@ -5,8 +5,14 @@ from pymobiledevice3.service_connection import ServiceConnection
5
5
 
6
6
 
7
7
  class LockdownService:
8
- def __init__(self, lockdown: LockdownServiceProvider, service_name: str, is_developer_service=False,
9
- service: ServiceConnection = None, include_escrow_bag: bool = False):
8
+ def __init__(
9
+ self,
10
+ lockdown: LockdownServiceProvider,
11
+ service_name: str,
12
+ is_developer_service=False,
13
+ service: ServiceConnection = None,
14
+ include_escrow_bag: bool = False,
15
+ ):
10
16
  """
11
17
  :param lockdown: server provider
12
18
  :param service_name: wrapped service name - will attempt
@@ -15,8 +21,9 @@ class LockdownService:
15
21
  """
16
22
 
17
23
  if service is None:
18
- start_service = lockdown.start_lockdown_developer_service if is_developer_service else \
19
- lockdown.start_lockdown_service
24
+ start_service = (
25
+ lockdown.start_lockdown_developer_service if is_developer_service else lockdown.start_lockdown_service
26
+ )
20
27
  service = start_service(service_name, include_escrow_bag=include_escrow_bag)
21
28
 
22
29
  self.service_name = service_name
@@ -27,7 +34,7 @@ class LockdownService:
27
34
  def __enter__(self):
28
35
  return self
29
36
 
30
- async def __aenter__(self) -> 'LockdownService':
37
+ async def __aenter__(self) -> "LockdownService":
31
38
  return self
32
39
 
33
40
  def __exit__(self, exc_type, exc_val, exc_tb):
@@ -10,8 +10,8 @@ class ProvisioningProfile:
10
10
  def __init__(self, buf: bytes):
11
11
  self.buf = buf
12
12
 
13
- xml = b'<?xml' + buf.split(b'<?xml', 1)[1]
14
- xml = xml.split(b'</plist>')[0] + b'</plist>'
13
+ xml = b"<?xml" + buf.split(b"<?xml", 1)[1]
14
+ xml = xml.split(b"</plist>")[0] + b"</plist>"
15
15
  self.plist = plistlib.loads(xml)
16
16
 
17
17
  def __str__(self):
@@ -19,8 +19,8 @@ class ProvisioningProfile:
19
19
 
20
20
 
21
21
  class MisagentService(LockdownService):
22
- SERVICE_NAME = 'com.apple.misagent'
23
- RSD_SERVICE_NAME = 'com.apple.misagent.shim.remote'
22
+ SERVICE_NAME = "com.apple.misagent"
23
+ RSD_SERVICE_NAME = "com.apple.misagent.shim.remote"
24
24
 
25
25
  def __init__(self, lockdown: LockdownClient):
26
26
  if isinstance(lockdown, LockdownClient):
@@ -29,27 +29,30 @@ class MisagentService(LockdownService):
29
29
  super().__init__(lockdown, self.RSD_SERVICE_NAME)
30
30
 
31
31
  def install(self, plist: BytesIO) -> dict:
32
- response = self.service.send_recv_plist({'MessageType': 'Install',
33
- 'Profile': plist.read(),
34
- 'ProfileType': 'Provisioning'})
35
- if response['Status']:
36
- raise PyMobileDevice3Exception(f'invalid status: {response}')
32
+ response = self.service.send_recv_plist({
33
+ "MessageType": "Install",
34
+ "Profile": plist.read(),
35
+ "ProfileType": "Provisioning",
36
+ })
37
+ if response["Status"]:
38
+ raise PyMobileDevice3Exception(f"invalid status: {response}")
37
39
 
38
40
  return response
39
41
 
40
42
  def remove(self, profile_id: str) -> dict:
41
- response = self.service.send_recv_plist({'MessageType': 'Remove',
42
- 'ProfileID': profile_id,
43
- 'ProfileType': 'Provisioning'})
44
- if response['Status']:
45
- raise PyMobileDevice3Exception(f'invalid status: {response}')
43
+ response = self.service.send_recv_plist({
44
+ "MessageType": "Remove",
45
+ "ProfileID": profile_id,
46
+ "ProfileType": "Provisioning",
47
+ })
48
+ if response["Status"]:
49
+ raise PyMobileDevice3Exception(f"invalid status: {response}")
46
50
 
47
51
  return response
48
52
 
49
53
  def copy_all(self) -> list[ProvisioningProfile]:
50
- response = self.service.send_recv_plist({'MessageType': 'CopyAll',
51
- 'ProfileType': 'Provisioning'})
52
- if response['Status']:
53
- raise PyMobileDevice3Exception(f'invalid status: {response}')
54
+ response = self.service.send_recv_plist({"MessageType": "CopyAll", "ProfileType": "Provisioning"})
55
+ if response["Status"]:
56
+ raise PyMobileDevice3Exception(f"invalid status: {response}")
54
57
 
55
- return [ProvisioningProfile(p) for p in response['Payload']]
58
+ return [ProvisioningProfile(p) for p in response["Payload"]]