pymobiledevice3 5.0.1__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 +442 -421
  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.1.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.1.dist-info/RECORD +0 -173
  140. {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.2.dist-info}/WHEEL +0 -0
  141. {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.2.dist-info}/entry_points.txt +0 -0
  142. {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.2.dist-info}/licenses/LICENSE +0 -0
  143. {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.2.dist-info}/top_level.txt +0 -0
@@ -34,97 +34,116 @@ from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
34
34
  from pymobiledevice3.services.lockdown_service import LockdownService
35
35
  from pymobiledevice3.utils import try_decode
36
36
 
37
- MAXIMUM_READ_SIZE = 4 * 1024 ** 2 # 4 MB
37
+ MAXIMUM_READ_SIZE = 4 * 1024**2 # 4 MB
38
38
  MODE_MASK = 0o0000777
39
39
 
40
- StatResult = namedtuple('StatResult',
41
- ['st_mode', 'st_ino', 'st_dev', 'st_nlink', 'st_uid', 'st_gid', 'st_size', 'st_atime',
42
- 'st_mtime', 'st_ctime', 'st_blocks', 'st_blksize', 'st_birthtime'])
43
-
44
- afc_opcode_t = Enum(Int64ul,
45
- STATUS=0x00000001,
46
- DATA=0x00000002, # Data */
47
- READ_DIR=0x00000003, # ReadDir */
48
- READ_FILE=0x00000004, # ReadFile */
49
- WRITE_FILE=0x00000005, # WriteFile */
50
- WRITE_PART=0x00000006, # WritePart */
51
- TRUNCATE=0x00000007, # TruncateFile */
52
- REMOVE_PATH=0x00000008, # RemovePath */
53
- MAKE_DIR=0x00000009, # MakeDir */
54
- GET_FILE_INFO=0x0000000a, # GetFileInfo */
55
- GET_DEVINFO=0x0000000b, # GetDeviceInfo */
56
- WRITE_FILE_ATOM=0x0000000c, # WriteFileAtomic (tmp file+rename) */
57
- FILE_OPEN=0x0000000d, # FileRefOpen */
58
- FILE_OPEN_RES=0x0000000e, # FileRefOpenResult */
59
- READ=0x0000000f, # FileRefRead */
60
- WRITE=0x00000010, # FileRefWrite */
61
- FILE_SEEK=0x00000011, # FileRefSeek */
62
- FILE_TELL=0x00000012, # FileRefTell */
63
- FILE_TELL_RES=0x00000013, # FileRefTellResult */
64
- FILE_CLOSE=0x00000014, # FileRefClose */
65
- FILE_SET_SIZE=0x00000015, # FileRefSetFileSize (ftruncate) */
66
- GET_CON_INFO=0x00000016, # GetConnectionInfo */
67
- SET_CON_OPTIONS=0x00000017, # SetConnectionOptions */
68
- RENAME_PATH=0x00000018, # RenamePath */
69
- SET_FS_BS=0x00000019, # SetFSBlockSize (0x800000) */
70
- SET_SOCKET_BS=0x0000001A, # SetSocketBlockSize (0x800000) */
71
- FILE_LOCK=0x0000001B, # FileRefLock */
72
- MAKE_LINK=0x0000001C, # MakeLink */
73
- SET_FILE_TIME=0x0000001E, # set st_mtime */
74
- )
40
+ StatResult = namedtuple(
41
+ "StatResult",
42
+ [
43
+ "st_mode",
44
+ "st_ino",
45
+ "st_dev",
46
+ "st_nlink",
47
+ "st_uid",
48
+ "st_gid",
49
+ "st_size",
50
+ "st_atime",
51
+ "st_mtime",
52
+ "st_ctime",
53
+ "st_blocks",
54
+ "st_blksize",
55
+ "st_birthtime",
56
+ ],
57
+ )
75
58
 
