mpytool 2.3.0__tar.gz → 2.3.2__tar.gz

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 (36) hide show
  1. {mpytool-2.3.0 → mpytool-2.3.2}/PKG-INFO +142 -34
  2. {mpytool-2.3.0 → mpytool-2.3.2}/README.md +141 -33
  3. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool/cmd_cp.py +1 -4
  4. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool/conn_serial.py +49 -27
  5. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool/logger.py +16 -2
  6. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool/mount.py +126 -32
  7. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool/mpytool.py +83 -44
  8. mpytool-2.3.2/mpytool/utils.py +136 -0
  9. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool.egg-info/PKG-INFO +142 -34
  10. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool.egg-info/SOURCES.txt +1 -0
  11. {mpytool-2.3.0 → mpytool-2.3.2}/pyproject.toml +1 -1
  12. mpytool-2.3.2/tests/test_cli.py +634 -0
  13. {mpytool-2.3.0 → mpytool-2.3.2}/tests/test_integration.py +58 -32
  14. {mpytool-2.3.0 → mpytool-2.3.2}/tests/test_mpytool.py +2 -0
  15. {mpytool-2.3.0 → mpytool-2.3.2}/tests/test_utils.py +81 -36
  16. mpytool-2.3.0/mpytool/utils.py +0 -100
  17. {mpytool-2.3.0 → mpytool-2.3.2}/LICENSE +0 -0
  18. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool/__init__.py +0 -0
  19. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool/conn.py +0 -0
  20. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool/conn_socket.py +0 -0
  21. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool/mpy.py +0 -0
  22. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool/mpy_comm.py +0 -0
  23. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool/mpy_cross.py +0 -0
  24. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool/speedtest.py +0 -0
  25. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool/terminal.py +0 -0
  26. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool/terminal_unix.py +0 -0
  27. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool/terminal_win.py +0 -0
  28. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool.egg-info/dependency_links.txt +0 -0
  29. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool.egg-info/entry_points.txt +0 -0
  30. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool.egg-info/requires.txt +0 -0
  31. {mpytool-2.3.0 → mpytool-2.3.2}/mpytool.egg-info/top_level.txt +0 -0
  32. {mpytool-2.3.0 → mpytool-2.3.2}/setup.cfg +0 -0
  33. {mpytool-2.3.0 → mpytool-2.3.2}/tests/test_cmd_cp.py +0 -0
  34. {mpytool-2.3.0 → mpytool-2.3.2}/tests/test_errors.py +0 -0
  35. {mpytool-2.3.0 → mpytool-2.3.2}/tests/test_mount.py +0 -0
  36. {mpytool-2.3.0 → mpytool-2.3.2}/tests/test_mpy.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mpytool
3
- Version: 2.3.0
3
+ Version: 2.3.2
4
4
  Summary: MPY tool - manage files on devices running MicroPython
5
5
  Author-email: Pavel Revak <pavel.revak@gmail.com>
6
6
  License-Expression: MIT
