micropython-stubber 1.17.6__py3-none-any.whl → 1.20.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. {micropython_stubber-1.17.6.dist-info → micropython_stubber-1.20.0.dist-info}/METADATA +7 -6
  2. micropython_stubber-1.20.0.dist-info/RECORD +147 -0
  3. mpflash/README.md +18 -2
  4. mpflash/libusb_flash.ipynb +203 -0
  5. mpflash/mpflash/ask_input.py +234 -0
  6. mpflash/mpflash/cli_download.py +107 -0
  7. mpflash/mpflash/cli_flash.py +170 -0
  8. mpflash/mpflash/cli_group.py +40 -7
  9. mpflash/mpflash/cli_list.py +41 -0
  10. mpflash/mpflash/cli_main.py +13 -8
  11. mpflash/mpflash/common.py +33 -121
  12. mpflash/mpflash/config.py +9 -0
  13. mpflash/mpflash/{downloader.py → download.py} +110 -96
  14. mpflash/mpflash/downloaded.py +108 -0
  15. mpflash/mpflash/errors.py +5 -0
  16. mpflash/mpflash/flash.py +69 -0
  17. mpflash/mpflash/flash_esp.py +17 -23
  18. mpflash/mpflash/flash_stm32.py +16 -113
  19. mpflash/mpflash/flash_stm32_cube.py +111 -0
  20. mpflash/mpflash/flash_stm32_dfu.py +101 -0
  21. mpflash/mpflash/flash_uf2.py +8 -8
  22. mpflash/mpflash/flash_uf2_linux.py +13 -6
  23. mpflash/mpflash/flash_uf2_windows.py +24 -12
  24. mpflash/mpflash/list.py +56 -39
  25. mpflash/mpflash/logger.py +12 -13
  26. mpflash/mpflash/mpboard_id/__init__.py +96 -0
  27. mpflash/mpflash/mpboard_id/board_id.py +63 -0
  28. mpflash/mpflash/mpboard_id/board_info.csv +2213 -0
  29. mpflash/mpflash/mpboard_id/board_info.json +19910 -0
  30. mpflash/mpflash/mpremoteboard/__init__.py +209 -0
  31. mpflash/mpflash/mpremoteboard/mpy_fw_info.py +141 -0
  32. {stubber/bulk → mpflash/mpflash/mpremoteboard}/runner.py +19 -4
  33. mpflash/mpflash/vendor/dfu.py +164 -0
  34. mpflash/mpflash/vendor/pydfu.py +605 -0
  35. mpflash/mpflash/vendor/readme.md +3 -0
  36. mpflash/mpflash/vendor/versions.py +113 -0
  37. mpflash/mpflash/worklist.py +147 -0
  38. mpflash/poetry.lock +427 -610
  39. mpflash/pyproject.toml +22 -6
  40. mpflash/stm32_udev_rules.md +63 -0
  41. stubber/__init__.py +1 -1
  42. stubber/basicgit.py +1 -0
  43. stubber/board/createstubs.py +11 -4
  44. stubber/board/createstubs_db.py +11 -5
  45. stubber/board/createstubs_db_min.py +61 -58
  46. stubber/board/createstubs_db_mpy.mpy +0 -0
  47. stubber/board/createstubs_mem.py +11 -5
  48. stubber/board/createstubs_mem_min.py +56 -53
  49. stubber/board/createstubs_mem_mpy.mpy +0 -0
  50. stubber/board/createstubs_min.py +54 -51
  51. stubber/board/createstubs_mpy.mpy +0 -0
  52. stubber/board/modulelist.txt +1 -0
  53. stubber/bulk/mcu_stubber.py +9 -5
  54. stubber/codemod/_partials/db_main.py +14 -25
  55. stubber/codemod/_partials/lvgl_main.py +2 -2
  56. stubber/codemod/board.py +10 -3
  57. stubber/commands/clone_cmd.py +7 -7
  58. stubber/commands/config_cmd.py +3 -0
  59. stubber/commands/{mcu_cmd.py → get_mcu_cmd.py} +20 -3
  60. stubber/freeze/get_frozen.py +0 -2
  61. stubber/publish/candidates.py +1 -1
  62. stubber/publish/package.py +1 -1
  63. stubber/publish/pathnames.py +1 -1
  64. stubber/publish/stubpackage.py +1 -0
  65. stubber/rst/lookup.py +1 -1
  66. stubber/stubber.py +1 -9
  67. stubber/tools/manifestfile.py +5 -3
  68. stubber/update_fallback.py +104 -104
  69. stubber/utils/config.py +32 -36
  70. stubber/utils/repos.py +2 -2
  71. stubber/utils/versions.py +1 -0
  72. micropython_stubber-1.17.6.dist-info/RECORD +0 -132
  73. mpflash/mpflash/flasher.py +0 -276
  74. stubber/bulk/board_id.py +0 -40
  75. stubber/bulk/mpremoteboard.py +0 -141
  76. stubber/commands/get_lobo_cmd.py +0 -58
  77. stubber/commands/minify_cmd.py +0 -60
  78. stubber/commands/upd_fallback_cmd.py +0 -36
  79. stubber/commands/upd_module_list_cmd.py +0 -18
  80. {micropython_stubber-1.17.6.dist-info → micropython_stubber-1.20.0.dist-info}/LICENSE +0 -0
  81. {micropython_stubber-1.17.6.dist-info → micropython_stubber-1.20.0.dist-info}/WHEEL +0 -0
  82. {micropython_stubber-1.17.6.dist-info → micropython_stubber-1.20.0.dist-info}/entry_points.txt +0 -0
  83. /mpflash/mpflash/{uf2_boardid.py → flash_uf2_boardid.py} +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: micropython-stubber
3
- Version: 1.17.6
3
+ Version: 1.20.0
4
4
  Summary: Tooling to create and maintain stubs for MicroPython
5
5
  Home-page: https://github.com/Josverl/micropython-stubber#readme
6
6
  License: MIT
7
7
  Keywords: MicroPython,stubs,vscode,pyright,linting,static type check
8
8
  Author: Jos Verlinde
9
9
  Author-email: jos_verlinde@hotmail.com
10
- Requires-Python: >=3.9,<3.12
10
+ Requires-Python: >=3.9,<4.0
11
11
  Classifier: License :: OSI Approved :: MIT License
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Programming Language :: Python :: 3.9
@@ -25,6 +25,7 @@ Requires-Dist: executing (>=2.0.1,<3.0.0)
25
25
  Requires-Dist: importlib-metadata (>=1.0,<2.0) ; python_version < "3.8"
26
26
  Requires-Dist: libcst (>=1.1.0,<2.0.0)
27
27
  Requires-Dist: loguru (>=0.6,<0.8)
28
+ Requires-Dist: mpflash (>=0.6.0)
28
29
  Requires-Dist: mpremote (>=1.22.0,<2.0.0)
29
30
  Requires-Dist: mypy (==1.7.0)
30
31
  Requires-Dist: mypy-gitlab-code-quality (>=1.1.0,<2.0.0)
@@ -51,13 +52,13 @@ Description-Content-Type: text/markdown
51
52
 
52
53
  [![pypi version](https://badgen.net/pypi/v/micropython-stubber)](https://pypi.org/project/micropython-stubber/)
53
54
  [![python versions](https://badgen.net/pypi/python/micropython-stubber)](https://badgen.net/pypi/python/micropython-stubber)
54
- [![Documentation Status](https://readthedocs.org/projects/micropython-stubber/badge/?version=latest)](https://micropython-stubber.readthedocs.io/en/latest/?badge=latest "Document build status badge")
55
+ [![Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black "Black badge")
55
56
  [![Star on GitHub](https://img.shields.io/github/stars/josverl/micropython-stubber.svg?style=social)](https://github.com/josverl/micropython-stubber/stargazers)
56
57
  [![All Contributors](https://img.shields.io/badge/all_contributors-19-green.svg?style=flat-square)](#Contributions)
57
58
  <!-- break -->
58
- [![pytest tests/common](https://github.com/Josverl/micropython-stubber/actions/workflows/pytest.yml/badge.svg)](https://github.com/Josverl/micropython-stubber/actions/workflows/pytest.yml)
59
- [![codecov](https://codecov.io/gh/Josverl/micropython-stubber/branch/main/graph/badge.svg?token=WJFGMKBHOV)](https://codecov.io/gh/Josverl/micropython-stubber)
60
- [![Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black "Black badge")
59
+ [![pytest stubber](https://github.com/Josverl/micropython-stubber/actions/workflows/pytest.yml/badge.svg)](https://github.com/Josverl/micropython-stubber/actions/workflows/pytest.yml)
60
+ [![pytest mpflash](https://github.com/Josverl/micropython-stubber/actions/workflows/pytest_mpflash.yml/badge.svg)](https://github.com/Josverl/micropython-stubber/actions/workflows/pytest_mpflash.yml)
61
+ [![Documentation Status](https://readthedocs.org/projects/micropython-stubber/badge/?version=latest)](https://micropython-stubber.readthedocs.io/en/latest/?badge=latest "Document build status badge")
61
62
  <!-- break -->
62
63
  [![Open in VSCode](https://img.shields.io/static/v1?logo=visualstudiocode&label=&message=Open%20in%20Visual%20Studio%20Code&labelColor=2c2c32&color=007acc&logoColor=007acc
63
64
  )](https://open.vscode.dev/josverl/micropython-stubber)
@@ -0,0 +1,147 @@
1
+ mpflash/libusb_flash.ipynb,sha256=sw5MVQvPmH-DJy9kOdXyO80BSjEPMEXf_GJsGk3usrc,6428
2
+ mpflash/mpflash/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ mpflash/mpflash/ask_input.py,sha256=NGjCcOx49gW8xuDZK1BQXNOMPy7fUQ5pQamasez1wHI,7793
4
+ mpflash/mpflash/cli_download.py,sha256=9Rxwo-j7h9_rwMeAgITmfkdiNVi-Wunr1vpx2VjjUNM,3090
5
+ mpflash/mpflash/cli_flash.py,sha256=Hld8SGNTJWKB0CTjfG8wGZh8RaC7CtVxhw4--LKTkig,5760
6
+ mpflash/mpflash/cli_group.py,sha256=nL3H06PHm_XUDlMuRyjgmTYeLnkrLa9mKDdahYw-KRo,1967
7
+ mpflash/mpflash/cli_list.py,sha256=uxTRPdjFWv5ev4E_pz1JYv8DSFLOtZvTKmVmCiRpEC4,1005
8
+ mpflash/mpflash/cli_main.py,sha256=VxIpmvk3-2Sr1uB1AMT5bRa0TlrbY28ZaYd6NGZnEe0,632
9
+ mpflash/mpflash/common.py,sha256=lucFGMLl03qz-5Ic2XVv4g5XVt6hloUU6N5v0tSaUYE,1049
10
+ mpflash/mpflash/config.py,sha256=G6TxliEGxoYXy1SHQYBKgywnKccz9QzD3mGq_Vv1frg,419
11
+ mpflash/mpflash/download.py,sha256=HhL97PFTts_QhI1121QcWS7Z2nbfqvJ7mof_KFARx6k,10765
12
+ mpflash/mpflash/downloaded.py,sha256=ADMJqZn7WVcU-Rm2X6RqA8ejtBNBYXcpwxVyT3v7r6s,3803
13
+ mpflash/mpflash/errors.py,sha256=Q5LR12Wo8iUCg5n_qq4GjdBdBflbvCOdKsRJ5InYRfI,96
14
+ mpflash/mpflash/flash.py,sha256=YGYXuNNbjro4QvZmpwpLCo86nFsh4UxWrOJHOowUYDY,2490
15
+ mpflash/mpflash/flash_esp.py,sha256=TjBOk2y1eLrcE8T3iYGypsiskPX7BFNfxYmCuUo_3v4,2316
16
+ mpflash/mpflash/flash_stm32.py,sha256=d4BoQl3a9Tchnvn2ZTuq2MpYBB4MTaRukwtEncI95k0,823
17
+ mpflash/mpflash/flash_stm32_cube.py,sha256=w7aGWjReeWUKl0Q3ZjXH8BRqNO1Tk9AO7gtRNUg1c9Y,3970
18
+ mpflash/mpflash/flash_stm32_dfu.py,sha256=G70EZodWb-aRi507Jxbys-VEwbBGU1oZacow3_nq-d4,2972
19
+ mpflash/mpflash/flash_uf2.py,sha256=KvNPk1zDwQexJfPI5MlIoR7zTD0u-pQQwSHuFQjuMXg,2093
20
+ mpflash/mpflash/flash_uf2_boardid.py,sha256=WZKucGu_hJ8ymb236uuZbiR6pD6AA_l4LA-7LwtQhq8,414
21
+ mpflash/mpflash/flash_uf2_linux.py,sha256=LAGkzTImVq-wKo7LGUNlwkUHv1L4rGO7igR5dwxY07o,4298
22
+ mpflash/mpflash/flash_uf2_windows.py,sha256=dcmA-koavH7duOuNwI0n2aDDbhF1_5ZZ-mXFAXgj8z4,1072
23
+ mpflash/mpflash/list.py,sha256=G35Pjc8Aw3qqY4dCi-0QtRRZEiJF5EPwyuU7Jx5S63Q,3186
24
+ mpflash/mpflash/logger.py,sha256=dI_H_a7EOdQJyvoeRHQuYeZuTKYVUS3DUPTLhE9rkdM,1098
25
+ mpflash/mpflash/mpboard_id/__init__.py,sha256=JYGe7VwpBV4ig2M9a6vJUQrMtgdNjZKHt_Z5N13Ycrs,3509
26
+ mpflash/mpflash/mpboard_id/board_id.py,sha256=NjKkIUv3sw6X60qy--mieQWrle3WNKw5NwAepMenTHI,2230
27
+ mpflash/mpflash/mpboard_id/board_info.csv,sha256=KPWDo-zHWfrPGQn9oInsDH-5IdCzhBCs6K_YAmqqSpQ,96983
28
+ mpflash/mpflash/mpboard_id/board_info.json,sha256=JtVyOMIO1O7vLKzJ0hyXQ4JSxXiQBJyay2hjdNLnZM0,674442
29
+ mpflash/mpflash/mpremoteboard/__init__.py,sha256=DxlO_7LiyWDz5hNRI77fzp3sI3fZQ9Sd23dnGLx4Zl0,7017
30
+ mpflash/mpflash/mpremoteboard/mpy_fw_info.py,sha256=6AQbN3jtQgllqWQYl4e-63KeEtV08EXk8_JnM6XBkvo,4554
31
+ mpflash/mpflash/mpremoteboard/runner.py,sha256=H3W_xGJvjz7TLtlkDQrCLibgegRWGfsaBOABNbAfP_U,4783
32
+ mpflash/mpflash/vendor/dfu.py,sha256=oK_MRSOyDJrUuS6D24IMIsfL7oLcrvUq0yp_h4WIY2U,5739
33
+ mpflash/mpflash/vendor/pydfu.py,sha256=_MdBRo1EeNeKDqFPSTB5tNL1jGSBJgsVeVjE5e7Pb8s,20542
34
+ mpflash/mpflash/vendor/readme.md,sha256=iIIZxuLUIGHQ0KODzYVtMezsztvyxCXcNJp_AzwTIPk,86
35
+ mpflash/mpflash/vendor/versions.py,sha256=ooRZjeeYepQHwp12hMu2m0p8nZXQ5s942w5mGkKmgeI,3629
36
+ mpflash/mpflash/worklist.py,sha256=qZsqF3Lf5Bl7QQ31ZLVHewP6WC8fmwQPMbyNgbG7LB4,5299
37
+ mpflash/poetry.lock,sha256=IFlzAMe4-gKB5OJHkbm7vnGBmJGBI3vcasHkQmiNz7I,120389
38
+ mpflash/pyproject.toml,sha256=Pv5rFYNPI8K6vH9Fd9JwOi6B-07To0uKPijmTh-bLmc,1628
39
+ mpflash/README.md,sha256=q_vVktLk3C_3L5nZT6SfiKs7l4zOSYG03zXrHinOLig,12253
40
+ mpflash/stm32_udev_rules.md,sha256=uxvC8FvU7K0R1QQUqCIvVfW9yfWYlIHhIVtirAjQVHE,2684
41
+ stubber/__init__.py,sha256=o1qcasRklnxYGOP3EFPV2_p14ofWGqNiABgcOKra5-8,49
42
+ stubber/basicgit.py,sha256=sflgCv7apLbV2w8F6gmhc-3kuqDnnS4tdGol6JT2uTM,9545
43
+ stubber/board/board_info.csv,sha256=K2VSmfR013fN-oJWkQUmiQ19w09dVwJHDquPy6QmMhY,8627
44
+ stubber/board/boot.py,sha256=XjWlKErU5nI1HJSugXIP_3hlwgRQboE6sJrpcbSygnk,1120
45
+ stubber/board/createstubs.py,sha256=UEsqCBrXA9ipSjwI7FMr2nsZ0HtNBW2LN1kfSnK1bEw,32723
46
+ stubber/board/createstubs_db.py,sha256=BTaGBSVVIz1SzeRCFGgMeShYd6SdtBV3J8ZHi8iy_Zw,30445
47
+ stubber/board/createstubs_db_min.py,sha256=Gm1tcNzQ9zcPRt_bHYrUoKLXicHWxUxsOsqHI3TqjPk,11473
48
+ stubber/board/createstubs_db_mpy.mpy,sha256=0P0crBWixxVHvpPwB2C1kXTK6g7KuEtzE_4EYJDs1M4,9536
49
+ stubber/board/createstubs_lvgl.py,sha256=CTe7eq1ACRK_JJxavaqDD8znn29nSWJiHHTZ_ps6EhM,27217
50
+ stubber/board/createstubs_lvgl_min.py,sha256=jLkWYmeboI2A8feMC7pT7cYWttLejQTuX7WAEZCylhw,27207
51
+ stubber/board/createstubs_lvgl_mpy.mpy,sha256=ex-nlq2V5e8anQBJvRWEEc-FzU7nlwg5NSrZ8vOadIA,9267
52
+ stubber/board/createstubs_mem.py,sha256=2DKVzQEt2qyh9s6iS_mo3u5YZ1htS0xn5ycCFIjQWLQ,28779
53
+ stubber/board/createstubs_mem_min.py,sha256=mMxSu3TYPmsh_olGJ83b_OBojwwxDeFbVm96H4nJ8WM,11019
54
+ stubber/board/createstubs_mem_mpy.mpy,sha256=KdYmiWuaqzPMFpOirTpE7uJTyk1k384f87MQtTaL0NM,9118
55
+ stubber/board/createstubs_min.py,sha256=n5IQQLlxt8AIUplS3onjuekm2H4WAlU2fmYMldpf-rc,13564
56
+ stubber/board/createstubs_mpy.mpy,sha256=QBmLdLJnPDJJBRZrR27ss6slwUGzredY1f_HrA17f9g,12228
57
+ stubber/board/fw_info.py,sha256=6AQbN3jtQgllqWQYl4e-63KeEtV08EXk8_JnM6XBkvo,4554
58
+ stubber/board/info.py,sha256=b7SOPZHVsVhaayKCwVkFZlYu0BW-UFI7LuG1Eop9480,5629
59
+ stubber/board/main.py,sha256=f6V3tdt6sPZVLuwemT-NLuK9GySfW2c2J6PJMOOWQQw,413
60
+ stubber/board/modulelist.txt,sha256=LrFH2H7tHZCA960yIa5-6mHItwI5N2LwQZ_IveDoyYs,2775
61
+ stubber/board/pyrightconfig.json,sha256=6oHS4aDOfwKBAFeUPsCGJzEXpUgBZsPaF0M4P-N26D4,1376
62
+ stubber/bulk/mcu_stubber.py,sha256=_1z0LUzcMbEIXIYInMJcAJZbBPTI8yCHgd1-1nlMscM,16379
63
+ stubber/codemod/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
+ stubber/codemod/_partials/__init__.py,sha256=4v1lkgSBzFw08gxwujh5sivpbJbYqg5lZeRzgyvN4TE,1561
65
+ stubber/codemod/_partials/db_main.py,sha256=ZKzxV0LOEyHu1zcsBr4xRf9i1a4Jyh808sdbmcmkrWE,4003
66
+ stubber/codemod/_partials/lvgl_main.py,sha256=9BAJP6P1R2SQVbNya2ujes35eATa56D_Ri2_PjeRBq0,1964
67
+ stubber/codemod/_partials/modules_reader.py,sha256=dJj-H0ncUWVtilSyohQ-dyiUZOjQObds_-llwy_LkYU,2046
68
+ stubber/codemod/add_comment.py,sha256=CZMjtKO9aarZo1E60QXo80CLJAH05z_ylK6Vvjvb0ls,1965
69
+ stubber/codemod/add_method.py,sha256=fZH-RGi_pzFpi3tF_0AMDbA9A94dlgXMrc3ItpY3Ylw,2609
70
+ stubber/codemod/board.py,sha256=HDNS8saQIdoPH74MNG9mte0MRBqCOcy3d6f_I0H9J2I,11881
71
+ stubber/codemod/enrich.py,sha256=y1qUMnpgMHHgT7hN_Cp5Fmtv3psNAzYM7oHj_bSmT5A,5438
72
+ stubber/codemod/merge_docstub.py,sha256=0F8_RWVOqwX4PTmxOX0NQrI7rYBkig9n3MHCqkEG5K4,12681
73
+ stubber/codemod/modify_list.py,sha256=xrpFBKug273D9E02owUheZD418BvsIHIZCFj4YDjTxU,2118
74
+ stubber/codemod/utils.py,sha256=itARwbMps9UlzMaf4F3wJLJXJvtD-HYq1T1xw96zmR8,2459
75
+ stubber/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
+ stubber/commands/build_cmd.py,sha256=a3wW-SLw0HKl3b_7knqoUjMRHbZ14S6oeIQyEnf5-js,2461
77
+ stubber/commands/cli.py,sha256=pHtViupghgqKMxbyk5_Zz-qHx6i-BGdnTqRO-kngH2E,1850
78
+ stubber/commands/clone_cmd.py,sha256=mKTfB9eXKX06lTYyon1VioEDIfTPX5dYp-r9Qo87qIg,2673
79
+ stubber/commands/config_cmd.py,sha256=8g80QAuqBpYpivf35M2XcNxTOqapCRrnIATyen4cg5I,993
80
+ stubber/commands/enrich_folder_cmd.py,sha256=aGkydAsjyM9LHB99bcjxz_jyDGgOmisZyysbDhZxres,1853
81
+ stubber/commands/get_core_cmd.py,sha256=oxiDb_r1Ao9N2maeV0EBKosI4nRDNJkDk52xNunYICM,2226
82
+ stubber/commands/get_docstubs_cmd.py,sha256=xTkuc7k7Od7LUtt_ZohoHaRuE6qhQ80ST0b0ZHKMJrM,2824
83
+ stubber/commands/get_frozen_cmd.py,sha256=LhtWUL6l2kPUcRQBz19ChwTsdzjai4ryf0UBe52Fu48,3812
84
+ stubber/commands/get_mcu_cmd.py,sha256=uDodn57wdc9rHt7WSmHCFI-zTT1XrebPEaWN-G43E2Y,2015
85
+ stubber/commands/merge_cmd.py,sha256=2gQYxqapVGD8WMBsqRES7xjIS8acu4hTyutr1OANpAo,1673
86
+ stubber/commands/publish_cmd.py,sha256=myvgP7Y-pb-nyrMVMelNmIVHbxeK4g1ZXmQtxASblkk,2910
87
+ stubber/commands/stub_cmd.py,sha256=St3UlrVdbkddXystDG2NmKLq_1RbE-gNxlE7ShwQwaw,1186
88
+ stubber/commands/switch_cmd.py,sha256=DM73QU4Vo3ifr01rv-xSmlxp36T20josOt9-cyUWUDU,1796
89
+ stubber/commands/variants_cmd.py,sha256=QDm-KtDFIa9_Jl21vjArrW7OrToR8VfwK22pRo0e6CE,1284
90
+ stubber/cst_transformer.py,sha256=XbvGTUmhhFWW_Ig8Pu6lFdkBS_NCEmJ1oQQm4H1XSrM,6479
91
+ stubber/data/board_info.csv,sha256=K2VSmfR013fN-oJWkQUmiQ19w09dVwJHDquPy6QmMhY,8627
92
+ stubber/data/board_info.json,sha256=jyvBN5seoxx7Z7B3UpvMn7H8xWCpmG4VtFSPb8PjmZI,58939
93
+ stubber/data/micropython_tags.csv,sha256=HQnzPN7jLmgKX3QvobsPMZa-xMb0exglriFziBjaRz8,1909
94
+ stubber/data/requirements-core-micropython.txt,sha256=6RQWWbLh8YVcD_l1-hjg6wX_Fm1LmNEwy5NExKJIkeg,1317
95
+ stubber/data/requirements-core-pycopy.txt,sha256=tW71l6FIuoQY1tuxkDgeN4Uw8IIp0YrlhhaaqSGSOA8,1051
96
+ stubber/downloader.py,sha256=UbrvPg8xaX5xcdAaFUe2pdDBor5clyTl3yzh7r7FLdc,1206
97
+ stubber/freeze/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
+ stubber/freeze/common.py,sha256=fydpiBQvwwBM-Uib12NG1k51Pm5gUmPa19UFj6ZTD5E,2639
99
+ stubber/freeze/freeze_folder.py,sha256=9jLa6M1Uie6MOBnXezrrBYkM9sq4Ja6bz7RGsFpIZJw,2491
100
+ stubber/freeze/freeze_manifest_2.py,sha256=djruxIe8DkkYq9FM4Zj4VQg-UmG8kcYbRiIWIbqgZGk,4061
101
+ stubber/freeze/get_frozen.py,sha256=n1Hh59P88BL9nQnLnjUqnoPToW6pkgN2o1222amxwfM,5290
102
+ stubber/get_cpython.py,sha256=1YR8QxJq32yI_ZvUVWdNwiTxw2X5F4xdUgCxCFheEpw,3784
103
+ stubber/get_lobo.py,sha256=jyysWbeEwNuZZtkTudJP1QbyVvh-TwFom5cE7iCi9lE,1776
104
+ stubber/minify.py,sha256=QC5TbyNH7xJRauo8IMJgMnKGocqdjEXGb6YQgBvMTTA,15026
105
+ stubber/publish/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
106
+ stubber/publish/bump.py,sha256=qSb1DpaIxgyoH3YcPU1XKyDKgqkomxSm0WWf1sAVh0Y,3262
107
+ stubber/publish/candidates.py,sha256=vR_oNw3fjtWBa6Gvufe28Y6EKV3mWlJ1X6tq9Go0U1g,11576
108
+ stubber/publish/database.py,sha256=CLy5oiLasA-YzTTXi9d01qLAyk7NpugCDUOa5R9Ac2g,623
109
+ stubber/publish/defaults.py,sha256=-Ey04lflKVnT0xO8r8AGliQSdtek9Dm_LDjpwvAnAVk,1636
110
+ stubber/publish/enums.py,sha256=55TrwB7zlbCeXE3EdC4CCVmhRFlie-DlTqFuaAg-qXo,944
111
+ stubber/publish/helpers.py,sha256=909umfKUHBMBoVnAanop1vKx8loCrWntlfiiG6z89lY,716
112
+ stubber/publish/merge_docstubs.py,sha256=bo35onpFgcmcqExKSbpbZKprVs2D_feSy0awNZ09a7A,5319
113
+ stubber/publish/missing_class_methods.py,sha256=i_tPnGpEpmu53N3exPCrwR1HprxxBpgHgLAZSwJCb4o,1823
114
+ stubber/publish/package.py,sha256=9Op5nPJNOmjTv3QxVeaL86m6Aak2UlUgcQIcDGBbX5w,6320
115
+ stubber/publish/pathnames.py,sha256=O-9519j6FTIlmTFyDWqCxdG3k8MWhDI89rClBrgUONQ,1811
116
+ stubber/publish/publish.py,sha256=4CTI3n2DDU8QnrSiaDT2SAqk73tlziPLE4cLt8saDrk,3698
117
+ stubber/publish/pypi.py,sha256=Mu1F7Xx4e0NPWK1_Erck6QGEfdY8w67EBeWFi6JiAzk,1240
118
+ stubber/publish/stubpackage.py,sha256=45yquQiBlJhacYEOmAHP6BgDfl1EtUWjdDLx06rCWgE,44731
119
+ stubber/rst/__init__.py,sha256=5VcbDCotIICa2xnJDs_gw2sFXpjjGOZZbwCrNKXy1OE,293
120
+ stubber/rst/classsort.py,sha256=YCmF4QEYXqZ1Yu2FZb1iPQBrVkq-mrZaBaRcSUlC7ZE,2655
121
+ stubber/rst/lookup.py,sha256=9ouUrZO5FoWLMb02C-sUw_IDHrcFldbKgxcEx2J1Wmw,20149
122
+ stubber/rst/output_dict.py,sha256=cpBXRtUD-uh0EgjWIBiRrMLBmIAEXjoJFSOAg-qJQiU,14755
123
+ stubber/rst/reader.py,sha256=ZR2vrB0xup7qY2zAC6HKKytaiQjlUdr-gxFGamkSfHQ,33382
124
+ stubber/rst/report_return.py,sha256=WZJSbgjsjxFeCeY-vLms56gv_x3TubaGXGQ8--d8RqI,2814
125
+ stubber/rst/rst_utils.py,sha256=q4MCmhCeI0fnx6KNVdgz1nE4_hAK4T-F7oAMBnmwZ4w,17817
126
+ stubber/stubber.py,sha256=41zvyaDQt25Y8IRsMvcQR68LxDZrTz_iVJpEQ5D3VWc,1634
127
+ stubber/stubs_from_docs.py,sha256=34hHae5zWjlFyO0lXhEjyV2IyuX4akwO1VNb01ylcLY,2833
128
+ stubber/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
129
+ stubber/tools/manifestfile.py,sha256=D5Plwj5LRDe6zq5m-ETKfum0vFAykka70WXSEHl83a4,23721
130
+ stubber/tools/readme.md,sha256=kH7dA2Rs4BLCXa2ILoTDIj3sJHcGYtDPntyxVIOXvtI,199
131
+ stubber/update_fallback.py,sha256=NUxp1sN1-8BLPd0rpExTcYBppUXYWPP8dOcjNeLY2Zo,4921
132
+ stubber/update_module_list.py,sha256=QJ-c2K1Wf2SQdpMeGvlVabasKqsN9ZQV4ye5PbSpsWE,4640
133
+ stubber/utils/__init__.py,sha256=nV9FsOZsJ_hXsyUv4j0Qqp-PKycxyIktU9IoLs4kQmQ,225
134
+ stubber/utils/config.py,sha256=Jg4eHhgKim4uP4IqZRWykRNiX1r-SXC2xSrbsVprGAA,4859
135
+ stubber/utils/makeversionhdr.py,sha256=ZRpClirIzNK4saZHPaDuEpXhBRI_Ow_yZOxeNM3D_Ro,1908
136
+ stubber/utils/manifest.py,sha256=XBYCkxtYVAdUcch1784eHPAXlXfyfjco4WnRXxBHZYA,3273
137
+ stubber/utils/post.py,sha256=oSFZdoP6JwEeAOvsBo3kTk7l8ff_AVtL2Y4VIjzujlE,2837
138
+ stubber/utils/repos.py,sha256=nNr6Wy-UfIivMPB-1dCzqLJMueqlwQbQA2ha882CnRs,5815
139
+ stubber/utils/stubmaker.py,sha256=qld_Wfm9f4EuzedXlX1Ky0i0BJdR75oOOTha13_ekz0,5238
140
+ stubber/utils/typed_config_toml.py,sha256=ikifCIZGNhS_uqsfp6IwIpxdtZqbLtywprjWG_Q0y8o,2629
141
+ stubber/utils/versions.py,sha256=R65PAlUCAs9uvTxA6Frco2tHx6ADZCn59JOWI59ZhOo,3790
142
+ stubber/variants.py,sha256=-o4TgotbKaCcYBdXkutPaBSR1JdxWmOAiuNT1UlahYc,3784
143
+ micropython_stubber-1.20.0.dist-info/entry_points.txt,sha256=NQi_M36fgq5k6giSuASas3LrpF6CVdkzfvJC0ja73_g,55
144
+ micropython_stubber-1.20.0.dist-info/LICENSE,sha256=Fx9qrL45ayRXgH6QzttboqZEjKXms0w1t_b_nkOqYCU,1572
145
+ micropython_stubber-1.20.0.dist-info/METADATA,sha256=Ca3hFC3I3QZKJaG2DPXrLXTNv8LB3f2BFJgpuRfhK4k,19096
146
+ micropython_stubber-1.20.0.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
147
+ micropython_stubber-1.20.0.dist-info/RECORD,,
mpflash/README.md CHANGED
@@ -9,12 +9,28 @@ mpflash has been tested on Windows x64, Linux X64 and ARM64, but not (yet) macOS
9
9
  1. List the connected boards including their firmware details, in a tabular or json format
10
10
  2. Download MicroPython firmware for specific boards and versions.
11
11
  3. Flash one or all connected MicroPython boards with a specific firmware or version.
12
- Tested ports: rp2, samd, esp32, esp32s3, esp8266 and stm32 (requires cubeprogrammer)
12
+ Tested ports: rp2, samd, esp32, esp32s3, esp8266 and stm32
13
13
 
14
14
  ## Installation
15
15
  To install mpflash, you can use pip: `pip install mpflash`
16
16
 
17
- ## How to use
17
+ ## Basic usage
18
+ You can use mpflash to perform various operations on your MicroPython boards. Here is an example of basic usage:
19
+
20
+ | Command | Description |
21
+ |---------|-------------|
22
+ | `mpflash list` | List the connected board(s) including their firmware details |
23
+ | `mpflash download` | Download the MicroPython firmware(s) for the connected board(s) |
24
+ | `mpflash flash` | Flash the latest stable firmware to the connected board(s) |
25
+
26
+
27
+ ## Linux permissions to access usb devices
28
+ In order to flash the firmware to the board, you need to have the correct permissions to access the USB devices.
29
+ On Windows this will not be an issue, but on Linux you can use udev rules to give non-root users access to the USB devices.
30
+ [See the stm32_permissions documentation](./stm32_udev_rules.md) for more information.
31
+
32
+
33
+ ## Advanced use
18
34
  You can list the connected boards using the following command:
19
35
  ```bash
20
36
  $ mpflash list
@@ -0,0 +1,203 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 3,
6
+ "metadata": {},
7
+ "outputs": [
8
+ {
9
+ "data": {
10
+ "text/plain": [
11
+ "[<DEVICE ID 0a05:7211 on Bus 002 Address 054>,\n",
12
+ " <DEVICE ID 0a05:7211 on Bus 002 Address 032>,\n",
13
+ " <DEVICE ID 045e:0c1e on Bus 002 Address 002>,\n",
14
+ " <DEVICE ID 045e:07b2 on Bus 002 Address 028>,\n",
15
+ " <DEVICE ID 045e:0904 on Bus 002 Address 015>,\n",
16
+ " <DEVICE ID 043e:9a39 on Bus 002 Address 057>,\n",
17
+ " <DEVICE ID 045e:0901 on Bus 002 Address 006>,\n",
18
+ " <DEVICE ID 05e3:0610 on Bus 002 Address 010>,\n",
19
+ " <DEVICE ID 2109:0817 on Bus 001 Address 001>,\n",
20
+ " <DEVICE ID 045e:0902 on Bus 002 Address 008>,\n",
21
+ " <DEVICE ID 1000:2000 on Bus 002 Address 016>,\n",
22
+ " <DEVICE ID 1189:8890 on Bus 002 Address 027>,\n",
23
+ " <DEVICE ID 2109:0817 on Bus 001 Address 002>,\n",
24
+ " <DEVICE ID 2109:2812 on Bus 002 Address 025>,\n",
25
+ " <DEVICE ID 046d:085e on Bus 002 Address 017>,\n",
26
+ " <DEVICE ID 045e:07c6 on Bus 002 Address 056>,\n",
27
+ " <DEVICE ID 0bda:5401 on Bus 002 Address 009>,\n",
28
+ " <DEVICE ID 10c4:ea60 on Bus 002 Address 055>,\n",
29
+ " <DEVICE ID 2109:2817 on Bus 002 Address 004>,\n",
30
+ " <DEVICE ID 0bda:5411 on Bus 002 Address 005>,\n",
31
+ " <DEVICE ID 045e:0900 on Bus 002 Address 003>,\n",
32
+ " <DEVICE ID 04e8:61f5 on Bus 002 Address 023>,\n",
33
+ " <DEVICE ID 045e:0903 on Bus 002 Address 020>,\n",
34
+ " <DEVICE ID 2109:2812 on Bus 002 Address 026>,\n",
35
+ " <DEVICE ID 8086:a0ed on Bus 002 Address 000>,\n",
36
+ " <DEVICE ID 2109:2817 on Bus 002 Address 013>,\n",
37
+ " <DEVICE ID 8087:0029 on Bus 002 Address 001>,\n",
38
+ " <DEVICE ID 8086:9a13 on Bus 001 Address 000>]"
39
+ ]
40
+ },
41
+ "execution_count": 3,
42
+ "metadata": {},
43
+ "output_type": "execute_result"
44
+ }
45
+ ],
46
+ "source": [
47
+ "import usb.core\n",
48
+ "import usb.util\n",
49
+ "import usb.backend.libusb1 as libusb1\n",
50
+ "from usb.core import USBError, Device\n",
51
+ "\n",
52
+ "from pathlib import Path\n",
53
+ "import platform\n",
54
+ "\n",
55
+ "if platform.system() == \"Windows\":\n",
56
+ " # on windows you need to use the libusb1 backend\n",
57
+ " import libusb\n",
58
+ "\n",
59
+ " arch = \"x64\" if platform.architecture()[0] == \"64bit\" else \"x86\"\n",
60
+ " libusb1_dll = Path(libusb.__file__).parent / f\"_platform\\\\_windows\\\\{arch}\\\\libusb-1.0.dll\"\n",
61
+ "\n",
62
+ " backend = libusb1.get_backend(find_library=lambda x: libusb1_dll.as_posix())\n",
63
+ "usb_devices = usb.core.find(backend=backend, find_all=True)\n",
64
+ "\n",
65
+ "list(usb_devices)"
66
+ ]
67
+ },
68
+ {
69
+ "cell_type": "code",
70
+ "execution_count": null,
71
+ "metadata": {},
72
+ "outputs": [],
73
+ "source": [
74
+ "for d in usb.core.find(backend=backend, find_all=True):\n",
75
+ " print(f\"Device {d.idVendor:04x}:{d.idProduct:04x}\")\n",
76
+ " print(f\"{d.iManufacturer=}\")\n",
77
+ " print(f\"{d.iProduct=}\")\n",
78
+ " print(f\"{d.bDeviceClass=}\")\n",
79
+ " print(f\"{d.bDescriptorType=}\")\n",
80
+ " print(f\"{d.bcdDevice=}\")\n",
81
+ " print(f\"{d.bcdUSB=}\")\n",
82
+ " # print(dir(d))\n",
83
+ " # print(f\" Manufacturer: {usb.util.get_string(dev, dev.iManufacturer)}\")\n",
84
+ "\n",
85
+ " print()"
86
+ ]
87
+ },
88
+ {
89
+ "cell_type": "code",
90
+ "execution_count": null,
91
+ "metadata": {},
92
+ "outputs": [],
93
+ "source": [
94
+ "import serial.tools.list_ports\n",
95
+ "\n",
96
+ "ports = serial.tools.list_ports.comports()\n",
97
+ "\n",
98
+ "for port in ports:\n",
99
+ " print(f\"Port: {port.device}\")\n",
100
+ " print(f\"Description: {port.description}\")\n",
101
+ " print(f\"Hardware ID: {port.hwid}\")\n",
102
+ " print()"
103
+ ]
104
+ },
105
+ {
106
+ "cell_type": "code",
107
+ "execution_count": null,
108
+ "metadata": {},
109
+ "outputs": [],
110
+ "source": [
111
+ "from mpflash.vendor import pydfu as pydfu\n",
112
+ "\n",
113
+ "try:\n",
114
+ " pydfu.list_dfu_devices()\n",
115
+ "except SystemExit:\n",
116
+ " print(\"No DFU devices found\")"
117
+ ]
118
+ },
119
+ {
120
+ "cell_type": "code",
121
+ "execution_count": null,
122
+ "metadata": {},
123
+ "outputs": [],
124
+ "source": [
125
+ "pydfu.init()"
126
+ ]
127
+ },
128
+ {
129
+ "cell_type": "code",
130
+ "execution_count": null,
131
+ "metadata": {},
132
+ "outputs": [],
133
+ "source": [
134
+ "dfu_file = Path(\"C:\\\\Users\\\\josverl\\\\Downloads\\\\firmware\\\\stm32\\\\PYBV11-THREAD-v1.23.0-preview.203.dfu\")\n",
135
+ "\n",
136
+ "print(\"Read DFU file...\")\n",
137
+ "elements = pydfu.read_dfu_file(dfu_file)\n",
138
+ "if not elements:\n",
139
+ " print(\"No data in dfu file\")"
140
+ ]
141
+ },
142
+ {
143
+ "cell_type": "code",
144
+ "execution_count": 1,
145
+ "metadata": {},
146
+ "outputs": [
147
+ {
148
+ "name": "stdout",
149
+ "output_type": "stream",
150
+ "text": [
151
+ "Writing memory...\n"
152
+ ]
153
+ },
154
+ {
155
+ "ename": "NameError",
156
+ "evalue": "name 'pydfu' is not defined",
157
+ "output_type": "error",
158
+ "traceback": [
159
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
160
+ "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)",
161
+ "Cell \u001b[1;32mIn[1], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mWriting memory...\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m----> 2\u001b[0m \u001b[43mpydfu\u001b[49m\u001b[38;5;241m.\u001b[39mwrite_elements(elements, \u001b[38;5;28;01mFalse\u001b[39;00m, progress\u001b[38;5;241m=\u001b[39mpydfu\u001b[38;5;241m.\u001b[39mcli_progress)\n",
162
+ "\u001b[1;31mNameError\u001b[0m: name 'pydfu' is not defined"
163
+ ]
164
+ }
165
+ ],
166
+ "source": [
167
+ "print(\"Writing memory...\")\n",
168
+ "pydfu.write_elements(elements, False, progress=pydfu.cli_progress)"
169
+ ]
170
+ },
171
+ {
172
+ "cell_type": "code",
173
+ "execution_count": null,
174
+ "metadata": {},
175
+ "outputs": [],
176
+ "source": [
177
+ "print(\"Exiting DFU...\")\n",
178
+ "pydfu.exit_dfu()"
179
+ ]
180
+ }
181
+ ],
182
+ "metadata": {
183
+ "kernelspec": {
184
+ "display_name": ".venv",
185
+ "language": "python",
186
+ "name": "python3"
187
+ },
188
+ "language_info": {
189
+ "codemirror_mode": {
190
+ "name": "ipython",
191
+ "version": 3
192
+ },
193
+ "file_extension": ".py",
194
+ "mimetype": "text/x-python",
195
+ "name": "python",
196
+ "nbconvert_exporter": "python",
197
+ "pygments_lexer": "ipython3",
198
+ "version": "3.11.7"
199
+ }
200
+ },
201
+ "nbformat": 4,
202
+ "nbformat_minor": 2
203
+ }
@@ -0,0 +1,234 @@
1
+ """
2
+ Interactive input for mpflash.
3
+
4
+ Note: The prompts can use "{version}" and "{action}" to insert the version and action in the prompt without needing an f-string.
5
+ The values are provided from the answers dictionary.
6
+ """
7
+
8
+ from dataclasses import dataclass, field
9
+ from pathlib import Path
10
+ from typing import Dict, List, Sequence, Tuple, Union
11
+
12
+ from loguru import logger as log
13
+
14
+ from mpflash.config import config
15
+ from mpflash.mpboard_id import known_stored_boards, local_mp_ports
16
+ from mpflash.mpremoteboard import MPRemoteBoard
17
+ from mpflash.vendor.versions import micropython_versions
18
+
19
+
20
+ @dataclass
21
+ class Params:
22
+ ports: List[str] = field(default_factory=list)
23
+ boards: List[str] = field(default_factory=list)
24
+ versions: List[str] = field(default_factory=list)
25
+ fw_folder: Path = Path()
26
+
27
+
28
+ @dataclass
29
+ class DownloadParams(Params):
30
+ clean: bool = False
31
+ force: bool = False
32
+
33
+
34
+ @dataclass
35
+ class FlashParams(Params):
36
+ # TODO: Should Serial port be a list?
37
+ serial: str = ""
38
+ erase: bool = True
39
+ bootloader: bool = True
40
+ cpu: str = ""
41
+
42
+
43
+ ParamType = Union[DownloadParams, FlashParams]
44
+
45
+
46
+ def ask_missing_params(
47
+ params: ParamType,
48
+ action: str = "download",
49
+ ) -> ParamType:
50
+ """
51
+ Asks the user for parameters that have not been supplied on the commandline and returns the updated params.
52
+
53
+ Args:
54
+ params (ParamType): The parameters to be updated.
55
+ action (str, optional): The action to be performed. Defaults to "download".
56
+
57
+ Returns:
58
+ ParamType: The updated parameters.
59
+ """
60
+ if not config.interactive:
61
+ # no interactivity allowed
62
+ return params
63
+ # import only when needed to reduce load time
64
+ import inquirer
65
+
66
+ questions = []
67
+ answers = {"action": action}
68
+ if isinstance(params, FlashParams):
69
+ if not params.serial or "?" in params.serial:
70
+ ask_serialport(questions, action=action)
71
+ else:
72
+ answers["serial"] = params.serial
73
+
74
+ if not params.versions or "?" in params.versions:
75
+ ask_versions(questions, action=action)
76
+ else:
77
+ # versions is used to show only the boards for the selected versions
78
+ answers["versions"] = params.versions # type: ignore
79
+
80
+ if not params.boards or "?" in params.boards:
81
+ ask_port_board(questions, action=action)
82
+
83
+ answers = inquirer.prompt(questions, answers=answers)
84
+ if not answers:
85
+ # input cancelled by user
86
+ return [] # type: ignore
87
+ # print(repr(answers))
88
+ if isinstance(params, FlashParams) and "serial" in answers:
89
+ params.serial = answers["serial"]
90
+ if "port" in answers:
91
+ params.ports = [answers["port"]]
92
+ if "boards" in answers:
93
+ params.boards = answers["boards"] if isinstance(answers["boards"], list) else [answers["boards"]]
94
+ if "versions" in answers:
95
+ # make sure it is a list
96
+ params.versions = answers["versions"] if isinstance(answers["versions"], list) else [answers["versions"]]
97
+
98
+ log.debug(repr(params))
99
+
100
+ return params
101
+
102
+
103
+ def filter_matching_boards(answers: dict) -> Sequence[Tuple[str, str]]:
104
+ """
105
+ Filters the known boards based on the selected versions and returns the filtered boards.
106
+
107
+ Args:
108
+ answers (dict): The user's answers.
109
+
110
+ Returns:
111
+ Sequence[Tuple[str, str]]: The filtered boards.
112
+ """
113
+ # if version is not asked ; then need to get the version from the inputs
114
+ if "versions" in answers:
115
+ _versions = list(answers["versions"])
116
+ if "stable" in _versions:
117
+ _versions.remove("stable")
118
+ _versions.append(micropython_versions()[-2]) # latest stable
119
+ if "preview" in _versions:
120
+ _versions.remove("preview")
121
+ _versions.extend((micropython_versions()[-1], micropython_versions()[-2])) # latest preview and stable
122
+
123
+ some_boards = known_stored_boards(answers["port"], _versions) # or known_mp_boards(answers["port"])
124
+ else:
125
+ some_boards = known_stored_boards(answers["port"])
126
+
127
+ if some_boards:
128
+ # Create a dictionary where the keys are the second elements of the tuples
129
+ # This will automatically remove duplicates because dictionaries cannot have duplicate keys
130
+ unique_dict = {item[1]: item for item in some_boards}
131
+ # Get the values of the dictionary, which are the unique items from the original list
132
+ some_boards = list(unique_dict.values())
133
+ else:
134
+ some_boards = [("No boards found", "")]
135
+ return some_boards
136
+
137
+
138
+ def ask_port_board(questions: list, *, action: str):
139
+ """
140
+ Asks the user for the port and board selection.
141
+
142
+ Args:
143
+ questions (list): The list of questions to be asked.
144
+ action (str): The action to be performed.
145
+
146
+ Returns:
147
+ None
148
+ """
149
+ # import only when needed to reduce load time
150
+ import inquirer
151
+
152
+ # TODO: if action = flash, Use Inquirer.List for boards
153
+ inquirer_ux = inquirer.Checkbox if action == "download" else inquirer.List
154
+ questions.extend(
155
+ (
156
+ inquirer.List(
157
+ "port",
158
+ message="Which port do you want to {action} " + "to {serial} ?" if action == "flash" else "?",
159
+ choices=local_mp_ports(),
160
+ autocomplete=True,
161
+ ),
162
+ inquirer_ux(
163
+ "boards",
164
+ message=(
165
+ "Which {port} board firmware do you want to {action} " + "to {serial} ?"
166
+ if action == "flash"
167
+ else "?"
168
+ ),
169
+ choices=filter_matching_boards,
170
+ validate=lambda _, x: True if x else "Please select at least one board", # type: ignore
171
+ ),
172
+ )
173
+ )
174
+
175
+
176
+ def ask_versions(questions: list, *, action: str):
177
+ """
178
+ Asks the user for the version selection.
179
+
180
+ Args:
181
+ questions (list): The list of questions to be asked.
182
+ action (str): The action to be performed.
183
+
184
+ Returns:
185
+ None
186
+ """
187
+ # import only when needed to reduce load time
188
+ import inquirer
189
+
190
+ input_ux = inquirer.Checkbox if action == "download" else inquirer.List
191
+ mp_versions: List[str] = micropython_versions()
192
+ mp_versions = [v for v in mp_versions if "preview" not in v]
193
+ mp_versions.append("preview")
194
+ mp_versions.reverse() # newest first
195
+ questions.append(
196
+ input_ux(
197
+ # inquirer.List(
198
+ "versions",
199
+ message="Which version(s) do you want to {action} " + ("to {serial} ?" if action == "flash" else "?"),
200
+ # Hints would be nice , but needs a hint for each and every option
201
+ # hints=["Use space to select multiple options"],
202
+ choices=mp_versions,
203
+ autocomplete=True,
204
+ validate=lambda _, x: True if x else "Please select at least one version", # type: ignore
205
+ )
206
+ )
207
+
208
+
209
+ def ask_serialport(questions: list, *, action: str):
210
+ """
211
+ Asks the user for the serial port selection.
212
+
213
+ Args:
214
+ questions (list): The list of questions to be asked.
215
+ action (str): The action to be performed.
216
+
217
+ Returns:
218
+ None
219
+ """
220
+ # import only when needed to reduce load time
221
+ import inquirer
222
+
223
+ serialports = MPRemoteBoard.connected_boards()
224
+ questions.append(
225
+ inquirer.List(
226
+ "serial",
227
+ message="Which serial port do you want to {action} ?",
228
+ choices=serialports,
229
+ other=True,
230
+ validate=lambda _, x: True if x else "Please select or enter a serial port", # type: ignore
231
+ )
232
+ )
233
+
234
+ return questions