76
- afc_error_t = Enum(Int64ul,
77
- SUCCESS=0,
78
- UNKNOWN_ERROR=1,
79
- OP_HEADER_INVALID=2,
80
- NO_RESOURCES=3,
81
- READ_ERROR=4,
82
- WRITE_ERROR=5,
83
- UNKNOWN_PACKET_TYPE=6,
84
- INVALID_ARG=7,
85
- OBJECT_NOT_FOUND=8,
86
- OBJECT_IS_DIR=9,
87
- PERM_DENIED=10,
88
- SERVICE_NOT_CONNECTED=11,
89
- OP_TIMEOUT=12,
90
- TOO_MUCH_DATA=13,
91
- END_OF_DATA=14,
92
- OP_NOT_SUPPORTED=15,
93
- OBJECT_EXISTS=16,
94
- OBJECT_BUSY=17,
95
- NO_SPACE_LEFT=18,
96
- OP_WOULD_BLOCK=19,
97
- IO_ERROR=20,
98
- OP_INTERRUPTED=21,
99
- OP_IN_PROGRESS=22,
100
- INTERNAL_ERROR=23,
101
- MUX_ERROR=30,
102
- NO_MEM=31,
103
- NOT_ENOUGH_DATA=32,
104
- DIR_NOT_EMPTY=33,
105
- )
106
-
107
- afc_link_type_t = Enum(Int64ul,
108
- HARDLINK=1,
109
- SYMLINK=2,
110
- )
111
-
112
- afc_fopen_mode_t = Enum(Int64ul,
113
- RDONLY=0x00000001, # /**< r O_RDONLY */
114
- RW=0x00000002, # /**< r+ O_RDWR | O_CREAT */
115
- WRONLY=0x00000003, # /**< w O_WRONLY | O_CREAT | O_TRUNC */
116
- WR=0x00000004, # /**< w+ O_RDWR | O_CREAT | O_TRUNC */
117
- APPEND=0x00000005, # /**< a O_WRONLY | O_APPEND | O_CREAT */
118
- RDAPPEND=0x00000006, # /**< a+ O_RDWR | O_APPEND | O_CREAT */
119
- )
59
+ afc_opcode_t = Enum(
60
+ Int64ul,
61
+ STATUS=0x00000001,
62
+ DATA=0x00000002, # Data */
63
+ READ_DIR=0x00000003, # ReadDir */
64
+ READ_FILE=0x00000004, # ReadFile */
65
+ WRITE_FILE=0x00000005, # WriteFile */
66
+ WRITE_PART=0x00000006, # WritePart */
67
+ TRUNCATE=0x00000007, # TruncateFile */
68
+ REMOVE_PATH=0x00000008, # RemovePath */
69
+ MAKE_DIR=0x00000009, # MakeDir */
70
+ GET_FILE_INFO=0x0000000A, # GetFileInfo */
71
+ GET_DEVINFO=0x0000000B, # GetDeviceInfo */
72
+ WRITE_FILE_ATOM=0x0000000C, # WriteFileAtomic (tmp file+rename) */
73
+ FILE_OPEN=0x0000000D, # FileRefOpen */
74
+ FILE_OPEN_RES=0x0000000E, # FileRefOpenResult */
75
+ READ=0x0000000F, # FileRefRead */
76
+ WRITE=0x00000010, # FileRefWrite */
77
+ FILE_SEEK=0x00000011, # FileRefSeek */
78
+ FILE_TELL=0x00000012, # FileRefTell */
79
+ FILE_TELL_RES=0x00000013, # FileRefTellResult */
80
+ FILE_CLOSE=0x00000014, # FileRefClose */
81
+ FILE_SET_SIZE=0x00000015, # FileRefSetFileSize (ftruncate) */
82
+ GET_CON_INFO=0x00000016, # GetConnectionInfo */
83
+ SET_CON_OPTIONS=0x00000017, # SetConnectionOptions */
84
+ RENAME_PATH=0x00000018, # RenamePath */
85
+ SET_FS_BS=0x00000019, # SetFSBlockSize (0x800000) */
86
+ SET_SOCKET_BS=0x0000001A, # SetSocketBlockSize (0x800000) */
87
+ FILE_LOCK=0x0000001B, # FileRefLock */
88
+ MAKE_LINK=0x0000001C, # MakeLink */
89
+ SET_FILE_TIME=0x0000001E, # set st_mtime */
90
+ )
91
+
92
+ afc_error_t = Enum(
93
+ Int64ul,
94
+ SUCCESS=0,
95
+ UNKNOWN_ERROR=1,
96
+ OP_HEADER_INVALID=2,
97
+ NO_RESOURCES=3,
98
+ READ_ERROR=4,
99
+ WRITE_ERROR=5,
100
+ UNKNOWN_PACKET_TYPE=6,
101
+ INVALID_ARG=7,
102
+ OBJECT_NOT_FOUND=8,
103
+ OBJECT_IS_DIR=9,
104
+ PERM_DENIED=10,
105
+ SERVICE_NOT_CONNECTED=11,
106
+ OP_TIMEOUT=12,
107
+ TOO_MUCH_DATA=13,
108
+ END_OF_DATA=14,
109
+ OP_NOT_SUPPORTED=15,
110
+ OBJECT_EXISTS=16,
111
+ OBJECT_BUSY=17,
112
+ NO_SPACE_LEFT=18,
113
+ OP_WOULD_BLOCK=19,
114
+ IO_ERROR=20,
115
+ OP_INTERRUPTED=21,
116
+ OP_IN_PROGRESS=22,
117
+ INTERNAL_ERROR=23,
118
+ MUX_ERROR=30,
119
+ NO_MEM=31,
120
+ NOT_ENOUGH_DATA=32,
121
+ DIR_NOT_EMPTY=33,
122
+ )
123
+
124
+ afc_link_type_t = Enum(
125
+ Int64ul,
126
+ HARDLINK=1,
127
+ SYMLINK=2,
128
+ )
129
+
130
+ afc_fopen_mode_t = Enum(
131
+ Int64ul,
132
+ RDONLY=0x00000001, # /**< r O_RDONLY */
133
+ RW=0x00000002, # /**< r+ O_RDWR | O_CREAT */
134
+ WRONLY=0x00000003, # /**< w O_WRONLY | O_CREAT | O_TRUNC */
135
+ WR=0x00000004, # /**< w+ O_RDWR | O_CREAT | O_TRUNC */
136
+ APPEND=0x00000005, # /**< a O_WRONLY | O_APPEND | O_CREAT */
137
+ RDAPPEND=0x00000006, # /**< a+ O_RDWR | O_APPEND | O_CREAT */
138
+ )
120
139
 
121
140
  AFC_FOPEN_TEXTUAL_MODES = {
122
- 'r': afc_fopen_mode_t.RDONLY,
123
- 'r+': afc_fopen_mode_t.RW,
124
- 'w': afc_fopen_mode_t.WRONLY,
125
- 'w+': afc_fopen_mode_t.WR,
126
- 'a': afc_fopen_mode_t.APPEND,
127
- 'a+': afc_fopen_mode_t.RDAPPEND,
141
+ "r": afc_fopen_mode_t.RDONLY,
142
+ "r+": afc_fopen_mode_t.RW,
143
+ "w": afc_fopen_mode_t.WRONLY,
144
+ "w+": afc_fopen_mode_t.WR,
145
+ "a": afc_fopen_mode_t.APPEND,
146
+ "a+": afc_fopen_mode_t.RDAPPEND,
128
147
  }
129
148
 
130
149
  AFC_LOCK_SH = 1 | 4 # /**< shared lock */
@@ -133,75 +152,75 @@ AFC_LOCK_UN = 8 | 4 # /**< unlock */
133
152
 
134
153
  MAXIMUM_WRITE_SIZE = 1 << 30
135
154
 
136
- AFCMAGIC = b'CFA6LPAA'
155
+ AFCMAGIC = b"CFA6LPAA"
137
156
 
138
157
  afc_header_t = Struct(
139
- 'magic' / Const(AFCMAGIC),
140
- 'entire_length' / Int64ul,
141
- 'this_length' / Int64ul,
142
- 'packet_num' / Int64ul,
143
- 'operation' / afc_opcode_t,
144
- '_data_offset' / Tell,
158
+ "magic" / Const(AFCMAGIC),
159
+ "entire_length" / Int64ul,
160
+ "this_length" / Int64ul,
161
+ "packet_num" / Int64ul,
162
+ "operation" / afc_opcode_t,
163
+ "_data_offset" / Tell,
145
164
  )
146
165
 
147
166
  afc_read_dir_req_t = Struct(
148
- 'filename' / CString('utf8'),
167
+ "filename" / CString("utf8"),
149
168
  )
150
169
 
151
170
  afc_read_dir_resp_t = Struct(
152
- 'filenames' / GreedyRange(CString('utf8')),
171
+ "filenames" / GreedyRange(CString("utf8")),
153
172
  )
154
173
 
155
174
  afc_mkdir_req_t = Struct(
156
- 'filename' / CString('utf8'),
175
+ "filename" / CString("utf8"),
157
176
  )
158
177
 
159
178
  afc_stat_t = Struct(
160
- 'filename' / CString('utf8'),
179
+ "filename" / CString("utf8"),
161
180
  )
162
181
 
163
182
  afc_make_link_req_t = Struct(
164
- 'type' / afc_link_type_t,
165
- 'target' / CString('utf8'),
166
- 'source' / CString('utf8'),
183
+ "type" / afc_link_type_t,
184
+ "target" / CString("utf8"),
185
+ "source" / CString("utf8"),
167
186
  )
168
187
 
169
188
  afc_fopen_req_t = Struct(
170
- 'mode' / afc_fopen_mode_t,
171
- 'filename' / CString('utf8'),
189
+ "mode" / afc_fopen_mode_t,
190
+ "filename" / CString("utf8"),
172
191
  )
173
192
 
174
193
  afc_fopen_resp_t = Struct(
175
- 'handle' / Int64ul,
194
+ "handle" / Int64ul,
176
195
  )
177
196
 
178
197
  afc_fclose_req_t = Struct(
179
- 'handle' / Int64ul,
198
+ "handle" / Int64ul,
180
199
  )
181
200
 
182
201
  afc_rm_req_t = Struct(
183
- 'filename' / CString('utf8'),
202
+ "filename" / CString("utf8"),
184
203
  )
185
204
 
186
205
  afc_rename_req_t = Struct(
187
- 'source' / CString('utf8'),
188
- 'target' / CString('utf8'),
206
+ "source" / CString("utf8"),
207
+ "target" / CString("utf8"),
189
208
  )
190
209
 
191
210
  afc_fread_req_t = Struct(
192
- 'handle' / Int64ul,
193
- 'size' / Int64ul,
211
+ "handle" / Int64ul,
212
+ "size" / Int64ul,
194
213
  )
195
214
 
196
215
  afc_lock_t = Struct(
197
- 'handle' / Int64ul,
198
- 'op' / Int64ul,
216
+ "handle" / Int64ul,
217
+ "op" / Int64ul,
199
218
  )
200
219
 
201
220
 
202
221
  def list_to_dict(d):
203
- d = d.decode('utf-8')
204
- t = d.split('\x00')
222
+ d = d.decode("utf-8")
223
+ t = d.split("\x00")
205
224
  t = t[:-1]
206
225
 
207
226
  assert len(t) % 2 == 0
@@ -212,28 +231,33 @@ def list_to_dict(d):
212
231
 
213
232
 
214
233
  class AfcService(LockdownService):
215
- SERVICE_NAME = 'com.apple.afc'
216
- RSD_SERVICE_NAME = 'com.apple.afc.shim.remote'
234
+ SERVICE_NAME = "com.apple.afc"
235
+ RSD_SERVICE_NAME = "com.apple.afc.shim.remote"
217
236
 
218
- def __init__(self, lockdown: LockdownServiceProvider, service_name: str = None):
237
+ def __init__(self, lockdown: LockdownServiceProvider, service_name: Optional[str] = None):
219
238
  if service_name is None:
220
- if isinstance(lockdown, LockdownClient):
221
- service_name = self.SERVICE_NAME
222
- else:
223
- service_name = self.RSD_SERVICE_NAME
239
+ service_name = self.SERVICE_NAME if isinstance(lockdown, LockdownClient) else self.RSD_SERVICE_NAME
224
240
  super().__init__(lockdown, service_name)
225
241
  self.packet_num = 0
226
242
 
227
- def pull(self, relative_src: str, dst: str, match: Optional[Pattern] = None, callback: Optional[Callable] = None,
228
- src_dir: str = '', ignore_errors: bool = False, progress_bar: bool = True) -> None:
243
+ def pull(
244
+ self,
245
+ relative_src: str,
246
+ dst: str,
247
+ match: Optional[Pattern] = None,
248
+ callback: Optional[Callable] = None,
249
+ src_dir: str = "",
250
+ ignore_errors: bool = False,
251
+ progress_bar: bool = True,
252
+ ) -> None:
229
253
  src = self.resolve_path(posixpath.join(src_dir, relative_src))
230
254
 
231
255
  if not self.isdir(src):
232
256
  # normal file
233
257
  if os.path.isdir(dst):
234
258
  dst = os.path.join(dst, os.path.basename(relative_src))
235
- with open(dst, 'wb') as f:
236
- src_size = self.stat(src)['st_size']
259
+ with open(dst, "wb") as f:
260
+ src_size = self.stat(src)["st_size"]
237
261
  if src_size <= MAXIMUM_READ_SIZE:
238
262
  f.write(self.get_file_contents(src))
239
263
  else:
@@ -247,7 +271,7 @@ class AfcService(LockdownService):
247
271
  f.write(self.fread(handle, min(MAXIMUM_READ_SIZE, left_size)))
248
272
  left_size -= MAXIMUM_READ_SIZE
249
273
  self.fclose(handle)
250
- os.utime(dst, (os.stat(dst).st_atime, self.stat(src)['st_mtime'].timestamp()))
274
+ os.utime(dst, (os.stat(dst).st_atime, self.stat(src)["st_mtime"].timestamp()))
251
275
  if callback is not None:
252
276
  callback(src, dst)
253
277
  else:
@@ -267,12 +291,22 @@ class AfcService(LockdownService):
267
291
  try:
268
292
  if self.isdir(src_filename):
269
293
  dst_filename.mkdir(exist_ok=True)
270
- self.pull(src_filename, str(dst_path), callback=callback, ignore_errors=ignore_errors,
271
- progress_bar=progress_bar)
294
+ self.pull(
295
+ src_filename,
296
+ str(dst_path),
297
+ callback=callback,
298
+ ignore_errors=ignore_errors,
299
+ progress_bar=progress_bar,
300
+ )
272
301
  continue
273
302
 
274
- self.pull(src_filename, str(dst_path), callback=callback, ignore_errors=ignore_errors,
275
- progress_bar=progress_bar)
303
+ self.pull(
304
+ src_filename,
305
+ str(dst_path),
306
+ callback=callback,
307
+ ignore_errors=ignore_errors,
308
+ progress_bar=progress_bar,
309
+ )
276
310
 
277
311
  except Exception as afc_exception:
278
312
  if not ignore_errors:
@@ -283,9 +317,9 @@ class AfcService(LockdownService):
283
317
  def exists(self, filename):
284
318
  try:
285
319
  self.stat(filename)
286
- return True
287
320
  except AfcFileNotFoundError:
288
321
  return False
322
+ return True
289
323
 
290
324
  @path_to_str()
291
325
  def wait_exists(self, filename):
@@ -309,7 +343,7 @@ class AfcService(LockdownService):
309
343
  if not self.exists(remote_parent):
310
344
  raise
311
345
  remote_path = posixpath.join(remote_parent, os.path.basename(remote_path))
312
- with open(local_path, 'rb') as f:
346
+ with open(local_path, "rb") as f:
313
347
  self.set_file_contents(remote_path, f.read())
314
348
  else:
315
349
  # directory
@@ -318,7 +352,7 @@ class AfcService(LockdownService):
318
352
 
319
353
  for filename in os.listdir(local_path):
320
354
  local_filename = os.path.join(local_path, filename)
321
- remote_filename = posixpath.join(remote_path, filename).removeprefix('/')
355
+ remote_filename = posixpath.join(remote_path, filename).removeprefix("/")
322
356
 
323
357
  if os.path.isdir(local_filename):
324
358
  if not self.exists(remote_filename):
@@ -336,7 +370,7 @@ class AfcService(LockdownService):
336
370
 
337
371
  @path_to_str()
338
372
  def rm_single(self, filename: str, force: bool = False) -> bool:
339
- """ remove single file or directory
373
+ """remove single file or directory
340
374
 
341
375
  return if succeed or raise exception depending on force parameter.
342
376
 
@@ -346,16 +380,16 @@ class AfcService(LockdownService):
346
380
  :rtype: bool
347
381
  """
348
382
  try:
349
- self._do_operation(afc_opcode_t.REMOVE_PATH, afc_rm_req_t.build({'filename': filename}))
350
- return True
383
+ self._do_operation(afc_opcode_t.REMOVE_PATH, afc_rm_req_t.build({"filename": filename}))
351
384
  except AfcException:
352
385
  if force:
353
386
  return False
354
387
  raise
388
+ return True
355
389
 
356
390
  @path_to_str()
357
391
  def rm(self, filename: str, match: Optional[Pattern] = None, force: bool = False) -> list[str]:
358
- """ recursive removal of a directory or a file
392
+ """recursive removal of a directory or a file
359
393
 
360
394
  if did not succeed, return list of undeleted filenames or raise exception depending on force parameter.
361
395
 
@@ -365,9 +399,8 @@ class AfcService(LockdownService):
365
399
  :return: list of undeleted paths
366
400
  :rtype: list[str]
367
401
  """
368
- if not self.exists(filename):
369
- if not self.rm_single(filename, force=force):
370
- return [filename]
402
+ if not self.exists(filename) and not self.rm_single(filename, force=force):
403
+ return [filename]
371
404
 
372
405
  # single file
373
406
  if not self.isdir(filename):
@@ -402,7 +435,7 @@ class AfcService(LockdownService):
402
435
  raise
403
436
 
404
437
  if undeleted_items:
405
- raise AfcException(f'Failed to delete paths: {undeleted_items}', None)
438
+ raise AfcException(f"Failed to delete paths: {undeleted_items}", None)
406
439
 
407
440
  return []
408
441
 
@@ -411,129 +444,132 @@ class AfcService(LockdownService):
411
444
 
412
445
  @path_to_str()
413
446
  def listdir(self, filename: str):
414
- data = self._do_operation(afc_opcode_t.READ_DIR, afc_read_dir_req_t.build({'filename': filename}))
447
+ data = self._do_operation(afc_opcode_t.READ_DIR, afc_read_dir_req_t.build({"filename": filename}))
415
448
  return afc_read_dir_resp_t.parse(data).filenames[2:] # skip the . and ..
416
449
 
417
450
  @path_to_str()
418
451
  def makedirs(self, filename: str):
419
- return self._do_operation(afc_opcode_t.MAKE_DIR, afc_mkdir_req_t.build({'filename': filename}))
452
+ return self._do_operation(afc_opcode_t.MAKE_DIR, afc_mkdir_req_t.build({"filename": filename}))
420
453
 
421
454
  @path_to_str()
422
455
  def isdir(self, filename: str) -> bool:
423
456
  stat = self.stat(filename)
424
- return stat.get('st_ifmt') == 'S_IFDIR'
457
+ return stat.get("st_ifmt") == "S_IFDIR"
425
458
 
426
459
  @path_to_str()
427
460
  def stat(self, filename: str):
428
461
  try:
429
462
  stat = list_to_dict(
430
- self._do_operation(afc_opcode_t.GET_FILE_INFO, afc_stat_t.build({'filename': filename})))
463
+ self._do_operation(afc_opcode_t.GET_FILE_INFO, afc_stat_t.build({"filename": filename}))
464
+ )
431
465
  except AfcException as e:
432
466
  if e.status != afc_error_t.READ_ERROR:
433
467
  raise
434
468
  raise AfcFileNotFoundError(e.args[0], e.status) from e
435
469
 
436
- stat['st_size'] = int(stat['st_size'])
437
- stat['st_blocks'] = int(stat['st_blocks'])
438
- stat['st_mtime'] = int(stat['st_mtime'])
439
- stat['st_birthtime'] = int(stat['st_birthtime'])
440
- stat['st_nlink'] = int(stat['st_nlink'])
441
- stat['st_mtime'] = datetime.fromtimestamp(stat['st_mtime'] / (10 ** 9))
442
- stat['st_birthtime'] = datetime.fromtimestamp(stat['st_birthtime'] / (10 ** 9))
470
+ stat["st_size"] = int(stat["st_size"])
471
+ stat["st_blocks"] = int(stat["st_blocks"])
472
+ stat["st_mtime"] = int(stat["st_mtime"])
473
+ stat["st_birthtime"] = int(stat["st_birthtime"])
474
+ stat["st_nlink"] = int(stat["st_nlink"])
475
+ stat["st_mtime"] = datetime.fromtimestamp(stat["st_mtime"] / (10**9))
476
+ stat["st_birthtime"] = datetime.fromtimestamp(stat["st_birthtime"] / (10**9))
443
477
  return stat
444
478
 
445
479
  @path_to_str()
446
480
  def os_stat(self, path: str):
447
481
  stat = self.stat(path)
448
482
  mode = 0
449
- for s_mode in ['S_IFDIR', 'S_IFCHR', 'S_IFBLK', 'S_IFREG', 'S_IFIFO', 'S_IFLNK', 'S_IFSOCK']:
450
- if stat['st_ifmt'] == s_mode:
483
+ for s_mode in ["S_IFDIR", "S_IFCHR", "S_IFBLK", "S_IFREG", "S_IFIFO", "S_IFLNK", "S_IFSOCK"]:
484
+ if stat["st_ifmt"] == s_mode:
451
485
  mode = getattr(stat_module, s_mode)
452
486
  return StatResult(
453
- mode, hash(posixpath.normpath(path)), 0, stat['st_nlink'], 0, 0, stat['st_size'],
454
- stat['st_mtime'].timestamp(), stat['st_mtime'].timestamp(), stat['st_birthtime'].timestamp(),
455
- stat['st_blocks'], 4096, stat['st_birthtime'].timestamp(),
487
+ mode,
488
+ hash(posixpath.normpath(path)),
489
+ 0,
490
+ stat["st_nlink"],
491
+ 0,
492
+ 0,
493
+ stat["st_size"],
494
+ stat["st_mtime"].timestamp(),
495
+ stat["st_mtime"].timestamp(),
496
+ stat["st_birthtime"].timestamp(),
497
+ stat["st_blocks"],
498
+ 4096,
499
+ stat["st_birthtime"].timestamp(),
456
500
  )
457
501
 
458
502
  @path_to_str()
459
503
  def link(self, target: str, source: str, type_=afc_link_type_t.SYMLINK):
460
- return self._do_operation(afc_opcode_t.MAKE_LINK,
461
- afc_make_link_req_t.build({'type': type_, 'target': target, 'source': source}))
504
+ return self._do_operation(
505
+ afc_opcode_t.MAKE_LINK, afc_make_link_req_t.build({"type": type_, "target": target, "source": source})
506
+ )
462
507
 
463
508
  @path_to_str()
464
- def fopen(self, filename: str, mode: str = 'r') -> int:
509
+ def fopen(self, filename: str, mode: str = "r") -> int:
465
510
  if mode not in AFC_FOPEN_TEXTUAL_MODES:
466
- raise ArgumentError(f'mode can be only one of: {AFC_FOPEN_TEXTUAL_MODES.keys()}')
511
+ raise ArgumentError(f"mode can be only one of: {AFC_FOPEN_TEXTUAL_MODES.keys()}")
467
512
 
468
- data = self._do_operation(afc_opcode_t.FILE_OPEN,
469
- afc_fopen_req_t.build({'mode': AFC_FOPEN_TEXTUAL_MODES[mode], 'filename': filename}))
513
+ data = self._do_operation(
514
+ afc_opcode_t.FILE_OPEN, afc_fopen_req_t.build({"mode": AFC_FOPEN_TEXTUAL_MODES[mode], "filename": filename})
515
+ )
470
516
  return afc_fopen_resp_t.parse(data).handle
471
517
 
472
518
  def fclose(self, handle: int):
473
- return self._do_operation(afc_opcode_t.FILE_CLOSE, afc_fclose_req_t.build({'handle': handle}))
519
+ return self._do_operation(afc_opcode_t.FILE_CLOSE, afc_fclose_req_t.build({"handle": handle}))
474
520
 
475
521
  @path_to_str()
476
522
  def rename(self, source: str, target: str):
477
523
  try:
478
- return self._do_operation(afc_opcode_t.RENAME_PATH,
479
- afc_rename_req_t.build({'source': source, 'target': target}))
524
+ return self._do_operation(
525
+ afc_opcode_t.RENAME_PATH, afc_rename_req_t.build({"source": source, "target": target})
526
+ )
480
527
  except AfcException as e:
481
528
  if self.exists(source):
482
529
  raise
483
530
  raise AfcFileNotFoundError(e.args[0], e.status) from e
484
531
 
485
532
  def fread(self, handle: int, sz: bytes) -> bytes:
486
- data = b''
533
+ data = b""
487
534
  while sz > 0:
488
- if sz > MAXIMUM_READ_SIZE:
489
- to_read = MAXIMUM_READ_SIZE
490
- else:
491
- to_read = sz
492
- self._dispatch_packet(afc_opcode_t.READ, afc_fread_req_t.build({'handle': handle, 'size': to_read}))
535
+ to_read = MAXIMUM_READ_SIZE if sz > MAXIMUM_READ_SIZE else sz
536
+ self._dispatch_packet(afc_opcode_t.READ, afc_fread_req_t.build({"handle": handle, "size": to_read}))
493
537
  status, chunk = self._receive_data()
494
538
  if status != afc_error_t.SUCCESS:
495
- raise AfcException('fread error', status)
539
+ raise AfcException("fread error", status)
496
540
  sz -= to_read
497
541
  data += chunk
498
542
  return data
499
543
 
500
544
  def fwrite(self, handle, data, chunk_size=MAXIMUM_WRITE_SIZE):
501
- file_handle = struct.pack('<Q', handle)
545
+ file_handle = struct.pack("<Q", handle)
502
546
  chunks_count = len(data) // chunk_size
503
- b = b''
547
+ b = b""
504
548
  for i in range(chunks_count):
505
- chunk = data[i * chunk_size:(i + 1) * chunk_size]
506
- self._dispatch_packet(afc_opcode_t.WRITE,
507
- file_handle + chunk,
508
- this_length=48)
549
+ chunk = data[i * chunk_size : (i + 1) * chunk_size]
550
+ self._dispatch_packet(afc_opcode_t.WRITE, file_handle + chunk, this_length=48)
509
551
  b += chunk
510
552
 
511
- status, response = self._receive_data()
553
+ status, _response = self._receive_data()
512
554
  if status != afc_error_t.SUCCESS:
513
- raise AfcException(f'failed to write chunk: {status}', status)
555
+ raise AfcException(f"failed to write chunk: {status}", status)
514
556
 
515
557
  if len(data) % chunk_size:
516
- chunk = data[chunks_count * chunk_size:]
517
- self._dispatch_packet(afc_opcode_t.WRITE,
518
- file_handle + chunk,
519
- this_length=48)
558
+ chunk = data[chunks_count * chunk_size :]
559
+ self._dispatch_packet(afc_opcode_t.WRITE, file_handle + chunk, this_length=48)
520
560
 
521
561
  b += chunk
522
562
 
523
- status, response = self._receive_data()
563
+ status, _response = self._receive_data()
524
564
  if status != afc_error_t.SUCCESS:
525
- raise AfcException(f'failed to write last chunk: {status}', status)
565
+ raise AfcException(f"failed to write last chunk: {status}", status)
526
566
 
527
567
  @path_to_str()
528
568
  def resolve_path(self, filename: str):
529
569
  info = self.stat(filename)
530
- if info['st_ifmt'] == 'S_IFLNK':
531
- target = info['LinkTarget']
532
- if not target.startswith('/'):
533
- # relative path
534
- filename = posixpath.join(posixpath.dirname(filename), target)
535
- else:
536
- filename = target
570
+ if info["st_ifmt"] == "S_IFLNK":
571
+ target = info["LinkTarget"]
572
+ filename = posixpath.join(posixpath.dirname(filename), target) if not target.startswith("/") else target
537
573
  return filename
538
574
 
539
575
  @path_to_str()
@@ -541,19 +577,19 @@ class AfcService(LockdownService):
541
577
  filename = self.resolve_path(filename)
542
578
  info = self.stat(filename)
543
579
 
544
- if info['st_ifmt'] != 'S_IFREG':
545
- raise AfcException(f'{filename} isn\'t a file', afc_error_t.INVALID_ARG)
580
+ if info["st_ifmt"] != "S_IFREG":
581
+ raise AfcException(f"{filename} isn't a file", afc_error_t.INVALID_ARG)
546
582
 
547
583
  h = self.fopen(filename)
548
584
  if not h:
549
585
  return
550
- d = self.fread(h, int(info['st_size']))
586
+ d = self.fread(h, int(info["st_size"]))
551
587
  self.fclose(h)
552
588
  return d
553
589
 
554
590
  @path_to_str()
555
591
  def set_file_contents(self, filename: str, data: bytes) -> None:
556
- h = self.fopen(filename, 'w')
592
+ h = self.fopen(filename, "w")
557
593
  self.fwrite(h, data)
558
594
  self.fclose(h)
559
595
 
@@ -562,10 +598,10 @@ class AfcService(LockdownService):
562
598
  dirs = []
563
599
  files = []
564
600
  for fd in self.listdir(dirname):
565
- if fd in ('.', '..', ''):
601
+ if fd in (".", "..", ""):
566
602
  continue
567
603
  infos = self.stat(posixpath.join(dirname, fd))
568
- if infos and infos.get('st_ifmt') == 'S_IFDIR':
604
+ if infos and infos.get("st_ifmt") == "S_IFDIR":
569
605
  dirs.append(fd)
570
606
  else:
571
607
  files.append(fd)
@@ -589,14 +625,16 @@ class AfcService(LockdownService):
589
625
  yield posixpath.join(folder, entry)
590
626
 