@@ -42,6 +42,7 @@ It is an alternative to the official [mpremote](https://docs.micropython.org/en/
42
42
  RAM usage (API)
43
43
  - **Shell completion** - ZSH and Bash with remote path completion
44
44
  - **Network support** - connect over TCP
45
+ - **Full Unicode support** - handles Unicode in file names and content
45
46
 
46
47
  See [README_mpremote.md](README_mpremote.md) for detailed comparison with mpremote.
47
48
 
@@ -97,13 +98,34 @@ $ mpytool --help
97
98
 
98
99
  ### List files
99
100
  ```
100
- $ mpytool -p /dev/ttyACM0 ls # list CWD (default)
101
- $ mpytool -p /dev/ttyACM0 ls :/lib # list /lib
101
+ $ mpytool -p /dev/ttyACM0 ls # Linux: list CWD (default)
102
+ LS: /
103
+ 215B boot.py
104
+ 3.03K main.py
105
+ lib/
106
+
107
+ $ mpytool ls :/lib # list /lib (auto-detect port)
108
+ LS: /lib
109
+ uhttp/
110
+ 23.1K wlan.py
111
+
112
+ $ mpytool ls :/data # Unicode file names supported
113
+ LS: /data
114
+ 64B データ.csv
115
+ 32B 🍅.py
116
+ 128B súbor.txt
117
+ 256B 配置.json
102
118
  ```
103
119
 
104
120
  ### Tree
105
121
  ```
106
- $ mpytool -p /dev/ttyACM0 tree # tree of CWD (default)
122
+ $ mpytool -p /dev/cu.usbmodem1101 tree # macOS: tree of CWD
123
+ TREE: /
124
+ 142K ./
125
+ 97.7K ├─ lib/
126
+ 69.6K │ └─ uhttp/
127
+ 23 ├─ boot.py
128
+ 3.03K └─ main.py
107
129
  ```
108
130
 
109
131
  ### Copy files (: prefix = device path)
@@ -153,40 +175,70 @@ $ mpytool mv :/a.py :/b.py :/lib/ # move multiple files to directory
153
175
  ### View file contents
154
176
  ```
155
177
  $ mpytool cat :boot.py # print file from CWD
178
+ CAT: /boot.py
179
+ import machine
180
+ ...
181
+
156
182
  $ mpytool cat :/lib/module.py # print file with absolute path
183
+ CAT: /lib/module.py
184
+ def hello():
185
+ print("Hello!")
157
186
  ```
158
187
 
159
188
  ### Make directory, delete files (: prefix = device path)
160
189
  ```
161
190
  $ mpytool mkdir :lib :data # create directories in CWD
191
+ MKDIR: /lib
192
+ MKDIR: /data
193
+
162
194
  $ mpytool mkdir :/lib/subdir # create with absolute path
195
+ MKDIR: /lib/subdir
196
+
163
197
  $ mpytool rm :old.py # delete file in CWD
198
+ RM: /old.py
199
+
164
200
  $ mpytool rm :mydir # delete directory and contents
201
+ RM: /mydir
202
+
165
203
  $ mpytool rm :mydir/ # delete contents only, keep directory
166
- $ mpytool rm : # delete everything in CWD
167
- $ mpytool rm :/ # delete everything on device (root)
204
+ RM contents: /mydir
168
205
  ```
169
206
 
170
207
  ### Current working directory
171
208
  ```
172
209
  $ mpytool pwd # print current directory
210
+ PWD
173
211
  /
212
+
174
213
  $ mpytool cd :/lib # change to /lib
214
+ CD: /lib
215
+
175
216
  $ mpytool cd :subdir # change to relative path (from CWD)
176
- $ mpytool cd :.. # change to parent directory
217
+ CD: /lib/subdir
218
+
177
219
  $ mpytool cd :/lib -- ls # change directory and list files
220
+ CD: /lib
221
+ LS: /lib
222
+ uhttp/
223
+ 23.1K wlan.py
178
224
  ```
179
225
 
180
226
  ### Module search path (sys.path)
181
227
  ```
182
228
  $ mpytool path # show current sys.path
183
- '', '/lib'
229
+ : :/lib
230
+
184
231
  $ mpytool path : :/lib # replace entire sys.path
232
+ PATH set to 2 entries
233
+
185
234
  $ mpytool path -f :/custom # prepend to sys.path (remove duplicates)
235
+ PATH prepended 1 entries
236
+
186
237
  $ mpytool path -a :/sdcard/lib # append to sys.path (remove duplicates)
238
+ PATH appended 1 entries
239
+
187
240
  $ mpytool path -d :/custom # delete from sys.path
188
- $ mpytool path -f : :/lib :/extra # prepend multiple paths
189
- $ mpytool cd :/app -- path -f : # combine with cd to set working dir
241
+ PATH removed 1 entries
190
242
  ```
191
243
 
192
244
  Path semantics: `:` = empty string (CWD) in sys.path, `:/` = root directory. The `-f` and `-a` flags automatically remove duplicates (move existing paths to new position).
@@ -194,17 +246,23 @@ Path semantics: `:` = empty string (CWD) in sys.path, `:/` = root directory. The
194
246
  ### Stop, reset and REPL
195
247
  ```
196
248
  $ mpytool stop # stop running program (Ctrl-C)
197
- $ mpytool stop -- repl # stop and enter REPL
249
+ STOP
250
+
198
251
  $ mpytool reset # soft reset (Ctrl-D, runs boot.py/main.py)
199
- $ mpytool reset --raw # soft reset in raw REPL (clears RAM only)
252
+ RESET soft
253
+
200
254
  $ mpytool reset --machine # MCU reset (machine.reset, auto-reconnect)
201
- $ mpytool reset --machine -t 30 # MCU reset with 30s reconnect timeout
202
- $ mpytool reset --rts # hardware reset via RTS signal (serial only)
203
- $ mpytool reset --boot # enter bootloader (machine.bootloader)
204
- $ mpytool reset --dtr-boot # enter bootloader via DTR/RTS (ESP32 only)
255
+ RESET machine
256
+
205
257
  $ mpytool reset -- monitor # reset and monitor output
258
+ RESET soft
259
+ MONITOR (Ctrl+C to stop)
260
+
206
261
  $ mpytool repl # enter REPL mode
262
+ REPL (Ctrl+] to exit)
263
+
207
264
  $ mpytool sleep 2 # sleep for 2 seconds (useful between commands)
265
+ SLEEP 2.0s
208
266
  ```
209
267
 
210
268
  ### Serial terminal and monitor (general purpose)
@@ -227,21 +285,35 @@ Both `repl` and `monitor` can be used as general-purpose serial tools - not just
227
285
  ### Execute Python code on device
228
286
  ```
229
287
  $ mpytool exec "print('Hello!')"
288
+ EXEC: print('Hello!')
289
+ Hello!
290
+
230
291
  $ mpytool exec "import sys; print(sys.version)"
292
+ EXEC: import sys; print(sys.version)
293
+ 3.4.0; MicroPython v1.24.0
231
294
  ```
232
295
 
233
296
  ### Run local Python file on device
234
297
  ```
235
298
  $ mpytool run script.py # run script (fire-and-forget)
299
+ RUN: script.py (128 bytes)
300
+
236
301
  $ mpytool run script.py -- monitor # run script and capture output
302
+ RUN: script.py (128 bytes)
303
+ MONITOR (Ctrl+C to stop)
304
+ Hello from script!
237
305
  ```
238
306
 
239
307
  ### Edit file on device
240
308
  ```
241
309
  $ mpytool edit :boot.py # edit file (uses $VISUAL or $EDITOR)
310
+ EDIT: /boot.py
311
+
242
312
  $ mpytool edit :/lib/config.py # absolute path
243
- $ mpytool edit --editor vim :main.py # explicit editor
313
+ EDIT: /lib/config.py
314
+
244
315
  $ mpytool edit :newfile.py # create new file if doesn't exist
316
+ EDIT: /newfile.py (new file)
245
317
  ```
246
318
 
247
319
  Downloads file to a temp file, opens in editor, uploads back if changed.
@@ -250,6 +322,7 @@ Editor priority: `--editor` > `$VISUAL` > `$EDITOR` > error.
250
322
  ### Device RTC (real-time clock)
251
323
  ```
252
324
  $ mpytool rtc # display current RTC
325
+ RTC
253
326
  2026-02-21 15:30:45
254
327
 
255
328
  $ mpytool rtc --set # set RTC to local PC time
@@ -366,7 +439,8 @@ SPEEDTEST
366
439
 
367
440
  ### Show device information
368
441
  ```
369
- $ mpytool info
442
+ $ mpytool -p COM3 info # Windows
443
+ INFO
370
444
  Platform: rp2
371
445
  Version: 3.4.0; MicroPython v1.27.0 on 2025-12-09
372
446
  Impl: micropython
@@ -423,28 +497,30 @@ $ mpytool rm :old.py -- cp new.py : -- reset
423
497
 
424
498
  ### Auto-detect serial port (if only one device is connected)
425
499
  ```
426
- $ mpytool ls lib/
500
+ $ mpytool ls :/lib
501
+ LS: /lib
427
502
  uhttp/
428
- 23.2 KB wlan.py
429
- 4.95 KB wlan_http.py
503
+ 23.1K wlan.py
504
+ 4.95K wlan_http.py
430
505
  ```
431
506
 
432
507
  ### Tree view
433
508
  ```
434
509
  $ mpytool tree
435
- 142 KB ./
436
- 41.3 KB ├─ html/
437
- 587 B │ ├─ index.html
438
- 40.8 KB └─ wlan.html
439
- 97.7 KB ├─ lib/
440
- 69.6 KB │ ├─ uhttp/
441
- 93 B ├─ __init__.py
442
- 26.3 KB │ │ ├─ client.py
443
- 43.2 KB │ │ └─ server.py
444
- 23.2 KB ├─ wlan.py
445
- 4.95 KB └─ wlan_http.py
446
- 23 B ├─ boot.py
447
- 3.03 KB └─ main.py
510
+ TREE: /
511
+ 142K ./
512
+ 41.3K ├─ html/
513
+ 587├─ index.html
514
+ 40.8K │ └─ wlan.html
515
+ 97.7K ├─ lib/
516
+ 69.6K │ ├─ uhttp/
517
+ 93 │ │ ├─ __init__.py
518
+ 26.3K │ │ ├─ client.py
519
+ 43.2K│ └─ server.py
520
+ 23.1K├─ wlan.py
521
+ 4.95K │ └─ wlan_http.py
522
+ 23 ├─ boot.py
523
+ 3.03K └─ main.py
448
524
  ```
449
525
 
450
526
  ### Connect over network (TCP, default port 23)
@@ -616,6 +692,38 @@ exec bash
616
692
  - Support for `--` command separator
617
693
  - Works with both relative and absolute paths
618
694
 
695
+ ## Development
696
+
697
+ ### Running tests
698
+
699
+ ```bash
700
+ # Unit tests (no device needed)
701
+ python -m unittest discover tests/ -v
702
+
703
+ # Read-only integration tests (safe on production device)
704
+ MPYTOOL_TEST_PORT=/dev/ttyACM0 python -m unittest tests.test_integration -v
705
+
706
+ # All integration tests (dedicated test device)
707
+ MPYTOOL_TEST_PORT_RW=/dev/ttyACM0 python -m unittest tests.test_integration -v
708
+
709
+ # CLI tests (no device needed for basic tests)
710
+ python -m unittest tests.test_cli -v
711
+
712
+ # All CLI tests with device
713
+ MPYTOOL_TEST_PORT_RW=/dev/ttyACM0 python -m unittest tests.test_cli -v
714
+ ```
715
+
716
+ Test categories:
717
+ - **Unit tests** (`test_*.py` except `test_integration.py`, `test_cli.py`) - no device needed
718
+ - **Read-only tests** (`MPYTOOL_TEST_PORT`) - safe on any device, no filesystem changes
719
+ - **All tests** (`MPYTOOL_TEST_PORT_RW`) - includes write and flash operations, use dedicated test device
720
+
721
+ ### Install from source
722
+
723
+ ```bash
724
+ pip install -e .
725
+ ```
726
+
619
727
  ## Requirements
620
728
 
621
729
  Working only with MicroPython boards, not with CircuitPython
@@ -28,6 +28,7 @@ It is an alternative to the official [mpremote](https://docs.micropython.org/en/
28
28
  RAM usage (API)
29
29
  - **Shell completion** - ZSH and Bash with remote path completion
30
30
  - **Network support** - connect over TCP
31
+ - **Full Unicode support** - handles Unicode in file names and content
31
32
 
32
33
  See [README_mpremote.md](README_mpremote.md) for detailed comparison with mpremote.
33
34
 
@@ -83,13 +84,34 @@ $ mpytool --help
83
84
 
84
85
  ### List files
85
86
  ```
86
- $ mpytool -p /dev/ttyACM0 ls # list CWD (default)
87
- $ mpytool -p /dev/ttyACM0 ls :/lib # list /lib
87
+ $ mpytool -p /dev/ttyACM0 ls # Linux: list CWD (default)
88
+ LS: /
89
+ 215B boot.py
90
+ 3.03K main.py
91
+ lib/
92
+
93
+ $ mpytool ls :/lib # list /lib (auto-detect port)
94
+ LS: /lib
95
+ uhttp/
96
+ 23.1K wlan.py
97
+
98
+ $ mpytool ls :/data # Unicode file names supported
99
+ LS: /data
100
+ 64B データ.csv
101
+ 32B 🍅.py
102
+ 128B súbor.txt
103
+ 256B 配置.json
88
104
  ```
89
105
 
90
106
  ### Tree
91
107
  ```
92
- $ mpytool -p /dev/ttyACM0 tree # tree of CWD (default)
108
+ $ mpytool -p /dev/cu.usbmodem1101 tree # macOS: tree of CWD
109
+ TREE: /
110
+ 142K ./
111
+ 97.7K ├─ lib/
112
+ 69.6K │ └─ uhttp/
113
+ 23 ├─ boot.py
114
+ 3.03K └─ main.py
93
115
  ```
94
116
 
95
117
  ### Copy files (: prefix = device path)
@@ -139,40 +161,70 @@ $ mpytool mv :/a.py :/b.py :/lib/ # move multiple files to directory
139
161
  ### View file contents
140
162
  ```
141
163
  $ mpytool cat :boot.py # print file from CWD
164
+ CAT: /boot.py
165
+ import machine
166
+ ...
167
+
142
168
  $ mpytool cat :/lib/module.py # print file with absolute path
169
+ CAT: /lib/module.py
170
+ def hello():
171
+ print("Hello!")
143
172
  ```
144
173
 
145
174
  ### Make directory, delete files (: prefix = device path)
146
175
  ```
147
176
  $ mpytool mkdir :lib :data # create directories in CWD
177
+ MKDIR: /lib
178
+ MKDIR: /data
179
+
148
180
  $ mpytool mkdir :/lib/subdir # create with absolute path
181
+ MKDIR: /lib/subdir
182
+
149
183
  $ mpytool rm :old.py # delete file in CWD
184
+ RM: /old.py
185
+
150
186
  $ mpytool rm :mydir # delete directory and contents
187
+ RM: /mydir
188
+
151
189
  $ mpytool rm :mydir/ # delete contents only, keep directory
152
- $ mpytool rm : # delete everything in CWD
153
- $ mpytool rm :/ # delete everything on device (root)
190
+ RM contents: /mydir
154
191
  ```
155
192
 
156
193
  ### Current working directory
157
194
  ```
158
195
  $ mpytool pwd # print current directory
196
+ PWD
159
197
  /
198
+
160
199
  $ mpytool cd :/lib # change to /lib
200
+ CD: /lib
201
+
161
202
  $ mpytool cd :subdir # change to relative path (from CWD)
162
- $ mpytool cd :.. # change to parent directory
203
+ CD: /lib/subdir
204
+
163
205
  $ mpytool cd :/lib -- ls # change directory and list files
206
+ CD: /lib
207
+ LS: /lib
208
+ uhttp/
209
+ 23.1K wlan.py
164
210
  ```
165
211
 
166
212
  ### Module search path (sys.path)
167
213
  ```
168
214
  $ mpytool path # show current sys.path
169
- '', '/lib'
215
+ : :/lib
216
+
170
217
  $ mpytool path : :/lib # replace entire sys.path
218
+ PATH set to 2 entries
219
+
171
220
  $ mpytool path -f :/custom # prepend to sys.path (remove duplicates)
221
+ PATH prepended 1 entries
222
+
172
223
  $ mpytool path -a :/sdcard/lib # append to sys.path (remove duplicates)
224
+ PATH appended 1 entries
225
+
173
226
  $ mpytool path -d :/custom # delete from sys.path
174
- $ mpytool path -f : :/lib :/extra # prepend multiple paths
175
- $ mpytool cd :/app -- path -f : # combine with cd to set working dir
227
+ PATH removed 1 entries
176
228
  ```
177
229
 
178
230
  Path semantics: `:` = empty string (CWD) in sys.path, `:/` = root directory. The `-f` and `-a` flags automatically remove duplicates (move existing paths to new position).
@@ -180,17 +232,23 @@ Path semantics: `:` = empty string (CWD) in sys.path, `:/` = root directory. The
180
232
  ### Stop, reset and REPL
181
233
  ```
182
234
  $ mpytool stop # stop running program (Ctrl-C)
183
- $ mpytool stop -- repl # stop and enter REPL
235
+ STOP
236
+
184
237
  $ mpytool reset # soft reset (Ctrl-D, runs boot.py/main.py)
185
- $ mpytool reset --raw # soft reset in raw REPL (clears RAM only)
238
+ RESET soft
239
+
186
240
  $ mpytool reset --machine # MCU reset (machine.reset, auto-reconnect)
187
- $ mpytool reset --machine -t 30 # MCU reset with 30s reconnect timeout
188
- $ mpytool reset --rts # hardware reset via RTS signal (serial only)
189
- $ mpytool reset --boot # enter bootloader (machine.bootloader)
190
- $ mpytool reset --dtr-boot # enter bootloader via DTR/RTS (ESP32 only)
241
+ RESET machine
242
+
191
243
  $ mpytool reset -- monitor # reset and monitor output
244
+ RESET soft
245
+ MONITOR (Ctrl+C to stop)
246
+
192
247
  $ mpytool repl # enter REPL mode
248
+ REPL (Ctrl+] to exit)
249
+
193
250
  $ mpytool sleep 2 # sleep for 2 seconds (useful between commands)
251
+ SLEEP 2.0s
194
252
  ```
195
253
 
196
254
  ### Serial terminal and monitor (general purpose)
@@ -213,21 +271,35 @@ Both `repl` and `monitor` can be used as general-purpose serial tools - not just
213
271
  ### Execute Python code on device
214
272
  ```
215
273
  $ mpytool exec "print('Hello!')"
274
+ EXEC: print('Hello!')
275
+ Hello!
276
+
216
277
  $ mpytool exec "import sys; print(sys.version)"
278
+ EXEC: import sys; print(sys.version)
279
+ 3.4.0; MicroPython v1.24.0
217
280
  ```
218
281
 
219
282
  ### Run local Python file on device
220
283
  ```
221
284
  $ mpytool run script.py # run script (fire-and-forget)
285
+ RUN: script.py (128 bytes)
286
+
222
287
  $ mpytool run script.py -- monitor # run script and capture output
288
+ RUN: script.py (128 bytes)
289
+ MONITOR (Ctrl+C to stop)
290
+ Hello from script!
223
291
  ```
224
292
 
225
293
  ### Edit file on device
226
294
  ```
227
295
  $ mpytool edit :boot.py # edit file (uses $VISUAL or $EDITOR)
296
+ EDIT: /boot.py
297
+
228
298
  $ mpytool edit :/lib/config.py # absolute path
229
- $ mpytool edit --editor vim :main.py # explicit editor
299
+ EDIT: /lib/config.py
300
+
230
301
  $ mpytool edit :newfile.py # create new file if doesn't exist
302
+ EDIT: /newfile.py (new file)
231
303
  ```
232
304
 
233
305
  Downloads file to a temp file, opens in editor, uploads back if changed.
@@ -236,6 +308,7 @@ Editor priority: `--editor` > `$VISUAL` > `$EDITOR` > error.
236
308
  ### Device RTC (real-time clock)
237
309
  ```
238
310
  $ mpytool rtc # display current RTC
311
+ RTC
239
312
  2026-02-21 15:30:45
240
313
 
241
314
  $ mpytool rtc --set # set RTC to local PC time
@@ -352,7 +425,8 @@ SPEEDTEST
352
425
 
353
426
  ### Show device information
354
427
  ```
355
- $ mpytool info
428
+ $ mpytool -p COM3 info # Windows
429
+ INFO
356
430
  Platform: rp2
357
431
  Version: 3.4.0; MicroPython v1.27.0 on 2025-12-09
358
432
  Impl: micropython
@@ -409,28 +483,30 @@ $ mpytool rm :old.py -- cp new.py : -- reset
409
483
 
410
484
  ### Auto-detect serial port (if only one device is connected)
411
485
  ```
412
- $ mpytool ls lib/
486
+ $ mpytool ls :/lib
487
+ LS: /lib
413
488
  uhttp/
414
- 23.2 KB wlan.py
415
- 4.95 KB wlan_http.py
489
+ 23.1K wlan.py
490
+ 4.95K wlan_http.py
416
491
  ```
417
492
 
418
493
  ### Tree view
419
494
  ```
420
495
  $ mpytool tree
421
- 142 KB ./
422
- 41.3 KB ├─ html/
423
- 587 B │ ├─ index.html
424
- 40.8 KB └─ wlan.html
425
- 97.7 KB ├─ lib/
426
- 69.6 KB │ ├─ uhttp/
427
- 93 B ├─ __init__.py
428
- 26.3 KB │ │ ├─ client.py
429
- 43.2 KB │ │ └─ server.py
430
- 23.2 KB ├─ wlan.py
431
- 4.95 KB └─ wlan_http.py
432
- 23 B ├─ boot.py
433
- 3.03 KB └─ main.py
496
+ TREE: /
497
+ 142K ./
498
+ 41.3K ├─ html/
499
+ 587├─ index.html
500
+ 40.8K │ └─ wlan.html
501
+ 97.7K ├─ lib/
502
+ 69.6K │ ├─ uhttp/
503
+ 93 │ │ ├─ __init__.py
504
+ 26.3K │ │ ├─ client.py
505
+ 43.2K│ └─ server.py
506
+ 23.1K├─ wlan.py
507
+ 4.95K │ └─ wlan_http.py
508
+ 23 ├─ boot.py
509
+ 3.03K └─ main.py
434
510
  ```
435
511
 
436
512
  ### Connect over network (TCP, default port 23)
@@ -602,6 +678,38 @@ exec bash
602
678
  - Support for `--` command separator
603
679
  - Works with both relative and absolute paths
604
680
 
681
+ ## Development
682
+
683
+ ### Running tests
684
+
685
+ ```bash
686
+ # Unit tests (no device needed)
687
+ python -m unittest discover tests/ -v
688
+
689
+ # Read-only integration tests (safe on production device)
690
+ MPYTOOL_TEST_PORT=/dev/ttyACM0 python -m unittest tests.test_integration -v
691
+
692
+ # All integration tests (dedicated test device)
693
+ MPYTOOL_TEST_PORT_RW=/dev/ttyACM0 python -m unittest tests.test_integration -v
694
+
695
+ # CLI tests (no device needed for basic tests)
696
+ python -m unittest tests.test_cli -v
697
+
698
+ # All CLI tests with device
699
+ MPYTOOL_TEST_PORT_RW=/dev/ttyACM0 python -m unittest tests.test_cli -v
700
+ ```
701
+
702
+ Test categories:
703
+ - **Unit tests** (`test_*.py` except `test_integration.py`, `test_cli.py`) - no device needed
704
+ - **Read-only tests** (`MPYTOOL_TEST_PORT`) - safe on any device, no filesystem changes
705
+ - **All tests** (`MPYTOOL_TEST_PORT_RW`) - includes write and flash operations, use dedicated test device
706
+
707
+ ### Install from source
708
+
709
+ ```bash
710
+ pip install -e .
711
+ ```
712
+
605
713
  ## Requirements
606
714
 
607
715
  Working only with MicroPython boards, not with CircuitPython
@@ -216,10 +216,7 @@ class CopyCommand:
216
216
  else:
217
217
  self._progress_src = self._format_local_path(src)
218
218
  if is_dst_remote:
219
- if dst.startswith('/'):
220
- self._progress_dst = ':' + dst
221
- else:
222
- self._progress_dst = ':/' + dst
219
+ self._progress_dst = ':' + dst
223
220
  else:
224
221
  self._progress_dst = self._format_local_path(dst)
225
222
  if len(self._progress_dst) > self._progress_max_dst_len: