mposcli 0.4.1__tar.gz → 0.6.0__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.
- {mposcli-0.4.1 → mposcli-0.6.0}/PKG-INFO +44 -11
- {mposcli-0.4.1 → mposcli-0.6.0}/README.md +43 -10
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/__init__.py +1 -1
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/cli_app/build.py +1 -1
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/cli_app/copy_mpos.py +24 -44
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/cli_app/flash.py +15 -7
- mposcli-0.6.0/mposcli/cli_app/shell.py +45 -0
- mposcli-0.6.0/mposcli/tests/test_mpremote_cp_utils.py +74 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/tests/test_readme.py +13 -1
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/tools.py +3 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/user_input.py +5 -4
- mposcli-0.6.0/mposcli/utilities/__init__.py +0 -0
- mposcli-0.6.0/mposcli/utilities/mpremote.py +64 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/.editorconfig +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/.github/workflows/tests.yml +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/.gitignore +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/.idea/.gitignore +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/.pre-commit-config.yaml +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/.pre-commit-hooks.yaml +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/.run/Template Python tests.run.xml +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/.run/Template Python.run.xml +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/.run/Unittests __all__.run.xml +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/.run/cli --help.run.xml +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/.run/dev-cli --help.run.xml +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/.run/dev-cli test.run.xml +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/.venv-app/.gitignore +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/.venv-app/lib/python3.14/site-packages/cli_base/tests/shell_complete_snapshots/.gitignore +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/cli.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/dev-cli.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/dist/.gitignore +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/__main__.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/cli_app/__init__.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/cli_app/run_deskop.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/cli_app/update.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/cli_dev/__init__.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/cli_dev/__main__.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/cli_dev/code_style.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/cli_dev/packaging.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/cli_dev/shell_completion.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/cli_dev/testing.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/cli_dev/update_readme_history.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/constants.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/fs_utils.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/mpos_utils.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/tests/__init__.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/tests/test_doctests.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/tests/test_project_setup.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/mposcli/tests/test_readme_history.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/noxfile.py +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/pyproject.toml +0 -0
- {mposcli-0.4.1 → mposcli-0.6.0}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mposcli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: CLI helper for MicroPythonOS: https://github.com/MicroPythonOS/MicroPythonOS
|
|
5
5
|
Project-URL: Documentation, https://github.com/jedie/mposcli
|
|
6
6
|
Project-URL: Source, https://github.com/jedie/mposcli
|
|
@@ -47,7 +47,8 @@ cd ~/MicroPythonOS
|
|
|
47
47
|
|
|
48
48
|
[comment]: <> (✂✂✂ auto generated main help start ✂✂✂)
|
|
49
49
|
```
|
|
50
|
-
usage: mposcli [-h] {build,cp,cp-app,flash,run-desktop,update,update-
|
|
50
|
+
usage: mposcli [-h] {build,cp,cp-app,flash,run-desktop,shell,update,update-
|
|
51
|
+
submodules,version}
|
|
51
52
|
|
|
52
53
|
|
|
53
54
|
|
|
@@ -61,8 +62,8 @@ usage: mposcli [-h] {build,cp,cp-app,flash,run-desktop,update,update-submodules,
|
|
|
61
62
|
│ • cp Copy/update internal_filesystem/lib/mpos files to the device │
|
|
62
63
|
│ via "mpremote fs cp". Display a file chooser to select which │
|
|
63
64
|
│ files to copy/update. But can also be used to copy/update all │
|
|
64
|
-
│ files. see:
|
|
65
|
-
│
|
|
65
|
+
│ files. see: │
|
|
66
|
+
│ https://docs.micropythonos.com/architecture/filesystem/ │
|
|
66
67
|
│ • cp-app Copy/update internal_filesystem/apps to the device via │
|
|
67
68
|
│ "mpremote fs cp". Display a file chooser to select which app to │
|
|
68
69
|
│ copy/update. But can also be used to copy/update all files. │
|
|
@@ -74,6 +75,9 @@ usage: mposcli [-h] {build,cp,cp-app,flash,run-desktop,update,update-submodules,
|
|
|
74
75
|
│ opythonos.com/os-development/installing-on-esp32/ │
|
|
75
76
|
│ • run-desktop Run MicroPythonOS on desktop. see: https://docs.micropythonos.c │
|
|
76
77
|
│ om/getting-started/running/#running-on-desktop │
|
|
78
|
+
│ • shell Start a REPL shell connected to the device using mpremote. │
|
|
79
|
+
│ Optional reset before starting the REPL. The goal it to try to │
|
|
80
|
+
│ get a REPL in a loop until it works. │
|
|
77
81
|
│ • update Update MicroPythonOS repository. Assume that there is a │
|
|
78
82
|
│ "origin" and/or "upstream" remote configured. Will also ask if │
|
|
79
83
|
│ you want to update the submodules as well, which is │
|
|
@@ -93,13 +97,13 @@ usage: mposcli [-h] {build,cp,cp-app,flash,run-desktop,update,update-submodules,
|
|
|
93
97
|
|
|
94
98
|
[comment]: <> (✂✂✂ auto generated build start ✂✂✂)
|
|
95
99
|
```
|
|
96
|
-
usage: mposcli build [-h] [{esp32,esp32s3,unix,macOS}] [-v]
|
|
100
|
+
usage: mposcli build [-h] [{esp32,esp32s3,unphone,unix,macOS}] [-v]
|
|
97
101
|
|
|
98
102
|
Build MicroPythonOS by calling: ./scripts/build_mpos.sh <target> see:
|
|
99
103
|
https://docs.micropythonos.com/os-development/
|
|
100
104
|
|
|
101
105
|
╭─ positional arguments ───────────────────────────────────────────────────╮
|
|
102
|
-
│ [{esp32,esp32s3,unix,macOS}]
|
|
106
|
+
│ [{esp32,esp32s3,unphone,unix,macOS}] │
|
|
103
107
|
│ Target platform to build for. (default: unix) │
|
|
104
108
|
╰──────────────────────────────────────────────────────────────────────────╯
|
|
105
109
|
╭─ options ────────────────────────────────────────────────────────────────╮
|
|
@@ -119,7 +123,7 @@ usage: mposcli cp [-h] [CP OPTIONS]
|
|
|
119
123
|
|
|
120
124
|
Copy/update internal_filesystem/lib/mpos files to the device via "mpremote fs cp". Display
|
|
121
125
|
a file chooser to select which files to copy/update. But can also be used to copy/update
|
|
122
|
-
all files. see: https://docs.micropythonos.com/
|
|
126
|
+
all files. see: https://docs.micropythonos.com/architecture/filesystem/
|
|
123
127
|
|
|
124
128
|
╭─ positional arguments ─────────────────────────────────────────────────────────────────╮
|
|
125
129
|
│ [{None}|PATH] Optional file or directory path. (default: None) │
|
|
@@ -173,7 +177,9 @@ https://docs.micropythonos.com/os-development/installing-on-esp32/
|
|
|
173
177
|
|
|
174
178
|
╭─ options ──────────────────────────────────────────────────────────────────────────────╮
|
|
175
179
|
│ -h, --help show this help message and exit │
|
|
176
|
-
│ --port STR
|
|
180
|
+
│ --port {None}|STR Port used for esptool and mpremote, e.g.: "/dev/ttyUSB0" or │
|
|
181
|
+
│ "/dev/ttyACM0" etc. Leave empty for autodetection (default: │
|
|
182
|
+
│ None) │
|
|
177
183
|
│ --address STR Address (default: 0x0) │
|
|
178
184
|
│ --flash-size STR Flash Size (default: detect) │
|
|
179
185
|
│ --verify, --no-verify Verify after flashing? (default: True) │
|
|
@@ -213,6 +219,26 @@ started/running/#running-on-desktop
|
|
|
213
219
|
|
|
214
220
|
|
|
215
221
|
|
|
222
|
+
## mposcli shell
|
|
223
|
+
|
|
224
|
+
[comment]: <> (✂✂✂ auto generated shell start ✂✂✂)
|
|
225
|
+
```
|
|
226
|
+
usage: mposcli shell [-h] [--reset | --no-reset] [-v]
|
|
227
|
+
|
|
228
|
+
Start a REPL shell connected to the device using mpremote. Optional reset before starting
|
|
229
|
+
the REPL. The goal it to try to get a REPL in a loop until it works.
|
|
230
|
+
|
|
231
|
+
╭─ options ────────────────────────────────────────────────────────────────────────╮
|
|
232
|
+
│ -h, --help show this help message and exit │
|
|
233
|
+
│ --reset, --no-reset Reset the device before starting the REPL? (default: False) │
|
|
234
|
+
│ -v, --verbosity Verbosity level; e.g.: -v, -vv, -vvv, etc. (repeatable) │
|
|
235
|
+
╰──────────────────────────────────────────────────────────────────────────────────╯
|
|
236
|
+
```
|
|
237
|
+
[comment]: <> (✂✂✂ auto generated shell end ✂✂✂)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
|
|
216
242
|
## mposcli update
|
|
217
243
|
|
|
218
244
|
|
|
@@ -317,6 +343,13 @@ completion,test,update,update-readme-history,update-test-snapshot-files,version}
|
|
|
317
343
|
|
|
318
344
|
[comment]: <> (✂✂✂ auto generated history start ✂✂✂)
|
|
319
345
|
|
|
346
|
+
* [v0.6.0](https://github.com/jedie/mposcli/compare/v0.5.0...v0.6.0)
|
|
347
|
+
* 2026-03-21 - NEW: "shell" to start the REPL
|
|
348
|
+
* [v0.5.0](https://github.com/jedie/mposcli/compare/v0.4.1...v0.5.0)
|
|
349
|
+
* 2026-03-08 - update README
|
|
350
|
+
* 2026-03-05 - Enhance "cp" command and auto restart "mpremote repl"
|
|
351
|
+
* 2026-03-03 - Refactor "cp" command
|
|
352
|
+
* 2026-03-03 - flash command: use port auto detection as default
|
|
320
353
|
* [v0.4.1](https://github.com/jedie/mposcli/compare/v0.4.0...v0.4.1)
|
|
321
354
|
* 2026-02-27 - Use "--force" for pulling submodules to overwrite local changes
|
|
322
355
|
* [v0.4.0](https://github.com/jedie/mposcli/compare/v0.3.0...v0.4.0)
|
|
@@ -325,6 +358,9 @@ completion,test,update,update-readme-history,update-test-snapshot-files,version}
|
|
|
325
358
|
* 2026-02-23 - Update requirements and fix code style
|
|
326
359
|
* 2026-02-23 - "build" command: target as positional argument
|
|
327
360
|
* 2026-02-23 - Expand "cp" command and allow optional filesystem path
|
|
361
|
+
|
|
362
|
+
<details><summary>Expand older history entries ...</summary>
|
|
363
|
+
|
|
328
364
|
* [v0.3.0](https://github.com/jedie/mposcli/compare/v0.2.0...v0.3.0)
|
|
329
365
|
* 2026-02-18 - Add "update" beside "update-submodules"
|
|
330
366
|
* 2026-02-17 - Update requirements
|
|
@@ -333,9 +369,6 @@ completion,test,update,update-readme-history,update-test-snapshot-files,version}
|
|
|
333
369
|
* 2026-02-16 - New CLI command: "cp" with convenience features.
|
|
334
370
|
* 2026-02-16 - New command: "flash" with file selector
|
|
335
371
|
* 2026-02-16 - Update README.md
|
|
336
|
-
|
|
337
|
-
<details><summary>Expand older history entries ...</summary>
|
|
338
|
-
|
|
339
372
|
* [v0.1.0](https://github.com/jedie/mposcli/compare/1695026...v0.1.0)
|
|
340
373
|
* 2026-02-16 - Add "update-submodules" command
|
|
341
374
|
* 2026-02-16 - Add "build" command
|
|
@@ -32,7 +32,8 @@ cd ~/MicroPythonOS
|
|
|
32
32
|
|
|
33
33
|
[comment]: <> (✂✂✂ auto generated main help start ✂✂✂)
|
|
34
34
|
```
|
|
35
|
-
usage: mposcli [-h] {build,cp,cp-app,flash,run-desktop,update,update-
|
|
35
|
+
usage: mposcli [-h] {build,cp,cp-app,flash,run-desktop,shell,update,update-
|
|
36
|
+
submodules,version}
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
|
|
@@ -46,8 +47,8 @@ usage: mposcli [-h] {build,cp,cp-app,flash,run-desktop,update,update-submodules,
|
|
|
46
47
|
│ • cp Copy/update internal_filesystem/lib/mpos files to the device │
|
|
47
48
|
│ via "mpremote fs cp". Display a file chooser to select which │
|
|
48
49
|
│ files to copy/update. But can also be used to copy/update all │
|
|
49
|
-
│ files. see:
|
|
50
|
-
│
|
|
50
|
+
│ files. see: │
|
|
51
|
+
│ https://docs.micropythonos.com/architecture/filesystem/ │
|
|
51
52
|
│ • cp-app Copy/update internal_filesystem/apps to the device via │
|
|
52
53
|
│ "mpremote fs cp". Display a file chooser to select which app to │
|
|
53
54
|
│ copy/update. But can also be used to copy/update all files. │
|
|
@@ -59,6 +60,9 @@ usage: mposcli [-h] {build,cp,cp-app,flash,run-desktop,update,update-submodules,
|
|
|
59
60
|
│ opythonos.com/os-development/installing-on-esp32/ │
|
|
60
61
|
│ • run-desktop Run MicroPythonOS on desktop. see: https://docs.micropythonos.c │
|
|
61
62
|
│ om/getting-started/running/#running-on-desktop │
|
|
63
|
+
│ • shell Start a REPL shell connected to the device using mpremote. │
|
|
64
|
+
│ Optional reset before starting the REPL. The goal it to try to │
|
|
65
|
+
│ get a REPL in a loop until it works. │
|
|
62
66
|
│ • update Update MicroPythonOS repository. Assume that there is a │
|
|
63
67
|
│ "origin" and/or "upstream" remote configured. Will also ask if │
|
|
64
68
|
│ you want to update the submodules as well, which is │
|
|
@@ -78,13 +82,13 @@ usage: mposcli [-h] {build,cp,cp-app,flash,run-desktop,update,update-submodules,
|
|
|
78
82
|
|
|
79
83
|
[comment]: <> (✂✂✂ auto generated build start ✂✂✂)
|
|
80
84
|
```
|
|
81
|
-
usage: mposcli build [-h] [{esp32,esp32s3,unix,macOS}] [-v]
|
|
85
|
+
usage: mposcli build [-h] [{esp32,esp32s3,unphone,unix,macOS}] [-v]
|
|
82
86
|
|
|
83
87
|
Build MicroPythonOS by calling: ./scripts/build_mpos.sh <target> see:
|
|
84
88
|
https://docs.micropythonos.com/os-development/
|
|
85
89
|
|
|
86
90
|
╭─ positional arguments ───────────────────────────────────────────────────╮
|
|
87
|
-
│ [{esp32,esp32s3,unix,macOS}]
|
|
91
|
+
│ [{esp32,esp32s3,unphone,unix,macOS}] │
|
|
88
92
|
│ Target platform to build for. (default: unix) │
|
|
89
93
|
╰──────────────────────────────────────────────────────────────────────────╯
|
|
90
94
|
╭─ options ────────────────────────────────────────────────────────────────╮
|
|
@@ -104,7 +108,7 @@ usage: mposcli cp [-h] [CP OPTIONS]
|
|
|
104
108
|
|
|
105
109
|
Copy/update internal_filesystem/lib/mpos files to the device via "mpremote fs cp". Display
|
|
106
110
|
a file chooser to select which files to copy/update. But can also be used to copy/update
|
|
107
|
-
all files. see: https://docs.micropythonos.com/
|
|
111
|
+
all files. see: https://docs.micropythonos.com/architecture/filesystem/
|
|
108
112
|
|
|
109
113
|
╭─ positional arguments ─────────────────────────────────────────────────────────────────╮
|
|
110
114
|
│ [{None}|PATH] Optional file or directory path. (default: None) │
|
|
@@ -158,7 +162,9 @@ https://docs.micropythonos.com/os-development/installing-on-esp32/
|
|
|
158
162
|
|
|
159
163
|
╭─ options ──────────────────────────────────────────────────────────────────────────────╮
|
|
160
164
|
│ -h, --help show this help message and exit │
|
|
161
|
-
│ --port STR
|
|
165
|
+
│ --port {None}|STR Port used for esptool and mpremote, e.g.: "/dev/ttyUSB0" or │
|
|
166
|
+
│ "/dev/ttyACM0" etc. Leave empty for autodetection (default: │
|
|
167
|
+
│ None) │
|
|
162
168
|
│ --address STR Address (default: 0x0) │
|
|
163
169
|
│ --flash-size STR Flash Size (default: detect) │
|
|
164
170
|
│ --verify, --no-verify Verify after flashing? (default: True) │
|
|
@@ -198,6 +204,26 @@ started/running/#running-on-desktop
|
|
|
198
204
|
|
|
199
205
|
|
|
200
206
|
|
|
207
|
+
## mposcli shell
|
|
208
|
+
|
|
209
|
+
[comment]: <> (✂✂✂ auto generated shell start ✂✂✂)
|
|
210
|
+
```
|
|
211
|
+
usage: mposcli shell [-h] [--reset | --no-reset] [-v]
|
|
212
|
+
|
|
213
|
+
Start a REPL shell connected to the device using mpremote. Optional reset before starting
|
|
214
|
+
the REPL. The goal it to try to get a REPL in a loop until it works.
|
|
215
|
+
|
|
216
|
+
╭─ options ────────────────────────────────────────────────────────────────────────╮
|
|
217
|
+
│ -h, --help show this help message and exit │
|
|
218
|
+
│ --reset, --no-reset Reset the device before starting the REPL? (default: False) │
|
|
219
|
+
│ -v, --verbosity Verbosity level; e.g.: -v, -vv, -vvv, etc. (repeatable) │
|
|
220
|
+
╰──────────────────────────────────────────────────────────────────────────────────╯
|
|
221
|
+
```
|
|
222
|
+
[comment]: <> (✂✂✂ auto generated shell end ✂✂✂)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
|
|
201
227
|
## mposcli update
|
|
202
228
|
|
|
203
229
|
|
|
@@ -302,6 +328,13 @@ completion,test,update,update-readme-history,update-test-snapshot-files,version}
|
|
|
302
328
|
|
|
303
329
|
[comment]: <> (✂✂✂ auto generated history start ✂✂✂)
|
|
304
330
|
|
|
331
|
+
* [v0.6.0](https://github.com/jedie/mposcli/compare/v0.5.0...v0.6.0)
|
|
332
|
+
* 2026-03-21 - NEW: "shell" to start the REPL
|
|
333
|
+
* [v0.5.0](https://github.com/jedie/mposcli/compare/v0.4.1...v0.5.0)
|
|
334
|
+
* 2026-03-08 - update README
|
|
335
|
+
* 2026-03-05 - Enhance "cp" command and auto restart "mpremote repl"
|
|
336
|
+
* 2026-03-03 - Refactor "cp" command
|
|
337
|
+
* 2026-03-03 - flash command: use port auto detection as default
|
|
305
338
|
* [v0.4.1](https://github.com/jedie/mposcli/compare/v0.4.0...v0.4.1)
|
|
306
339
|
* 2026-02-27 - Use "--force" for pulling submodules to overwrite local changes
|
|
307
340
|
* [v0.4.0](https://github.com/jedie/mposcli/compare/v0.3.0...v0.4.0)
|
|
@@ -310,6 +343,9 @@ completion,test,update,update-readme-history,update-test-snapshot-files,version}
|
|
|
310
343
|
* 2026-02-23 - Update requirements and fix code style
|
|
311
344
|
* 2026-02-23 - "build" command: target as positional argument
|
|
312
345
|
* 2026-02-23 - Expand "cp" command and allow optional filesystem path
|
|
346
|
+
|
|
347
|
+
<details><summary>Expand older history entries ...</summary>
|
|
348
|
+
|
|
313
349
|
* [v0.3.0](https://github.com/jedie/mposcli/compare/v0.2.0...v0.3.0)
|
|
314
350
|
* 2026-02-18 - Add "update" beside "update-submodules"
|
|
315
351
|
* 2026-02-17 - Update requirements
|
|
@@ -318,9 +354,6 @@ completion,test,update,update-readme-history,update-test-snapshot-files,version}
|
|
|
318
354
|
* 2026-02-16 - New CLI command: "cp" with convenience features.
|
|
319
355
|
* 2026-02-16 - New command: "flash" with file selector
|
|
320
356
|
* 2026-02-16 - Update README.md
|
|
321
|
-
|
|
322
|
-
<details><summary>Expand older history entries ...</summary>
|
|
323
|
-
|
|
324
357
|
* [v0.1.0](https://github.com/jedie/mposcli/compare/1695026...v0.1.0)
|
|
325
358
|
* 2026-02-16 - Add "update-submodules" command
|
|
326
359
|
* 2026-02-16 - Add "build" command
|
|
@@ -18,7 +18,7 @@ logger = logging.getLogger(__name__)
|
|
|
18
18
|
@app.command
|
|
19
19
|
def build(
|
|
20
20
|
target: Annotated[
|
|
21
|
-
Literal['esp32', 'esp32s3', 'unix', 'macOS'],
|
|
21
|
+
Literal['esp32', 'esp32s3', 'unphone', 'unix', 'macOS'],
|
|
22
22
|
tyro.conf.arg(
|
|
23
23
|
help='Target platform to build for.',
|
|
24
24
|
),
|
|
@@ -14,6 +14,7 @@ from mposcli.cli_app import app
|
|
|
14
14
|
from mposcli.mpos_utils import get_mpos_path
|
|
15
15
|
from mposcli.tools import get_mpremote_bin
|
|
16
16
|
from mposcli.user_input import choose_newest_modified_directory, get_newest_files
|
|
17
|
+
from mposcli.utilities.mpremote import MpOsPathResolver, start_mpremote_repl
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
logger = logging.getLogger(__name__)
|
|
@@ -44,58 +45,45 @@ def cp(
|
|
|
44
45
|
Copy/update internal_filesystem/lib/mpos files to the device via "mpremote fs cp".
|
|
45
46
|
Display a file chooser to select which files to copy/update.
|
|
46
47
|
But can also be used to copy/update all files.
|
|
47
|
-
see: https://docs.micropythonos.com/
|
|
48
|
+
see: https://docs.micropythonos.com/architecture/filesystem/
|
|
48
49
|
"""
|
|
49
50
|
setup_logging(verbosity=verbosity)
|
|
50
51
|
|
|
51
52
|
mpos_path = get_mpos_path()
|
|
52
|
-
|
|
53
|
-
internal_fs = mpos_path / 'internal_filesystem'
|
|
54
|
-
lib_mpos = internal_fs / 'lib' / 'mpos'
|
|
55
|
-
assert_is_dir(lib_mpos)
|
|
56
|
-
apps_path = internal_fs / 'apps'
|
|
57
|
-
assert_is_dir(apps_path)
|
|
53
|
+
resolver = MpOsPathResolver(mpos=mpos_path)
|
|
58
54
|
|
|
59
55
|
mpremote_bin = get_mpremote_bin()
|
|
60
56
|
|
|
61
57
|
print('\n')
|
|
62
58
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if not local_path
|
|
67
|
-
|
|
59
|
+
if not local_path:
|
|
60
|
+
# Let's the user select from the list of the newest modified files in internal_filesystem/lib/mpos:
|
|
61
|
+
local_path = get_newest_files(resolver.lib_mpos, limit=new_file_limit)
|
|
62
|
+
if not local_path:
|
|
63
|
+
print('Copy/update all files in lib/mpos to the device')
|
|
64
|
+
local_path = resolver.lib_mpos
|
|
68
65
|
|
|
69
|
-
|
|
66
|
+
print(f'Copy/update app: "{local_path}" ...')
|
|
70
67
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
if not local_path.exists():
|
|
69
|
+
print(f'[red]Error: The specified source path "{local_path}" does not exist.[/red]')
|
|
70
|
+
return
|
|
74
71
|
|
|
75
|
-
|
|
76
|
-
if local_path.is_relative_to(apps_path):
|
|
77
|
-
local_rel_path = local_path.relative_to(mpos_path)
|
|
78
|
-
remote_path = f':/{local_path.relative_to(internal_fs)}'
|
|
79
|
-
else:
|
|
80
|
-
raise NotImplementedError
|
|
81
|
-
else:
|
|
82
|
-
local_path = get_newest_files(lib_mpos, limit=new_file_limit)
|
|
83
|
-
if not local_path:
|
|
84
|
-
print('Copy/update all files in lib/mpos to the device')
|
|
85
|
-
local_path = lib_mpos
|
|
72
|
+
local_path_str, remote_str = resolver.resolve(local_path)
|
|
86
73
|
|
|
87
|
-
|
|
88
|
-
remote_path = f':/{local_path.relative_to(lib_mpos.parent)}'
|
|
74
|
+
popenargs = (mpremote_bin, 'fs')
|
|
89
75
|
|
|
90
76
|
if local_path.is_dir():
|
|
91
77
|
popenargs += ('-r',)
|
|
92
|
-
print(f'Copying directory "[bold]{
|
|
78
|
+
print(f'Copying directory "[bold]{local_path_str}[/bold]" to device at "[bold]{remote_str}[/bold]" ...')
|
|
93
79
|
else:
|
|
94
|
-
print(f'Copying file "[bold]{
|
|
80
|
+
print(f'Copying file "[bold]{local_path_str}[/bold]" to device at "[bold]{remote_str}[/bold]" ...')
|
|
95
81
|
|
|
96
|
-
popenargs += (local_rel_path, remote_path)
|
|
97
82
|
verbose_check_call(
|
|
98
83
|
*popenargs,
|
|
84
|
+
'cp',
|
|
85
|
+
local_path_str,
|
|
86
|
+
remote_str,
|
|
99
87
|
verbose=True,
|
|
100
88
|
cwd=mpos_path,
|
|
101
89
|
text=None,
|
|
@@ -112,15 +100,7 @@ def cp(
|
|
|
112
100
|
)
|
|
113
101
|
|
|
114
102
|
if repl:
|
|
115
|
-
|
|
116
|
-
verbose_check_call(
|
|
117
|
-
mpremote_bin,
|
|
118
|
-
'repl',
|
|
119
|
-
verbose=True,
|
|
120
|
-
cwd=mpos_path,
|
|
121
|
-
timeout=None,
|
|
122
|
-
text=None,
|
|
123
|
-
)
|
|
103
|
+
start_mpremote_repl()
|
|
124
104
|
|
|
125
105
|
|
|
126
106
|
@app.command
|
|
@@ -158,14 +138,14 @@ def cp_app(
|
|
|
158
138
|
|
|
159
139
|
if not app:
|
|
160
140
|
print('Copy/update all apps in "internal_filesystem/apps" to the device')
|
|
161
|
-
|
|
141
|
+
local_path = 'internal_filesystem/apps'
|
|
162
142
|
remote_path = ':/apps'
|
|
163
143
|
else:
|
|
164
144
|
print(f'Copy/update {app=} ...')
|
|
165
|
-
|
|
145
|
+
local_path = f'internal_filesystem/apps/{app.name}'
|
|
166
146
|
remote_path = f':/apps/{app.name}'
|
|
167
147
|
|
|
168
|
-
popenargs += (
|
|
148
|
+
popenargs += (local_path, remote_path)
|
|
169
149
|
verbose_check_call(
|
|
170
150
|
*popenargs,
|
|
171
151
|
verbose=True,
|
|
@@ -18,7 +18,15 @@ logger = logging.getLogger(__name__)
|
|
|
18
18
|
|
|
19
19
|
@app.command
|
|
20
20
|
def flash(
|
|
21
|
-
port: Annotated[
|
|
21
|
+
port: Annotated[
|
|
22
|
+
str | None,
|
|
23
|
+
tyro.conf.arg(
|
|
24
|
+
help=(
|
|
25
|
+
'Port used for esptool and mpremote, e.g.: "/dev/ttyUSB0" or "/dev/ttyACM0" etc.'
|
|
26
|
+
' Leave empty for autodetection'
|
|
27
|
+
)
|
|
28
|
+
),
|
|
29
|
+
] = None,
|
|
22
30
|
address: Annotated[str, tyro.conf.arg(help='Address')] = '0x0',
|
|
23
31
|
flash_size: Annotated[str, tyro.conf.arg(help='Flash Size')] = 'detect',
|
|
24
32
|
verify: Annotated[bool, tyro.conf.arg(help='Verify after flashing?')] = True,
|
|
@@ -46,10 +54,12 @@ def flash(
|
|
|
46
54
|
image_files = lvgl_micropython_build_path.glob('*.bin')
|
|
47
55
|
image_file = file_chooser(image_files)
|
|
48
56
|
|
|
57
|
+
popenargs = (esptool_bin,)
|
|
58
|
+
if port:
|
|
59
|
+
popenargs += ('--port', port)
|
|
60
|
+
|
|
49
61
|
verbose_check_call(
|
|
50
|
-
|
|
51
|
-
'--port',
|
|
52
|
-
port,
|
|
62
|
+
*popenargs,
|
|
53
63
|
'write-flash',
|
|
54
64
|
'--flash-size',
|
|
55
65
|
flash_size,
|
|
@@ -63,9 +73,7 @@ def flash(
|
|
|
63
73
|
|
|
64
74
|
if verify:
|
|
65
75
|
verbose_check_call(
|
|
66
|
-
|
|
67
|
-
'--port',
|
|
68
|
-
port,
|
|
76
|
+
*popenargs,
|
|
69
77
|
'verify-flash',
|
|
70
78
|
address,
|
|
71
79
|
image_file,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import time
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
|
|
5
|
+
import tyro
|
|
6
|
+
from cli_base.cli_tools.subprocess_utils import verbose_check_call
|
|
7
|
+
from cli_base.cli_tools.verbosity import setup_logging
|
|
8
|
+
from cli_base.tyro_commands import TyroVerbosityArgType
|
|
9
|
+
|
|
10
|
+
from mposcli.cli_app import app
|
|
11
|
+
from mposcli.mpos_utils import get_mpos_path
|
|
12
|
+
from mposcli.tools import get_mpremote_bin
|
|
13
|
+
from mposcli.utilities.mpremote import start_mpremote_repl
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@app.command
|
|
20
|
+
def shell(
|
|
21
|
+
reset: Annotated[
|
|
22
|
+
bool,
|
|
23
|
+
tyro.conf.arg(help='Reset the device before starting the REPL?'),
|
|
24
|
+
] = False,
|
|
25
|
+
verbosity: TyroVerbosityArgType = 1,
|
|
26
|
+
):
|
|
27
|
+
"""
|
|
28
|
+
Start a REPL shell connected to the device using mpremote. Optional reset before starting the REPL.
|
|
29
|
+
The goal it to try to get a REPL in a loop until it works.
|
|
30
|
+
"""
|
|
31
|
+
setup_logging(verbosity=verbosity)
|
|
32
|
+
mpos_path = get_mpos_path()
|
|
33
|
+
mpremote_bin = get_mpremote_bin()
|
|
34
|
+
|
|
35
|
+
if reset:
|
|
36
|
+
time.sleep(1)
|
|
37
|
+
verbose_check_call(
|
|
38
|
+
mpremote_bin,
|
|
39
|
+
'reset',
|
|
40
|
+
verbose=True,
|
|
41
|
+
cwd=mpos_path,
|
|
42
|
+
text=None,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
start_mpremote_repl()
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import tempfile
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from unittest import TestCase
|
|
4
|
+
|
|
5
|
+
from mposcli.utilities.mpremote import MpOsPathResolver
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ProjectSetupTestCase(TestCase):
|
|
9
|
+
def test_mpos_path_resolver(self):
|
|
10
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
11
|
+
mpos_path = Path(temp_dir).resolve()
|
|
12
|
+
|
|
13
|
+
camera_assets = mpos_path / 'internal_filesystem/apps/com.micropythonos.camera/assets/'
|
|
14
|
+
camera_assets.mkdir(parents=True)
|
|
15
|
+
(camera_assets / 'camera_app.py').touch()
|
|
16
|
+
|
|
17
|
+
board_path = mpos_path / 'internal_filesystem/lib/mpos/board/'
|
|
18
|
+
board_path.mkdir(parents=True)
|
|
19
|
+
(board_path / 'unphone.py').touch()
|
|
20
|
+
|
|
21
|
+
(mpos_path / 'internal_filesystem/lib/drivers/display/hx8357d/').mkdir(parents=True)
|
|
22
|
+
|
|
23
|
+
resolver = MpOsPathResolver(mpos=mpos_path)
|
|
24
|
+
self.assertEqual(
|
|
25
|
+
resolver.resolve(mpos_path / 'internal_filesystem/apps/com.micropythonos.camera'),
|
|
26
|
+
(
|
|
27
|
+
'internal_filesystem/apps/com.micropythonos.camera/',
|
|
28
|
+
':apps/',
|
|
29
|
+
),
|
|
30
|
+
)
|
|
31
|
+
self.assertEqual(
|
|
32
|
+
resolver.resolve(mpos_path / 'internal_filesystem/apps/com.micropythonos.camera/assets/'),
|
|
33
|
+
(
|
|
34
|
+
'internal_filesystem/apps/com.micropythonos.camera/assets/',
|
|
35
|
+
':apps/com.micropythonos.camera/',
|
|
36
|
+
),
|
|
37
|
+
)
|
|
38
|
+
self.assertEqual(
|
|
39
|
+
resolver.resolve(mpos_path / 'internal_filesystem/apps/com.micropythonos.camera/assets/camera_app.py'),
|
|
40
|
+
(
|
|
41
|
+
'internal_filesystem/apps/com.micropythonos.camera/assets/camera_app.py',
|
|
42
|
+
':apps/com.micropythonos.camera/assets/camera_app.py',
|
|
43
|
+
),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
self.assertEqual(
|
|
47
|
+
resolver.resolve(mpos_path / 'internal_filesystem/lib/mpos/board/'),
|
|
48
|
+
(
|
|
49
|
+
'internal_filesystem/lib/mpos/board/',
|
|
50
|
+
':mpos/',
|
|
51
|
+
),
|
|
52
|
+
)
|
|
53
|
+
self.assertEqual(
|
|
54
|
+
resolver.resolve(mpos_path / 'internal_filesystem/lib/mpos/board/unphone.py'),
|
|
55
|
+
(
|
|
56
|
+
'internal_filesystem/lib/mpos/board/unphone.py',
|
|
57
|
+
':mpos/board/unphone.py',
|
|
58
|
+
),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
self.assertEqual(
|
|
62
|
+
resolver.resolve(mpos_path / 'internal_filesystem/lib/drivers/display/hx8357d'),
|
|
63
|
+
(
|
|
64
|
+
'internal_filesystem/lib/drivers/display/hx8357d/',
|
|
65
|
+
':lib/drivers/display/',
|
|
66
|
+
),
|
|
67
|
+
)
|
|
68
|
+
self.assertEqual(
|
|
69
|
+
resolver.resolve(mpos_path / 'internal_filesystem/lib/drivers/display'),
|
|
70
|
+
(
|
|
71
|
+
'internal_filesystem/lib/drivers/display/',
|
|
72
|
+
':lib/drivers/',
|
|
73
|
+
),
|
|
74
|
+
)
|
|
@@ -83,7 +83,19 @@ class ReadmeTestCase(BaseTestCase):
|
|
|
83
83
|
|
|
84
84
|
commands.discard('version') # version is pseudo command, because the version always printed on every CLI call
|
|
85
85
|
commands = sorted(commands)
|
|
86
|
-
self.assertEqual(
|
|
86
|
+
self.assertEqual(
|
|
87
|
+
commands,
|
|
88
|
+
[
|
|
89
|
+
'build',
|
|
90
|
+
'cp',
|
|
91
|
+
'cp-app',
|
|
92
|
+
'flash',
|
|
93
|
+
'run-desktop',
|
|
94
|
+
'shell',
|
|
95
|
+
'update',
|
|
96
|
+
'update-submodules',
|
|
97
|
+
],
|
|
98
|
+
)
|
|
87
99
|
|
|
88
100
|
for command in commands:
|
|
89
101
|
with self.subTest(command):
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import functools
|
|
1
2
|
import shutil
|
|
2
3
|
import sys
|
|
3
4
|
from pathlib import Path
|
|
@@ -15,12 +16,14 @@ def get_bin(name: str) -> Path:
|
|
|
15
16
|
return Path(bin_path)
|
|
16
17
|
|
|
17
18
|
|
|
19
|
+
@functools.cache
|
|
18
20
|
def get_esptool_bin() -> Path:
|
|
19
21
|
esptool_bin = get_bin('esptool')
|
|
20
22
|
verbose_check_call(esptool_bin, 'version')
|
|
21
23
|
return esptool_bin
|
|
22
24
|
|
|
23
25
|
|
|
26
|
+
@functools.cache
|
|
24
27
|
def get_mpremote_bin():
|
|
25
28
|
mpremote_bin = get_bin('mpremote')
|
|
26
29
|
verbose_check_call(mpremote_bin, '--version')
|
|
@@ -46,7 +46,7 @@ def file_chooser(paths) -> Path | None:
|
|
|
46
46
|
return selection
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
def get_newest_files(directory, limit=10) -> Path | None:
|
|
49
|
+
def get_newest_files(directory: Path, limit=10) -> Path | None:
|
|
50
50
|
files = []
|
|
51
51
|
|
|
52
52
|
def scan(dir_path):
|
|
@@ -60,7 +60,7 @@ def get_newest_files(directory, limit=10) -> Path | None:
|
|
|
60
60
|
scan(directory)
|
|
61
61
|
files.sort(key=lambda x: x[1], reverse=True)
|
|
62
62
|
|
|
63
|
-
print(f'[bold]Choose a file[/bold] (only from the newest {limit}):\n')
|
|
63
|
+
print(f'[bold]Choose a file[/bold] (only from the newest {limit} from {directory}):\n')
|
|
64
64
|
for idx, (entry, mtime) in enumerate(files[:limit]):
|
|
65
65
|
dt = datetime.datetime.fromtimestamp(mtime).astimezone().strftime('%Y-%m-%d %H:%M:%S')
|
|
66
66
|
rel_path = Path(entry.path).relative_to(directory)
|
|
@@ -85,8 +85,9 @@ def get_newest_files(directory, limit=10) -> Path | None:
|
|
|
85
85
|
print(f'[red]Invalid selection: {number}[/red]')
|
|
86
86
|
sys.exit(1)
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
absolute_path = directory / selection
|
|
89
|
+
print(f'Selected file: {absolute_path}')
|
|
90
|
+
return absolute_path
|
|
90
91
|
|
|
91
92
|
|
|
92
93
|
def choose_newest_modified_directory(base_dir: Path) -> Path:
|
|
File without changes
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import shlex
|
|
2
|
+
import subprocess
|
|
3
|
+
import time
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from bx_py_utils.path import assert_is_dir
|
|
7
|
+
from rich import print
|
|
8
|
+
|
|
9
|
+
from mposcli.tools import get_mpremote_bin
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MpOsPathResolver:
|
|
13
|
+
def __init__(self, mpos: Path):
|
|
14
|
+
self.mpos = mpos # e.g.: ~/repos/MicroPythonOS
|
|
15
|
+
self.internal_fs = mpos / 'internal_filesystem'
|
|
16
|
+
self.lib_mpos = self.internal_fs / 'lib' / 'mpos'
|
|
17
|
+
assert_is_dir(self.lib_mpos)
|
|
18
|
+
self.apps_path = self.internal_fs / 'apps'
|
|
19
|
+
assert_is_dir(self.apps_path)
|
|
20
|
+
|
|
21
|
+
def resolve(self, source: Path):
|
|
22
|
+
source = source.resolve()
|
|
23
|
+
assert source.exists(), f'Not existing path: {source=}'
|
|
24
|
+
assert source.is_relative_to(self.mpos), f'{source=} is not inside {self.mpos=}'
|
|
25
|
+
|
|
26
|
+
if source.is_relative_to(self.apps_path):
|
|
27
|
+
device_base_path = self.apps_path.parent
|
|
28
|
+
elif source.is_relative_to(self.lib_mpos):
|
|
29
|
+
device_base_path = self.lib_mpos.parent
|
|
30
|
+
elif source.is_relative_to(self.internal_fs):
|
|
31
|
+
device_base_path = self.internal_fs
|
|
32
|
+
else:
|
|
33
|
+
raise ValueError(f'Path {source} is not in a recognized location')
|
|
34
|
+
|
|
35
|
+
remote_path = source.relative_to(device_base_path)
|
|
36
|
+
source_path = source.relative_to(self.mpos)
|
|
37
|
+
if source.is_dir():
|
|
38
|
+
remote_path = remote_path.parent
|
|
39
|
+
local_path_str = f'{source_path}/'
|
|
40
|
+
remote_str = f':{remote_path}/'
|
|
41
|
+
else:
|
|
42
|
+
local_path_str = f'{source_path}'
|
|
43
|
+
remote_str = f':{remote_path}'
|
|
44
|
+
|
|
45
|
+
return local_path_str, remote_str
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def start_mpremote_repl(max_try=10, wait_time=1):
|
|
49
|
+
print('Starting mpremote REPL...')
|
|
50
|
+
time.sleep(wait_time)
|
|
51
|
+
mpremote_bin = get_mpremote_bin()
|
|
52
|
+
|
|
53
|
+
popen_args = (mpremote_bin, 'repl')
|
|
54
|
+
|
|
55
|
+
for try_count in range(max_try):
|
|
56
|
+
print(f'\n+ {shlex.join(str(arg) for arg in popen_args)}')
|
|
57
|
+
try:
|
|
58
|
+
return subprocess.check_call(popen_args)
|
|
59
|
+
except subprocess.CalledProcessError as err:
|
|
60
|
+
print(
|
|
61
|
+
f'[yellow]mpremote finished with [red]exit code {err.returncode!r}[/red]'
|
|
62
|
+
f' Retrying in {wait_time} seconds... (try {try_count + 1}/{max_try})'
|
|
63
|
+
)
|
|
64
|
+
time.sleep(wait_time)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|