591
627
  def lock(self, handle, operation):
592
- return self._do_operation(afc_opcode_t.FILE_LOCK, afc_lock_t.build({'handle': handle, 'op': operation}))
628
+ return self._do_operation(afc_opcode_t.FILE_LOCK, afc_lock_t.build({"handle": handle, "op": operation}))
593
629
 
594
630
  def _dispatch_packet(self, operation, data, this_length=0):
595
- afcpack = Container(magic=AFCMAGIC,
596
- entire_length=afc_header_t.sizeof() + len(data),
597
- this_length=afc_header_t.sizeof() + len(data),
598
- packet_num=self.packet_num,
599
- operation=operation)
631
+ afcpack = Container(
632
+ magic=AFCMAGIC,
633
+ entire_length=afc_header_t.sizeof() + len(data),
634
+ this_length=afc_header_t.sizeof() + len(data),
635
+ packet_num=self.packet_num,
636
+ operation=operation,
637
+ )
600
638
  if this_length:
601
639
  afcpack.this_length = this_length
602
640
  header = afc_header_t.build(afcpack)
@@ -606,21 +644,21 @@ class AfcService(LockdownService):
606
644
  def _receive_data(self):
607
645
  res = self.service.recvall(afc_header_t.sizeof())
608
646
  status = afc_error_t.SUCCESS
609
- data = ''
647
+ data = ""
610
648
  if res:
611
649
  res = afc_header_t.parse(res)
612
- assert res['entire_length'] >= afc_header_t.sizeof()
613
- length = res['entire_length'] - afc_header_t.sizeof()
650
+ assert res["entire_length"] >= afc_header_t.sizeof()
651
+ length = res["entire_length"] - afc_header_t.sizeof()
614
652
  data = self.service.recvall(length)
615
653
  if res.operation == afc_opcode_t.STATUS:
616
654
  if length != 8:
617
- self.logger.error('Status length != 8')
655
+ self.logger.error("Status length != 8")
618
656
  status = afc_error_t.parse(data)
619
657
  elif res.operation != afc_opcode_t.DATA:
620
658
  pass
621
659
  return status, data
622
660
 
623
- def _do_operation(self, opcode, data: bytes = b''):
661
+ def _do_operation(self, opcode, data: bytes = b""):
624
662
  self._dispatch_packet(opcode, data)
625
663
  status, data = self._receive_data()
626
664
 
@@ -629,7 +667,7 @@ class AfcService(LockdownService):
629
667
  if status == afc_error_t.OBJECT_NOT_FOUND:
630
668
  exception = AfcFileNotFoundError
631
669
 
632
- raise exception(f'opcode: {opcode} failed with status: {status}', status)
670
+ raise exception(f"opcode: {opcode} failed with status: {status}", status)
633
671
 
634
672
  return data
635
673
 
@@ -667,24 +705,24 @@ class AfcLsStub(LsStub):
667
705
  return posixpath.basename(path)
668
706
 
669
707
  def getgroup(self, st_gid):
670
- return '-'
708
+ return "-"
671
709
 
672
710
  def getuser(self, st_uid):
673
- return '-'
711
+ return "-"
674
712
 
675
713
  def now(self):
676
714
  return self.afc_shell.lockdown.date
677
715
 
678
- def listdir(self, path='.'):
716
+ def listdir(self, path="."):
679
717
  return self.afc_shell.afc.listdir(path)
680
718
 
681
719
  def system(self):
682
- return 'Darwin'
720
+ return "Darwin"
683
721
 
684
722
  def getenv(self, key, default=None):
685
- return ''
723
+ return ""
686
724
 
687
- def print(self, *objects, sep=' ', end='\n', file=sys.stdout, flush=False):
725
+ def print(self, *objects, sep=" ", end="\n", file=sys.stdout, flush=False):
688
726
  print(objects[0], end=end)
689
727
 
690
728
  def get_tty_width(self):
@@ -692,9 +730,9 @@ class AfcLsStub(LsStub):
692
730
 
693
731
 
694
732
  def path_completer(xsh, action, completer, alias, command) -> list[str]:
695
- shell: AfcShell = XSH.ctx['_shell']
733
+ shell: AfcShell = XSH.ctx["_shell"]
696
734
  pwd = shell.cwd
697
- is_absolute = command.prefix.startswith('/')
735
+ is_absolute = command.prefix.startswith("/")
698
736
  dirpath = posixpath.join(pwd, command.prefix)
699
737
  if not shell.afc.exists(dirpath):
700
738
  dirpath = posixpath.dirname(dirpath)
@@ -706,7 +744,7 @@ def path_completer(xsh, action, completer, alias, command) -> list[str]:
706
744
  completion_option = posixpath.relpath(posixpath.join(dirpath, f), pwd)
707
745
  try:
708
746
  if shell.afc.isdir(posixpath.join(dirpath, f)):
709
- result.append(f'{completion_option}/')
747
+ result.append(f"{completion_option}/")
710
748
  else:
711
749
  result.append(completion_option)
712
750
  except AfcException:
@@ -715,9 +753,9 @@ def path_completer(xsh, action, completer, alias, command) -> list[str]:
715
753
 
716
754
 
717
755
  def dir_completer(xsh, action, completer, alias, command):
718
- shell: AfcShell = XSH.ctx['_shell']
756
+ shell: AfcShell = XSH.ctx["_shell"]
719
757
  pwd = shell.cwd
720
- is_absolute = command.prefix.startswith('/')
758
+ is_absolute = command.prefix.startswith("/")
721
759
  dirpath = posixpath.join(pwd, command.prefix)
722
760
  if not shell.afc.exists(dirpath):
723
761
  dirpath = posixpath.dirname(dirpath)
@@ -729,7 +767,7 @@ def dir_completer(xsh, action, completer, alias, command):
729
767
  completion_option = posixpath.relpath(posixpath.join(dirpath, f), pwd)
730
768
  try:
731
769
  if shell.afc.isdir(posixpath.join(dirpath, f)):
732
- result.append(f'{completion_option}/')
770
+ result.append(f"{completion_option}/")
733
771
  except AfcException:
734
772
  result.append(completion_option)
735
773
  return result
@@ -737,22 +775,27 @@ def dir_completer(xsh, action, completer, alias, command):
737
775
 
738
776
  class AfcShell:
739
777
  @classmethod
740
- def create(cls, service_provider: LockdownServiceProvider, service_name: Optional[str] = None,
741
- service: Optional[LockdownService] = None, auto_cd: Optional[str] = '/'):
778
+ def create(
779
+ cls,
780
+ service_provider: LockdownServiceProvider,
781
+ service_name: Optional[str] = None,
782
+ service: Optional[LockdownService] = None,
783
+ auto_cd: Optional[str] = "/",
784
+ ):
742
785
  warnings.filterwarnings("ignore", category=DeprecationWarning)
