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
@@ -2,18 +2,19 @@ import asyncio
2
2
  import logging
3
3
  from functools import update_wrapper
4
4
  from pathlib import Path
5
+ from typing import Annotated, Optional
5
6
  from urllib.error import URLError
6
7
 
7
- import click
8
+ import typer
9
+ from typer_injector import InjectingTyper
8
10
 
9
- from pymobiledevice3.cli.cli_common import Command, print_json
11
+ from pymobiledevice3.cli.cli_common import ServiceProviderDep, print_json
10
12
  from pymobiledevice3.exceptions import (
11
13
  AlreadyMountedError,
12
14
  DeveloperDiskImageNotFoundError,
13
15
  NotMountedError,
14
16
  UnsupportedCommandError,
15
17
  )
16
- from pymobiledevice3.lockdown import LockdownClient
17
18
  from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
18
19
  from pymobiledevice3.services.mobile_image_mounter import (
19
20
  DeveloperDiskImageMounter,
@@ -37,19 +38,15 @@ def catch_errors(func):
37
38
  return update_wrapper(catch_function, func)
38
39
 
39
40
 
40
- @click.group()
41
- def cli() -> None:
42
- pass
43
-
44
-
45
- @cli.group()
46
- def mounter() -> None:
47
- """Mount/Umount DeveloperDiskImage or query related info"""
48
- pass
41
+ cli = InjectingTyper(
42
+ name="mounter",
43
+ help="Mount/Umount DeveloperDiskImage or query related info",
44
+ no_args_is_help=True,
45
+ )
49
46
 
50
47
 
51
- @mounter.command("list", cls=Command)
52
- def mounter_list(service_provider: LockdownClient):
48
+ @cli.command("list")
49
+ def mounter_list(service_provider: ServiceProviderDep) -> None:
53
50
  """list all mounted images"""
54
51
  output = []
55
52
 
@@ -63,9 +60,8 @@ def mounter_list(service_provider: LockdownClient):
63
60
  print_json(output)
64
61
 
65
62
 
66
- @mounter.command("lookup", cls=Command)
67
- @click.argument("image_type")
68
- def mounter_lookup(service_provider: LockdownClient, image_type):
63
+ @cli.command("lookup")
64
+ def mounter_lookup(service_provider: ServiceProviderDep, image_type: str) -> None:
69
65
  """lookup mounter image type"""
70
66
  try:
71
67
  signature = MobileImageMounterService(lockdown=service_provider).lookup_image(image_type)
@@ -74,9 +70,9 @@ def mounter_lookup(service_provider: LockdownClient, image_type):
74
70
  logger.error(f"Disk image of type: {image_type} is not mounted")
75
71
 
76
72
 
77
- @mounter.command("umount-developer", cls=Command)
73
+ @cli.command("umount-developer")
78
74
  @catch_errors
79
- def mounter_umount_developer(service_provider: LockdownClient):
75
+ def mounter_umount_developer(service_provider: ServiceProviderDep) -> None:
80
76
  """unmount Developer image"""
81
77
  try:
82
78
  DeveloperDiskImageMounter(lockdown=service_provider).umount()
@@ -85,9 +81,9 @@ def mounter_umount_developer(service_provider: LockdownClient):
85
81
  logger.error("Developer image isn't currently mounted")
86
82
 
87
83
 
88
- @mounter.command("umount-personalized", cls=Command)
84
+ @cli.command("umount-personalized")
89
85
  @catch_errors
90
- def mounter_umount_personalized(service_provider: LockdownClient):
86
+ def mounter_umount_personalized(service_provider: ServiceProviderDep) -> None:
91
87
  """unmount Personalized image"""
92
88
  try:
93
89
  PersonalizedImageMounter(lockdown=service_provider).umount()
@@ -96,13 +92,29 @@ def mounter_umount_personalized(service_provider: LockdownClient):
96
92
  logger.error("Personalized image isn't currently mounted")
97
93
 
98
94
 
99
- @mounter.command("mount-developer", cls=Command)
100
- @click.argument("image", type=click.Path(exists=True, file_okay=True, dir_okay=False))
101
- @click.argument("signature", type=click.Path(exists=True, file_okay=True, dir_okay=False))
95
+ @cli.command("mount-developer")
102
96
  @catch_errors
103
- def mounter_mount_developer(service_provider: LockdownServiceProvider, image: str, signature: str) -> None:
97
+ def mounter_mount_developer(
98
+ service_provider: ServiceProviderDep,
99
+ image: Annotated[
100
+ Path,
101
+ typer.Argument(
102
+ exists=True,
103
+ file_okay=True,
104
+ dir_okay=False,
105
+ ),
106
+ ],
107
+ signature: Annotated[
108
+ Path,
109
+ typer.Argument(
110
+ exists=True,
111
+ file_okay=True,
112
+ dir_okay=False,
113
+ ),
114
+ ],
115
+ ) -> None:
104
116
  """mount developer image"""
105
- DeveloperDiskImageMounter(lockdown=service_provider).mount(Path(image), Path(signature))
117
+ DeveloperDiskImageMounter(lockdown=service_provider).mount(image, signature)
106
118
  logger.info("Developer image mounted successfully")
107
119
 
108
120
 
@@ -115,16 +127,39 @@ async def mounter_mount_personalized_task(
115
127
  logger.info("Personalized image mounted successfully")
116
128
 
117
129
 
118
- @mounter.command("mount-personalized", cls=Command)
119
- @click.argument("image", type=click.Path(exists=True, file_okay=True, dir_okay=False))
120
- @click.argument("trust-cache", type=click.Path(exists=True, file_okay=True, dir_okay=False))
121
- @click.argument("build-manifest", type=click.Path(exists=True, file_okay=True, dir_okay=False))
130
+ @cli.command("mount-personalized")
122
131
  @catch_errors
123
132
  def mounter_mount_personalized(
124
- service_provider: LockdownServiceProvider, image: str, trust_cache: str, build_manifest: str
133
+ service_provider: ServiceProviderDep,
134
+ image: Annotated[
135
+ Path,
136
+ typer.Argument(
137
+ exists=True,
138
+ file_okay=True,
139
+ dir_okay=False,
140
+ ),
141
+ ],
142
+ trust_cache: Annotated[
143
+ Path,
144
+ typer.Argument(
145
+ exists=True,
146
+ file_okay=True,
147
+ dir_okay=False,
148
+ ),
149
+ ],
150
+ build_manifest: Annotated[
151
+ Path,
152
+ typer.Argument(
153
+ exists=True,
154
+ file_okay=True,
155
+ dir_okay=False,
156
+ ),
157
+ ],
125
158
  ) -> None:
126
159
  """mount personalized image"""
127
- asyncio.run(mounter_mount_personalized_task(service_provider, image, trust_cache, build_manifest), debug=True)
160
+ asyncio.run(
161
+ mounter_mount_personalized_task(service_provider, str(image), str(trust_cache), str(build_manifest)), debug=True
162
+ )
128
163
 
129
164
 
130
165
  async def mounter_auto_mount_task(service_provider: LockdownServiceProvider, xcode: str, version: str) -> None:
@@ -144,42 +179,49 @@ async def mounter_auto_mount_task(service_provider: LockdownServiceProvider, xco
144
179
  )
145
180
 
146
181
 
147
- @mounter.command("auto-mount", cls=Command)
148
- @click.option(
149
- "-x",
150
- "--xcode",
151
- type=click.Path(exists=True, dir_okay=True, file_okay=False),
152
- help="Xcode application path used to figure out automatically the DeveloperDiskImage path",
153
- )
154
- @click.option(
155
- "--version", help="use a different DeveloperDiskImage version from the one retrieved by lockdownconnection"
156
- )
157
- def mounter_auto_mount(service_provider: LockdownServiceProvider, xcode: str, version: str) -> None:
182
+ @cli.command("auto-mount")
183
+ def mounter_auto_mount(
184
+ service_provider: ServiceProviderDep,
185
+ xcode: Annotated[
186
+ Optional[Path],
187
+ typer.Option(
188
+ "--xcode",
189
+ "-x",
190
+ exists=True,
191
+ file_okay=True,
192
+ dir_okay=False,
193
+ help="Xcode application path used to figure out automatically the DeveloperDiskImage path",
194
+ ),
195
+ ] = None,
196
+ version: Annotated[
197
+ Optional[str],
198
+ typer.Option(help="Use a different DeveloperDiskImage version from the one retrieved by lockdownconnection"),
199
+ ] = None,
200
+ ) -> None:
158
201
  """auto-detect correct DeveloperDiskImage and mount it"""
159
- asyncio.run(mounter_auto_mount_task(service_provider, xcode, version), debug=True)
202
+ asyncio.run(mounter_auto_mount_task(service_provider, str(xcode), version), debug=True)
160
203
 
161
204
 
162
- @mounter.command("query-developer-mode-status", cls=Command)
163
- def mounter_query_developer_mode_status(service_provider: LockdownClient):
205
+ @cli.command("query-developer-mode-status")
206
+ def mounter_query_developer_mode_status(service_provider: ServiceProviderDep) -> None:
164
207
  """Query developer mode status"""
165
208
  print_json(MobileImageMounterService(lockdown=service_provider).query_developer_mode_status())
166
209
 
167
210
 
168
- @mounter.command("query-nonce", cls=Command)
169
- @click.option("--image-type")
170
- def mounter_query_nonce(service_provider: LockdownClient, image_type: str):
211
+ @cli.command("query-nonce")
212
+ def mounter_query_nonce(service_provider: ServiceProviderDep, image_type: Annotated[str, typer.Option()]) -> None:
171
213
  """Query nonce"""
172
214
  print_json(MobileImageMounterService(lockdown=service_provider).query_nonce(image_type))
173
215
 
174
216
 
175
- @mounter.command("query-personalization-identifiers", cls=Command)
176
- def mounter_query_personalization_identifiers(service_provider: LockdownClient):
217
+ @cli.command("query-personalization-identifiers")
218
+ def mounter_query_personalization_identifiers(service_provider: ServiceProviderDep) -> None:
177
219
  """Query personalization identifiers"""
178
220
  print_json(MobileImageMounterService(lockdown=service_provider).query_personalization_identifiers())
179
221
 
180
222
 
181
- @mounter.command("query-personalization-manifest", cls=Command)
182
- def mounter_query_personalization_manifest(service_provider: LockdownClient):
223
+ @cli.command("query-personalization-manifest")
224
+ def mounter_query_personalization_manifest(service_provider: ServiceProviderDep) -> None:
183
225
  """Query personalization manifest"""
184
226
  result = []
185
227
  mounter = MobileImageMounterService(lockdown=service_provider)
@@ -188,12 +230,12 @@ def mounter_query_personalization_manifest(service_provider: LockdownClient):
188
230
  print_json(result)
189
231
 
190
232
 
191
- @mounter.command("roll-personalization-nonce", cls=Command)
192
- def mounter_roll_personalization_nonce(service_provider: LockdownClient):
233
+ @cli.command("roll-personalization-nonce")
234
+ def mounter_roll_personalization_nonce(service_provider: ServiceProviderDep) -> None:
193
235
  MobileImageMounterService(lockdown=service_provider).roll_personalization_nonce()
194
236
 
195
237
 
196
- @mounter.command("roll-cryptex-nonce", cls=Command)
197
- def mounter_roll_cryptex_nonce(service_provider: LockdownClient):
238
+ @cli.command("roll-cryptex-nonce")
239
+ def mounter_roll_cryptex_nonce(service_provider: ServiceProviderDep) -> None:
198
240
  """Roll cryptex nonce (will reboot)"""
199
241
  MobileImageMounterService(lockdown=service_provider).roll_cryptex_nonce()
@@ -1,41 +1,48 @@
1
1
  import logging
2
+ from typing import Annotated
2
3
 
3
- import click
4
+ import typer
5
+ from typer_injector import InjectingTyper
4
6
 
5
- from pymobiledevice3.cli.cli_common import Command
6
- from pymobiledevice3.lockdown import LockdownClient
7
+ from pymobiledevice3.cli.cli_common import ServiceProviderDep
7
8
  from pymobiledevice3.resources.firmware_notifications import get_notifications
8
9
  from pymobiledevice3.services.notification_proxy import NotificationProxyService
9
10
 
10
11
  logger = logging.getLogger(__name__)
11
12
 
12
13
 
13
- @click.group()
14
- def cli() -> None:
15
- pass
14
+ cli = InjectingTyper(
15
+ name="notifications",
16
+ help="Post or observe Darwin notifications via notification_proxy.",
17
+ no_args_is_help=True,
18
+ )
16
19
 
17
20
 
18
- @cli.group()
19
- def notification() -> None:
20
- """Post/Observe notifications"""
21
- pass
22
-
23
-
24
- @notification.command(cls=Command)
25
- @click.argument("names", nargs=-1)
26
- @click.option("--insecure", is_flag=True, help="use the insecure relay meant for untrusted clients instead")
27
- def post(service_provider: LockdownClient, names, insecure):
28
- """API for notify_post()."""
21
+ @cli.command()
22
+ def post(
23
+ service_provider: ServiceProviderDep,
24
+ names: list[str],
25
+ insecure: Annotated[
26
+ bool,
27
+ typer.Option(help="Use the insecure relay meant for untrusted clients instead of the trusted channel."),
28
+ ],
29
+ ) -> None:
30
+ """Post one or more Darwin notifications (notify_post)."""
29
31
  service = NotificationProxyService(lockdown=service_provider, insecure=insecure)
30
32
  for name in names:
31
33
  service.notify_post(name)
32
34
 
33
35
 
34
- @notification.command(cls=Command)
35
- @click.argument("names", nargs=-1)
36
- @click.option("--insecure", is_flag=True, help="use the insecure relay meant for untrusted clients instead")
37
- def observe(service_provider: LockdownClient, names, insecure):
38
- """API for notify_register_dispatch()."""
36
+ @cli.command()
37
+ def observe(
38
+ service_provider: ServiceProviderDep,
39
+ names: list[str],
40
+ insecure: Annotated[
41
+ bool,
42
+ typer.Option(help="Use the insecure relay meant for untrusted clients instead of the trusted channel."),
43
+ ],
44
+ ) -> None:
45
+ """Subscribe and stream notifications (notify_register_dispatch)."""
39
46
  service = NotificationProxyService(lockdown=service_provider, insecure=insecure)
40
47
  for name in names:
41
48
  service.notify_register_dispatch(name)
@@ -44,10 +51,15 @@ def observe(service_provider: LockdownClient, names, insecure):
44
51
  logger.info(event)
45
52
 
46
53
 
47
- @notification.command("observe-all", cls=Command)
48
- @click.option("--insecure", is_flag=True, help="use the insecure relay meant for untrusted clients instead")
49
- def observe_all(service_provider: LockdownClient, insecure):
50
- """attempt to observe all builtin firmware notifications."""
54
+ @cli.command("observe-all")
55
+ def observe_all(
56
+ service_provider: ServiceProviderDep,
57
+ insecure: Annotated[
58
+ bool,
59
+ typer.Option(help="Use the insecure relay meant for untrusted clients instead of the trusted channel."),
60
+ ],
61
+ ) -> None:
62
+ """Subscribe to all known firmware notifications and stream events."""
51
63
  service = NotificationProxyService(lockdown=service_provider, insecure=insecure)
52
64
  for notification in get_notifications():
53
65
  service.notify_register_dispatch(notification)
@@ -1,17 +1,19 @@
1
1
  from datetime import datetime
2
- from typing import IO, Optional
2
+ from pathlib import Path
3
+ from typing import Annotated, Optional
3
4
 
4
- import click
5
+ import typer
5
6
  from pygments import formatters, highlight, lexers
7
+ from typer_injector import InjectingTyper
6
8
 
7
- from pymobiledevice3.cli.cli_common import Command, print_hex, user_requested_colored_output
8
- from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
9
+ from pymobiledevice3.cli.cli_common import ServiceProviderDep, print_hex, user_requested_colored_output
9
10
  from pymobiledevice3.services.pcapd import PcapdService
10
11
 
11
-
12
- @click.group()
13
- def cli() -> None:
14
- pass
12
+ cli = InjectingTyper(
13
+ name="pcap",
14
+ help="Sniff device traffic via pcapd and optionally save to a .pcap file.",
15
+ no_args_is_help=True,
16
+ )
15
17
 
16
18
 
17
19
  def print_packet_header(packet, color: bool) -> None:
@@ -37,25 +39,39 @@ def print_packet(packet, color: Optional[bool] = None):
37
39
  return packet
38
40
 
39
41
 
40
- @cli.command(cls=Command)
41
- @click.argument("out", type=click.File("wb"), required=False)
42
- @click.option("-c", "--count", type=click.INT, default=-1, help="Number of packets to sniff. Omit to endless sniff.")
43
- @click.option("--process", default=None, help="Process to filter. Omit for all.")
44
- @click.option("-i", "--interface", default=None, help="Interface name to filter. Omit for all.")
42
+ @cli.command()
45
43
  def pcap(
46
- service_provider: LockdownServiceProvider,
47
- out: Optional[IO],
48
- count: int,
49
- process: Optional[str],
50
- interface: Optional[str],
44
+ service_provider: ServiceProviderDep,
45
+ out: Optional[Path] = None,
46
+ count: Annotated[
47
+ int,
48
+ typer.Option(
49
+ "--count",
50
+ "-c",
51
+ help="Number of packets to sniff. Omit to endless sniff.",
52
+ ),
53
+ ] = -1,
54
+ process: Annotated[
55
+ Optional[str],
56
+ typer.Option(help="Process to filter. Omit for all."),
57
+ ] = None,
58
+ interface: Annotated[
59
+ Optional[str],
60
+ typer.Option(
61
+ "--interface",
62
+ "-i",
63
+ help="Interface name to filter. Omit for all.",
64
+ ),
65
+ ] = None,
51
66
  ) -> None:
52
- """Sniff device traffic"""
67
+ """Sniff device traffic."""
53
68
  service = PcapdService(lockdown=service_provider)
54
69
  packets_generator = service.watch(packets_count=count, process=process, interface_name=interface)
55
70
 
56
71
  if out is not None:
57
72
  packets_generator_with_print = (print_packet(p) for p in packets_generator)
58
- service.write_to_pcap(out, packets_generator_with_print)
73
+ with out.open("wb") as out_file:
74
+ service.write_to_pcap(out_file, packets_generator_with_print)
59
75
  return
60
76
 
61
77
  for packet in packets_generator:
@@ -1,26 +1,25 @@
1
1
  import time
2
+ from typing import Literal, Optional
2
3
 
3
- import click
4
+ from typer_injector import InjectingTyper
4
5
 
5
- from pymobiledevice3.cli.cli_common import Command
6
- from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
6
+ from pymobiledevice3.cli.cli_common import ServiceProviderDep
7
7
  from pymobiledevice3.services.power_assertion import PowerAssertionService
8
8
 
9
-
10
- @click.group()
11
- def cli() -> None:
12
- pass
9
+ cli = InjectingTyper(
10
+ name="power-assertion",
11
+ no_args_is_help=True,
12
+ )
13
13
 
14
14
 
15
- @cli.command("power-assertion", cls=Command)
16
- @click.argument(
17
- "assertion_type",
18
- type=click.Choice(["AMDPowerAssertionTypeWirelessSync", "PreventUserIdleSystemSleep", "PreventSystemSleep"]),
19
- )
20
- @click.argument("name")
21
- @click.argument("timeout", type=click.INT)
22
- @click.argument("details", required=False)
23
- def power_assertion(service_provider: LockdownServiceProvider, assertion_type, name, timeout, details) -> None:
15
+ @cli.command("power-assertion")
16
+ def power_assertion(
17
+ service_provider: ServiceProviderDep,
18
+ assertion_type: Literal["AMDPowerAssertionTypeWirelessSync", "PreventUserIdleSystemSleep", "PreventSystemSleep"],
19
+ name: str,
20
+ timeout: int,
21
+ details: Optional[str] = None,
22
+ ) -> None:
24
23
  """Create a power assertion"""
25
24
  with PowerAssertionService(service_provider).create_power_assertion(assertion_type, name, timeout, details):
26
25
  print("> Hit Ctrl+C to exit")
@@ -1,34 +1,28 @@
1
1
  import logging
2
2
 
3
- import click
3
+ from typer_injector import InjectingTyper
4
4
 
5
- from pymobiledevice3.cli.cli_common import Command, print_json
6
- from pymobiledevice3.lockdown import LockdownClient
5
+ from pymobiledevice3.cli.cli_common import ServiceProviderDep, print_json
7
6
  from pymobiledevice3.services.os_trace import OsTraceService
8
7
 
9
8
  logger = logging.getLogger(__name__)
10
9
 
11
10
 
12
- @click.group()
13
- def cli() -> None:
14
- pass
11
+ cli = InjectingTyper(
12
+ name="processes",
13
+ help="View process list using diagnosticsd API",
14
+ no_args_is_help=True,
15
+ )
15
16
 
16
17
 
17
- @cli.group()
18
- def processes() -> None:
19
- """View process list using diagnosticsd API"""
20
- pass
21
-
22
-
23
- @processes.command("ps", cls=Command)
24
- def processes_ps(service_provider: LockdownClient):
18
+ @cli.command("ps")
19
+ def processes_ps(service_provider: ServiceProviderDep) -> None:
25
20
  """show process list"""
26
21
  print_json(OsTraceService(lockdown=service_provider).get_pid_list().get("Payload"))
27
22
 
28
23
 
29
- @processes.command("pgrep", cls=Command)
30
- @click.argument("expression")
31
- def processes_pgrep(service_provider: LockdownClient, expression):
24
+ @cli.command("pgrep")
25
+ def processes_pgrep(service_provider: ServiceProviderDep, expression: str) -> None:
32
26
  """try to match processes pid by given expression (like pgrep)"""
33
27
  processes_list = OsTraceService(lockdown=service_provider).get_pid_list().get("Payload")
34
28
  for pid, process_info in processes_list.items():