743
- args = ['--rc', str(pathlib.Path(__file__).absolute())]
744
- os.environ['XONSH_COLOR_STYLE'] = 'default'
745
- XSH.ctx['_class'] = cls
746
- XSH.ctx['_lockdown'] = service_provider
747
- XSH.ctx['_auto_cd'] = auto_cd
786
+ args = ["--rc", str(pathlib.Path(__file__).absolute())]
787
+ os.environ["XONSH_COLOR_STYLE"] = "default"
788
+ XSH.ctx["_class"] = cls
789
+ XSH.ctx["_lockdown"] = service_provider
790
+ XSH.ctx["_auto_cd"] = auto_cd
748
791
  if service is not None:
749
- XSH.ctx['_service'] = service
792
+ XSH.ctx["_service"] = service
750
793
  else:
751
- XSH.ctx['_service'] = AfcService(service_provider, service_name=service_name)
794
+ XSH.ctx["_service"] = AfcService(service_provider, service_name=service_name)
752
795
 
753
796
  try:
754
- logging.getLogger('parso.python.diff').disabled = True
755
- logging.getLogger('parso.cache').disabled = True
797
+ logging.getLogger("parso.python.diff").disabled = True
798
+ logging.getLogger("parso.cache").disabled = True
756
799
  xonsh_main(args)
757
800
  except SystemExit:
758
801
  pass
@@ -760,18 +803,18 @@ class AfcShell:
760
803
  def __init__(self, lockdown: LockdownServiceProvider, service: AfcService):
761
804
  self.lockdown = lockdown
762
805
  self.afc = service
763
- XSH.ctx['_shell'] = self
764
- self.cwd = XSH.ctx.get('_auto_cd', '/')
806
+ XSH.ctx["_shell"] = self
807
+ self.cwd = XSH.ctx.get("_auto_cd", "/")
765
808
  self._commands = {}
766
809
  self._orig_aliases = {}
767
- self._orig_prompt = XSH.env['PROMPT']
810
+ self._orig_prompt = XSH.env["PROMPT"]
768
811
  self._setup_shell_commands()
769
812
 
770
- print_color('''
813
+ print_color("""
771
814
  {BOLD_WHITE}Welcome to xonsh-afc shell! 👋{RESET}
772
815
  Use {CYAN}show-help{RESET} to view a list of all available special commands.
773
816
  These special commands will replace all already existing commands.
774
- ''')
817
+ """)
775
818
 
776
819
  def _register_arg_parse_alias(self, name: str, handler: Union[Callable, str]):
777
820
  handler = ArgParserAlias(func=handler, has_args=True, prog=name)
@@ -788,38 +831,38 @@ class AfcShell:
788
831
 
789
832
  def _setup_shell_commands(self):
790
833
  # clear all host commands except for some useful ones
791
- XSH.env['PATH'].clear()
834
+ XSH.env["PATH"].clear()
792
835
  # adding "file" just to fix xonsh errors
793
- for cmd in ['wc', 'grep', 'egrep', 'sed', 'awk', 'print', 'yes', 'cat']:
836
+ for cmd in ["wc", "grep", "egrep", "sed", "awk", "print", "yes", "cat"]:
794
837
  executable = shutil.which(cmd)
795
838
  if executable is not None:
796
839
  self._register_rpc_command(cmd, executable)
797
840
 
798
- self._register_rpc_command('ls', self.do_ls)
799
- self._register_arg_parse_alias('pwd', self._do_pwd)
800
- self._register_arg_parse_alias('link', self._do_link)
801
- self._register_arg_parse_alias('cd', self._do_cd)
802
- self._register_arg_parse_alias('cat', self._do_cat)
803
- self._register_arg_parse_alias('rm', self._do_rm)
804
- self._register_arg_parse_alias('pull', self._do_pull)
805
- self._register_arg_parse_alias('push', self._do_push)
806
- self._register_arg_parse_alias('walk', self._do_walk)
807
- self._register_arg_parse_alias('head', self._do_head)
808
- self._register_arg_parse_alias('hexdump', self._do_hexdump)
809
- self._register_arg_parse_alias('mkdir', self._do_mkdir)
810
- self._register_arg_parse_alias('info', self._do_info)
811
- self._register_arg_parse_alias('mv', self._do_mv)
812
- self._register_arg_parse_alias('stat', self._do_stat)
813
- self._register_arg_parse_alias('show-help', self._do_show_help)
814
-
815
- XSH.env['PROMPT'] = f'[{{BOLD_CYAN}}{self.afc.service_name}:{{afc_cwd}}{{RESET}}]{{prompt_end}} '
816
- XSH.env['PROMPT_FIELDS']['afc_cwd'] = self._afc_cwd
817
- XSH.env['PROMPT_FIELDS']['prompt_end'] = self._prompt
841
+ self._register_rpc_command("ls", self.do_ls)
842
+ self._register_arg_parse_alias("pwd", self._do_pwd)
843
+ self._register_arg_parse_alias("link", self._do_link)
844
+ self._register_arg_parse_alias("cd", self._do_cd)
845
+ self._register_arg_parse_alias("cat", self._do_cat)
846
+ self._register_arg_parse_alias("rm", self._do_rm)
847
+ self._register_arg_parse_alias("pull", self._do_pull)
848
+ self._register_arg_parse_alias("push", self._do_push)
849
+ self._register_arg_parse_alias("walk", self._do_walk)
850
+ self._register_arg_parse_alias("head", self._do_head)
851
+ self._register_arg_parse_alias("hexdump", self._do_hexdump)
852
+ self._register_arg_parse_alias("mkdir", self._do_mkdir)
853
+ self._register_arg_parse_alias("info", self._do_info)
854
+ self._register_arg_parse_alias("mv", self._do_mv)
855
+ self._register_arg_parse_alias("stat", self._do_stat)
856
+ self._register_arg_parse_alias("show-help", self._do_show_help)
857
+
858
+ XSH.env["PROMPT"] = f"[{{BOLD_CYAN}}{self.afc.service_name}:{{afc_cwd}}{{RESET}}]{{prompt_end}} "
859
+ XSH.env["PROMPT_FIELDS"]["afc_cwd"] = self._afc_cwd
860
+ XSH.env["PROMPT_FIELDS"]["prompt_end"] = self._prompt
818
861
 
819
862
  def _prompt(self) -> str:
820
863
  if len(XSH.history) == 0 or XSH.history[-1].rtn == 0:
821
- return '{BOLD_GREEN}${RESET}'
822
- return '{BOLD_RED}${RESET}'
864
+ return "{BOLD_GREEN}${RESET}"
865
+ return "{BOLD_RED}${RESET}"
823
866
 
824
867
  def _afc_cwd(self) -> str:
825
868
  return self.cwd
@@ -831,9 +874,9 @@ class AfcShell:
831
874
  """
832
875
  list all rpc commands
833
876
  """
834
- buf = ''
835
- for k, v in self._commands.items():
836
- buf += f'👾 {k}\n'
877
+ buf = ""
878
+ for k, _v in self._commands.items():
879
+ buf += f"👾 {k}\n"
837
880
  print(buf)
838
881
 
839
882
  def _do_pwd(self) -> None:
@@ -849,13 +892,13 @@ class AfcShell:
849
892
  self.cwd = directory
850
893
  self._update_prompt()
851
894
  else:
852
- print(f'[ERROR] {directory} does not exist')
895
+ print(f"[ERROR] {directory} does not exist")
853
896
 
854
897
  def do_ls(self, args, stdin, stdout, stderr):
855
- """ list files """
898
+ """list files"""
856
899
  try:
857
- with ls_cli.make_context('ls', args) as ctx:
858
- files = list(map(self._relative_path, ctx.params.pop('files')))
900
+ with ls_cli.make_context("ls", args) as ctx:
901
+ files = list(map(self._relative_path, ctx.params.pop("files")))
859
902
  files = files if files else [self.cwd]
860
903
  Ls(AfcLsStub(self, stdout))(*files, **ctx.params)
861
904
  except Exit:
@@ -871,12 +914,17 @@ class AfcShell:
871
914
  def _do_cat(self, filename: str):
872
915
  print(try_decode(self.afc.get_file_contents(self.relative_path(filename))))
873
916
 
874
- def _do_rm(self, file: Annotated[list[str], Arg(nargs='+', completer=path_completer)]):
917
+ def _do_rm(self, file: Annotated[list[str], Arg(nargs="+", completer=path_completer)]):
875
918
  for filename in file:
876
919
  self.afc.rm(self.relative_path(filename))
877
920
 
878
- def _do_pull(self, remote_path: Annotated[str, Arg(completer=path_completer)], local_path: str,
879
- ignore_errors: bool = False, progress_bar: bool = False) -> None:
921
+ def _do_pull(
922
+ self,
923
+ remote_path: Annotated[str, Arg(completer=path_completer)],
924
+ local_path: str,
925
+ ignore_errors: bool = False,
926
+ progress_bar: bool = False,
927
+ ) -> None:
880
928
  """
881
929
  Pull a file or directory from device to local machine.
882
930
 
@@ -889,14 +937,20 @@ class AfcShell:
889
937
  """
890
938
 
891
939
  def log(src, dst):
892
- print(f'{src} --> {dst}')
893
-
894
- self.afc.pull(remote_path, local_path, callback=log, src_dir=self.cwd, ignore_errors=ignore_errors,
895
- progress_bar=progress_bar)
940
+ print(f"{src} --> {dst}")
941
+
942
+ self.afc.pull(
943
+ remote_path,
944
+ local_path,
945
+ callback=log,
946
+ src_dir=self.cwd,
947
+ ignore_errors=ignore_errors,
948
+ progress_bar=progress_bar,
949
+ )
896
950
 
897
951
  def _do_push(self, local_path: str, remote_path: Annotated[str, Arg(completer=path_completer)]):
898
952
  def log(src, dst):
899
- print(f'{src} --> {dst}')
953
+ print(f"{src} --> {dst}")
900
954
 
901
955
  self.afc.push(local_path, self.relative_path(remote_path), callback=log)
902
956
 
@@ -904,36 +958,41 @@ class AfcShell:
904
958
  print(try_decode(self.afc.get_file_contents(self.relative_path(filename))[:32]))
905
959
 
906
960
  def _do_hexdump(self, filename: Annotated[str, Arg(completer=path_completer)]):
907
- print(hexdump.hexdump(self.afc.get_file_contents(self.relative_path(filename)), result='return'))
961
+ print(hexdump.hexdump(self.afc.get_file_contents(self.relative_path(filename)), result="return"))
908
962
 
909
963
  def _do_mkdir(self, filename: Annotated[str, Arg(completer=path_completer)]):
910
964
  self.afc.makedirs(self.relative_path(filename))
911
965
 
912
966
  def _do_info(self):
913
967
  for k, v in self.afc.get_device_info().items():
914
- print(f'{k}: {v}')
968
+ print(f"{k}: {v}")
915
969
 
916
- def _do_mv(self, source: Annotated[str, Arg(completer=path_completer)],
917
- dest: Annotated[str, Arg(completer=path_completer)]):
970
+ def _do_mv(
971
+ self, source: Annotated[str, Arg(completer=path_completer)], dest: Annotated[str, Arg(completer=path_completer)]
972
+ ):
918
973
  return self.afc.rename(self.relative_path(source), self.relative_path(dest))
919
974
 
920
975
  def _do_stat(self, filename: Annotated[str, Arg(completer=path_completer)]):
921
976
  for k, v in self.afc.stat(self.relative_path(filename)).items():
922
- print(f'{k}: {v}')
977
+ print(f"{k}: {v}")
923
978
 
924
979
  def relative_path(self, filename: str) -> str:
925
980
  return posixpath.join(self.cwd, filename)
926
981
 
927
982
  def _update_prompt(self) -> None:
928
- self.prompt = highlight(f'[{self.afc.service_name}:{self.cwd}]$ ', lexers.BashSessionLexer(),
929
- formatters.Terminal256Formatter(style='solarized-dark')).strip()
983
+ self.prompt = highlight(
984
+ f"[{self.afc.service_name}:{self.cwd}]$ ",
985
+ lexers.BashSessionLexer(),
986
+ formatters.Terminal256Formatter(style="solarized-dark"),
987
+ ).strip()
930
988
 
931
989
  def _complete(self, text, line, begidx, endidx):
932
990
  curdir_diff = posixpath.dirname(text)
933
991
  dirname = posixpath.join(self.cwd, curdir_diff)
934
992
  prefix = posixpath.basename(text)
935
993
  return [
936
- str(posixpath.join(curdir_diff, filename)) for filename in self.afc.listdir(dirname)
994
+ str(posixpath.join(curdir_diff, filename))
995
+ for filename in self.afc.listdir(dirname)
937
996
  if filename.startswith(prefix)
938
997
  ]
939
998
 
@@ -973,9 +1032,9 @@ class AfcShell:
973
1032
 
974
1033
 
975
1034
  if __name__ == str(pathlib.Path(__file__).absolute()):
976
- rc = XSH.ctx['_class'](XSH.ctx['_lockdown'], XSH.ctx['_service'])
1035
+ rc = XSH.ctx["_class"](XSH.ctx["_lockdown"], XSH.ctx["_service"])
977
1036
  # fix fzf conflicts
978
- XSH.env['fzf_history_binding'] = "" # Ctrl+R
979
- XSH.env['fzf_ssh_binding'] = "" # Ctrl+S
980
- XSH.env['fzf_file_binding'] = "" # Ctrl+T
981
- XSH.env['fzf_dir_binding'] = "" # Ctrl+G
1037
+ XSH.env["fzf_history_binding"] = "" # Ctrl+R
1038
+ XSH.env["fzf_ssh_binding"] = "" # Ctrl+S
1039
+ XSH.env["fzf_file_binding"] = "" # Ctrl+T
1040
+ XSH.env["fzf_dir_binding"] = "" # Ctrl+G