mpflash 1.28.2__tar.gz → 1.28.4__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 (239) hide show
  1. {mpflash-1.28.2 → mpflash-1.28.4}/.github/workflows/pytest_mpflash.yml +3 -2
  2. mpflash-1.28.4/CHANGELOG.md +179 -0
  3. {mpflash-1.28.2 → mpflash-1.28.4}/PKG-INFO +16 -29
  4. {mpflash-1.28.2 → mpflash-1.28.4}/README.md +15 -28
  5. {mpflash-1.28.2 → mpflash-1.28.4}/justfile +1 -1
  6. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/basicgit.py +5 -0
  7. mpflash-1.28.4/mpflash/cli_erase.py +114 -0
  8. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/cli_flash.py +12 -0
  9. mpflash-1.28.4/mpflash/cli_format.py +115 -0
  10. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/cli_main.py +4 -0
  11. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/common.py +1 -0
  12. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/__init__.py +8 -0
  13. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/uf2/__init__.py +3 -1
  14. mpflash-1.28.4/mpflash/flash/builtins/uf2/boardid.py +36 -0
  15. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/uf2/erase.py +3 -3
  16. mpflash-1.28.4/mpflash/flash/format_fs.py +55 -0
  17. mpflash-1.28.4/mpflash/mpremoteboard/erase_bdev.py +118 -0
  18. mpflash-1.28.4/mpflash/mpremoteboard/format_bdev.py +159 -0
  19. {mpflash-1.28.2 → mpflash-1.28.4}/pyproject.toml +1 -1
  20. {mpflash-1.28.2 → mpflash-1.28.4}/tests/basicgit/test_basicgit.py +12 -0
  21. mpflash-1.28.4/tests/cli/test_cli_erase.py +105 -0
  22. {mpflash-1.28.2 → mpflash-1.28.4}/tests/cli/test_cli_flash.py +48 -0
  23. mpflash-1.28.4/tests/cli/test_cli_format.py +92 -0
  24. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_flash_tasks.py +42 -0
  25. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_flash_uf2_A.py +2 -0
  26. mpflash-1.28.4/tests/flash/test_format_fs.py +167 -0
  27. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_uf2_boardid.py +17 -1
  28. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_uf2_erase.py +10 -1
  29. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_cli_main.py +3 -3
  30. {mpflash-1.28.2 → mpflash-1.28.4}/uv.lock +1 -1
  31. mpflash-1.28.2/mpflash/flash/builtins/uf2/boardid.py +0 -15
  32. mpflash-1.28.2/mpflash/mpremoteboard/erase_bdev.py +0 -93
  33. {mpflash-1.28.2 → mpflash-1.28.4}/.all-contributorsrc +0 -0
  34. {mpflash-1.28.2 → mpflash-1.28.4}/.env +0 -0
  35. {mpflash-1.28.2 → mpflash-1.28.4}/.github/CODEOWNERS +0 -0
  36. {mpflash-1.28.2 → mpflash-1.28.4}/.github/codecov.yml +0 -0
  37. {mpflash-1.28.2 → mpflash-1.28.4}/.github/copilot-instructions.md +0 -0
  38. {mpflash-1.28.2 → mpflash-1.28.4}/.github/dependabot.yml +0 -0
  39. {mpflash-1.28.2 → mpflash-1.28.4}/.github/workflows/copilot-setup-steps.yml +0 -0
  40. {mpflash-1.28.2 → mpflash-1.28.4}/.github/workflows/dependency-review.yml +0 -0
  41. {mpflash-1.28.2 → mpflash-1.28.4}/.github/workflows/release.yml +0 -0
  42. {mpflash-1.28.2 → mpflash-1.28.4}/.gitignore +0 -0
  43. {mpflash-1.28.2 → mpflash-1.28.4}/.mailmap +0 -0
  44. {mpflash-1.28.2 → mpflash-1.28.4}/.readthedocs.yaml +0 -0
  45. {mpflash-1.28.2 → mpflash-1.28.4}/.vscode/extensions.json +0 -0
  46. {mpflash-1.28.2 → mpflash-1.28.4}/.vscode/launch.json +0 -0
  47. {mpflash-1.28.2 → mpflash-1.28.4}/.vscode/micropython-dict.txt +0 -0
  48. {mpflash-1.28.2 → mpflash-1.28.4}/.vscode/settings.json +0 -0
  49. {mpflash-1.28.2 → mpflash-1.28.4}/.vscode/tasks.json +0 -0
  50. {mpflash-1.28.2 → mpflash-1.28.4}/LICENSE +0 -0
  51. {mpflash-1.28.2 → mpflash-1.28.4}/docs/OIG4.jpg +0 -0
  52. {mpflash-1.28.2 → mpflash-1.28.4}/docs/api-reference.md +0 -0
  53. {mpflash-1.28.2 → mpflash-1.28.4}/docs/architecture.md +0 -0
  54. {mpflash-1.28.2 → mpflash-1.28.4}/docs/contributing.md +0 -0
  55. {mpflash-1.28.2 → mpflash-1.28.4}/docs/custom_firmware_prd.md +0 -0
  56. {mpflash-1.28.2 → mpflash-1.28.4}/docs/developer.md +0 -0
  57. {mpflash-1.28.2 → mpflash-1.28.4}/docs/index.md +0 -0
  58. {mpflash-1.28.2 → mpflash-1.28.4}/docs/logger_fixes.md +0 -0
  59. {mpflash-1.28.2 → mpflash-1.28.4}/docs/mpflash-2 (Small).jpg +0 -0
  60. {mpflash-1.28.2 → mpflash-1.28.4}/docs/mpflash-2.jpg +0 -0
  61. {mpflash-1.28.2 → mpflash-1.28.4}/docs/mpflash.jpg +0 -0
  62. {mpflash-1.28.2 → mpflash-1.28.4}/docs/mpflash_api_example.ipynb +0 -0
  63. {mpflash-1.28.2 → mpflash-1.28.4}/docs/mpremoteboard_api.md +0 -0
  64. {mpflash-1.28.2 → mpflash-1.28.4}/docs/startup_speed.md +0 -0
  65. {mpflash-1.28.2 → mpflash-1.28.4}/docs/stm32_udev_rules.md +0 -0
  66. {mpflash-1.28.2 → mpflash-1.28.4}/docs/troubleshooting.md +0 -0
  67. {mpflash-1.28.2 → mpflash-1.28.4}/examples/worklist_api_improvements.py +0 -0
  68. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/__init__.py +0 -0
  69. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/ask_input.py +0 -0
  70. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/bootloader/__init__.py +0 -0
  71. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/bootloader/activate.py +0 -0
  72. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/bootloader/base.py +0 -0
  73. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/bootloader/builtins/__init__.py +0 -0
  74. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/bootloader/builtins/manual.py +0 -0
  75. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/bootloader/builtins/mpy.py +0 -0
  76. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/bootloader/builtins/touch1200.py +0 -0
  77. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/bootloader/detect.py +0 -0
  78. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/bootloader/registry.py +0 -0
  79. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/build.py +0 -0
  80. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/cli_add.py +0 -0
  81. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/cli_download.py +0 -0
  82. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/cli_group.py +0 -0
  83. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/cli_list.py +0 -0
  84. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/cli_plugins.py +0 -0
  85. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/cli_pyocd.py +0 -0
  86. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/config.py +0 -0
  87. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/connected.py +0 -0
  88. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/custom/__init__.py +0 -0
  89. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/custom/add.py +0 -0
  90. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/custom/copy.py +0 -0
  91. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/custom/naming.py +0 -0
  92. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/db/__init__.py +0 -0
  93. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/db/boards_version.txt +0 -0
  94. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/db/core.py +0 -0
  95. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/db/gather_boards.py +0 -0
  96. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/db/loader.py +0 -0
  97. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/db/meta.py +0 -0
  98. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/db/micropython_boards.zip +0 -0
  99. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/db/models.py +0 -0
  100. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/db/tools.py +0 -0
  101. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/download/__init__.py +0 -0
  102. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/download/from_web.py +0 -0
  103. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/download/fwinfo.py +0 -0
  104. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/download/jid.py +0 -0
  105. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/downloaded.py +0 -0
  106. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/errors.py +0 -0
  107. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/base.py +0 -0
  108. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/__init__.py +0 -0
  109. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/dfu/__init__.py +0 -0
  110. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/dfu/stm32_dfu.py +0 -0
  111. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/dfu_backend.py +0 -0
  112. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/esp/__init__.py +0 -0
  113. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/esptool_backend.py +0 -0
  114. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/pyocd/__init__.py +0 -0
  115. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/pyocd/core.py +0 -0
  116. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/pyocd/flash.py +0 -0
  117. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/pyocd/probes.py +0 -0
  118. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/pyocd_backend.py +0 -0
  119. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/uf2/linux.py +0 -0
  120. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/uf2/macos.py +0 -0
  121. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/uf2/uf2disk.py +0 -0
  122. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/uf2/volume.py +0 -0
  123. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/uf2/windows.py +0 -0
  124. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/uf2/wsl2.py +0 -0
  125. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/builtins/uf2_backend.py +0 -0
  126. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/context.py +0 -0
  127. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/registry.py +0 -0
  128. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/services.py +0 -0
  129. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/flash/worklist.py +0 -0
  130. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/list.py +0 -0
  131. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/logger.py +0 -0
  132. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/mpboard_id/__init__.py +0 -0
  133. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/mpboard_id/alternate.py +0 -0
  134. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/mpboard_id/board_id.py +0 -0
  135. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/mpboard_id/known.py +0 -0
  136. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/mpboard_id/resolve.py +0 -0
  137. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/mpremoteboard/__init__.py +0 -0
  138. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/mpremoteboard/mpy_fw_info.py +0 -0
  139. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/mpremoteboard/runner.py +0 -0
  140. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/py.typed +0 -0
  141. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/udev_rules/49-stlinkv2-1.rules +0 -0
  142. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/udev_rules/49-stlinkv2.rules +0 -0
  143. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/udev_rules/49-stlinkv3.rules +0 -0
  144. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/udev_rules/49-vtlinkii.rules +0 -0
  145. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/udev_rules/49-wch-link.rules +0 -0
  146. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/udev_rules/50-cmsis-dap.rules +0 -0
  147. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/udev_rules/50-picoprobe.rules +0 -0
  148. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/udev_rules/65-mpflash-stm32-dfu.rules +0 -0
  149. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/udev_rules/README.md +0 -0
  150. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/vendor/board_database.py +0 -0
  151. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/vendor/click_aliases.py +0 -0
  152. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/vendor/dfu.py +0 -0
  153. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/vendor/pydfu.py +0 -0
  154. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/vendor/readme.md +0 -0
  155. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash/versions.py +0 -0
  156. {mpflash-1.28.2 → mpflash-1.28.4}/mpflash.code-workspace +0 -0
  157. {mpflash-1.28.2 → mpflash-1.28.4}/reporting/MicroPython_boards.ipynb +0 -0
  158. {mpflash-1.28.2 → mpflash-1.28.4}/reporting/build_reporting_db.py +0 -0
  159. {mpflash-1.28.2 → mpflash-1.28.4}/reporting/micropython_boards_reporting.sqlite3 +0 -0
  160. {mpflash-1.28.2 → mpflash-1.28.4}/scripts/Qry_board_id_to_versions.sqlite3-query +0 -0
  161. {mpflash-1.28.2 → mpflash-1.28.4}/scripts/Untitled-1.ipynb +0 -0
  162. {mpflash-1.28.2 → mpflash-1.28.4}/scripts/Untitled-1.sqlite3-query +0 -0
  163. {mpflash-1.28.2 → mpflash-1.28.4}/scripts/Untitled-2.sqlite3-query +0 -0
  164. {mpflash-1.28.2 → mpflash-1.28.4}/scripts/Untitled-3.sqlite3-query +0 -0
  165. {mpflash-1.28.2 → mpflash-1.28.4}/scripts/Untitled-4.sqlite3-query +0 -0
  166. {mpflash-1.28.2 → mpflash-1.28.4}/scripts/Untitled-6.sqlite3-query +0 -0
  167. {mpflash-1.28.2 → mpflash-1.28.4}/scripts/Untitled-7.sqlite3-query +0 -0
  168. {mpflash-1.28.2 → mpflash-1.28.4}/scripts/Untitled-8.sqlite3-query +0 -0
  169. {mpflash-1.28.2 → mpflash-1.28.4}/scripts/join_boards-downloads.sqlite3-query +0 -0
  170. {mpflash-1.28.2 → mpflash-1.28.4}/scripts/libusb_flash.ipynb +0 -0
  171. {mpflash-1.28.2 → mpflash-1.28.4}/scripts/micropython_boards.zip +0 -0
  172. {mpflash-1.28.2 → mpflash-1.28.4}/scripts/mpr_command.ipynb +0 -0
  173. {mpflash-1.28.2 → mpflash-1.28.4}/scripts/publish.py +0 -0
  174. {mpflash-1.28.2 → mpflash-1.28.4}/scripts/sqlite3.exe +0 -0
  175. {mpflash-1.28.2 → mpflash-1.28.4}/src/mpflash/db/gather_boards.py +0 -0
  176. {mpflash-1.28.2 → mpflash-1.28.4}/tests/basicgit_test.py +0 -0
  177. {mpflash-1.28.2 → mpflash-1.28.4}/tests/bootloader/test_bootloader_detect.py +0 -0
  178. {mpflash-1.28.2 → mpflash-1.28.4}/tests/bootloader/test_bootloader_registry.py +0 -0
  179. {mpflash-1.28.2 → mpflash-1.28.4}/tests/cli/test_cli_download.py +0 -0
  180. {mpflash-1.28.2 → mpflash-1.28.4}/tests/cli/test_cli_list.py +0 -0
  181. {mpflash-1.28.2 → mpflash-1.28.4}/tests/cli/test_cli_options.py +0 -0
  182. {mpflash-1.28.2 → mpflash-1.28.4}/tests/cli/test_cli_plugins.py +0 -0
  183. {mpflash-1.28.2 → mpflash-1.28.4}/tests/cli/test_cli_pyocd.py +0 -0
  184. {mpflash-1.28.2 → mpflash-1.28.4}/tests/conftest.py +0 -0
  185. {mpflash-1.28.2 → mpflash-1.28.4}/tests/custom/test_init.py +0 -0
  186. {mpflash-1.28.2 → mpflash-1.28.4}/tests/custom/test_naming.py +0 -0
  187. {mpflash-1.28.2 → mpflash-1.28.4}/tests/data/firmware.jsonl +0 -0
  188. {mpflash-1.28.2 → mpflash-1.28.4}/tests/data/mpflash.db +0 -0
  189. {mpflash-1.28.2 → mpflash-1.28.4}/tests/db/conftest.py +0 -0
  190. {mpflash-1.28.2 → mpflash-1.28.4}/tests/db/test_core.py +0 -0
  191. {mpflash-1.28.2 → mpflash-1.28.4}/tests/db/test_find_board_id.py +0 -0
  192. {mpflash-1.28.2 → mpflash-1.28.4}/tests/db/test_gather.py +0 -0
  193. {mpflash-1.28.2 → mpflash-1.28.4}/tests/db/test_loader.py +0 -0
  194. {mpflash-1.28.2 → mpflash-1.28.4}/tests/db/test_meta.py +0 -0
  195. {mpflash-1.28.2 → mpflash-1.28.4}/tests/db/test_tools.py +0 -0
  196. {mpflash-1.28.2 → mpflash-1.28.4}/tests/fixtures/mock_pyocd_data.py +0 -0
  197. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_boot_touch1200.py +0 -0
  198. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_dfu_backend.py +0 -0
  199. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_flash_1.py +0 -0
  200. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_flash_esp.py +0 -0
  201. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_registry.py +0 -0
  202. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_services.py +0 -0
  203. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_stm32_dfu.py +0 -0
  204. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_uf2_linux.py +0 -0
  205. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_uf2_mac.py +0 -0
  206. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_uf2_volume.py +0 -0
  207. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_uf2_windows.py +0 -0
  208. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_uf2_wsl2.py +0 -0
  209. {mpflash-1.28.2 → mpflash-1.28.4}/tests/flash/test_worklist_refactored.py +0 -0
  210. {mpflash-1.28.2 → mpflash-1.28.4}/tests/hw/conftest.py +0 -0
  211. {mpflash-1.28.2 → mpflash-1.28.4}/tests/hw/test_hw_backends.py +0 -0
  212. {mpflash-1.28.2 → mpflash-1.28.4}/tests/hw/test_hw_erase.py +0 -0
  213. {mpflash-1.28.2 → mpflash-1.28.4}/tests/integration/test_cli_integration.py +0 -0
  214. {mpflash-1.28.2 → mpflash-1.28.4}/tests/mpboard_id/test_alternate.py +0 -0
  215. {mpflash-1.28.2 → mpflash-1.28.4}/tests/mpboard_id/test_known_boards.py +0 -0
  216. {mpflash-1.28.2 → mpflash-1.28.4}/tests/mpremoteboard/fake_output.py +0 -0
  217. {mpflash-1.28.2 → mpflash-1.28.4}/tests/mpremoteboard/fake_reset.py +0 -0
  218. {mpflash-1.28.2 → mpflash-1.28.4}/tests/mpremoteboard/fake_slow_output.py +0 -0
  219. {mpflash-1.28.2 → mpflash-1.28.4}/tests/mpremoteboard/test_mprb.py +0 -0
  220. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_ask_input.py +0 -0
  221. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_build.py +0 -0
  222. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_cli_add.py +0 -0
  223. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_common.py +0 -0
  224. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_config.py +0 -0
  225. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_connected.py +0 -0
  226. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_download.py +0 -0
  227. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_downloaded.py +0 -0
  228. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_filtered_comports.py +0 -0
  229. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_gather_boards_additional.py +0 -0
  230. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_list.py +0 -0
  231. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_logger_fix.py +0 -0
  232. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_mp_board_filter.py +0 -0
  233. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_mpf_api.py +0 -0
  234. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_version_preservation_fix.py +0 -0
  235. {mpflash-1.28.2 → mpflash-1.28.4}/tests/test_versions.py +0 -0
  236. {mpflash-1.28.2 → mpflash-1.28.4}/tests/unit/test_probe_management.py +0 -0
  237. {mpflash-1.28.2 → mpflash-1.28.4}/tests/unit/test_pyocd_flash_coverage.py +0 -0
  238. {mpflash-1.28.2 → mpflash-1.28.4}/tests/unit/test_target_detection.py +0 -0
  239. {mpflash-1.28.2 → mpflash-1.28.4}/tests.md +0 -0
@@ -73,7 +73,7 @@ jobs:
73
73
  run: |
74
74
  # run once to bootstrap database (test hack)
75
75
  uv run mpflash download --board RPI_PICO
76
- b
76
+ uv run pytest --cov --cov-branch --cov-report=xml --junitxml=results/junit.xml
77
77
 
78
78
  #----------------------------------------------
79
79
  # upload coverage stats
@@ -90,8 +90,9 @@ jobs:
90
90
 
91
91
  - name: Upload test results to Codecov
92
92
  if: ${{ !cancelled() }}
93
- uses: codecov/test-results-action@v1
93
+ uses: codecov/codecov-action@v7
94
94
  with:
95
+ report_type: test_results
95
96
  token: ${{ secrets.CODECOV_TOKEN }}
96
97
  files: results/junit.xml
97
98
  fail_ci_if_error: false
@@ -0,0 +1,179 @@
1
+ # Changelog
2
+
3
+ All notable changes to mpflash are documented in this file.
4
+
5
+ ## [Unreleased]
6
+
7
+ ### Added
8
+
9
+ - **`--format` option for `mpflash flash`** — reformats the board's filesystem after
10
+ flashing, recreating an empty filesystem of the same type (`VfsLfs2` or `VfsFat`) via
11
+ the MicroPython block device. Supported on `rp2`, `esp32`, `esp8266`, `samd`, `stm32`,
12
+ `nrf` and `mimxrt`. The mount point and filesystem type are detected at runtime using
13
+ the same `vfs.mount()` enumeration as `mpremote df`.
14
+ - **`mpflash format` command** — reformats the filesystem of connected boards without
15
+ flashing new firmware. Asks for confirmation before erasing (skip with `--yes`) and
16
+ supports the same ports as `flash --format`.
17
+ - **`mpflash erase` command** — erases the filesystem of connected boards via the
18
+ MicroPython block device and reboots them, without flashing new firmware. Reuses the
19
+ `flash --erase` implementation. Asks for confirmation before erasing (skip with
20
+ `--yes`). Supported on `rp2`, `samd` and `nrf`.
21
+
22
+ ## [1.28.3] - 2026-07-26
23
+
24
+ This release is a major internal refactor of how mpflash flashes boards and enters
25
+ bootloaders, turning both into pluggable, port-agnostic backends — plus two big new
26
+ capabilities: local firmware builds via [**mpbuild**](https://github.com/mattytrentini/mpbuild#mpbuild) and SWD/JTAG flashing via [**pyOCD**](https://pyocd.io/).
27
+
28
+ ### Highlights
29
+
30
+ - **Pluggable flash backends and bootloader activation** shared across MicroPython ports (UF2, DFU, esptool, pyOCD).
31
+ - **mpbuild integration** — build firmware locally right before flashing. *(Andrew Leech & Jos Verlinde)*
32
+ - **pyOCD integration** — flash STM32 / RP2040 / SAMD over a debug probe. *(Andrew Leech & Jos Verlinde)*
33
+ - **`--erase` now uses the MicroPython block device** instead of vendored flash-nuke images.
34
+
35
+ ### Flash backend architecture
36
+
37
+ The monolithic flash logic (`mpflash/flash/stm32.py`, `esp.py`, `uf2/`) has been
38
+ reorganized into a registry of self-describing backends under `mpflash/flash/builtins/`
39
+ (`uf2_backend`, `dfu_backend`, `esptool_backend`, `pyocd_backend`), each declaring the
40
+ ports and firmware formats it supports and a priority. New `flash/registry.py`,
41
+ `flash/base.py`, `flash/context.py` and `flash/services.py` provide the shared plumbing,
42
+ and `flash_mcu(..., method=FlashMethod.<X>)` selects a backend automatically.
43
+
44
+ - New **`mpflash plugins`** command lists every registered backend and its support matrix (`--format table|plain`).
45
+ - `FlashMethod` enum added to `common.py`; `--method / --flash-method` gains `auto` (default) and `pyocd`.
46
+ - Third-party backends can register via entry points.
47
+
48
+ ### Bootloader activation plugins
49
+
50
+ Bootloader entry has been refactored into a plugin structure (`bootloader/registry.py`,
51
+ `bootloader/base.py`, `bootloader/builtins/` with `manual`, `touch1200` and a new `mpy`
52
+ MicroPython-reset activator). Detection (`bootloader/detect.py`) was reworked, and a bug
53
+ was fixed where, if the serial port disappeared after an activator (board already reset
54
+ into its UF2 bootloader), mpflash would incorrectly fall through to a touch-1200 on a
55
+ now-missing port — it now re-checks bootloader state and waits for the UF2 volume to
56
+ mount before reporting success.
57
+
58
+ ### mpbuild integration (build firmware locally) — *Andrew Leech & Jos Verlinde*
59
+
60
+ New `mpflash/build.py` with a `BuildManager` that builds MicroPython firmware on demand:
61
+
62
+ - New flash flags: **`--build`** (build with mpbuild before flashing) and **`--clean`** (run `mpbuild clean` first).
63
+ - Build caching, dependency validation (checks for mpbuild + Docker), and per-port
64
+ preferred output formats (e.g. `.bin` for esptool, `.uf2` for UF2, `.dfu/.bin` for DFU,
65
+ `.bin/.hex/.elf/.axf` for pyOCD).
66
+ - Built artifacts are imported into the mpflash firmware database and a ready-to-run
67
+ `mpflash flash …` command is printed so you can re-flash without rebuilding.
68
+
69
+ ### pyOCD integration (SWD/JTAG flashing) — *Andrew Leech & Jos Verlinde*
70
+
71
+ Flash STM32, RP2040 and SAMD boards through a CMSIS-DAP / ST-Link / J-Link probe
72
+ (`flash/builtins/pyocd/`):
73
+
74
+ - New flash options: **`--method pyocd`**, **`--probe / --probe-id`**, **`--target`**
75
+ (explicit pyOCD target override) and **`--auto-install-packs / --no-auto-install-packs`** (default on).
76
+ - Probe discovery, MCU-info parsing with fuzzy target matching, dynamic target detection,
77
+ and automatic CMSIS pack installation for missing targets.
78
+ - New commands: **`mpflash list-probes`**, **`mpflash pyocd-info`**, **`mpflash pyocd-targets`**
79
+ (with `--board-filter` / `--target-filter`).
80
+ - ESP32/ESP8266 are intentionally excluded (use esptool).
81
+ - Extensive unit tests with mocked hardware so the suite runs without a probe or pyOCD installed.
82
+
83
+ ### Filesystem erase via serial block device
84
+
85
+ `--erase` no longer relies on `universal_flash_nuke.uf2` for rp2xxx boards, or a post-flash
86
+ `rm -r :` on others. Instead `mpremoteboard/erase_bdev.py` erases the filesystem block
87
+ device using `mpremoteboard/erase_bdev.py` and calls `machine.reset()`, leaving the board with a
88
+ fresh filesystem. Bootloader entry is now a separate, explicit step, and `flash_uf2` only
89
+ copies firmware.
90
+ The previously vendored pico-universal-flash-nuke image by @Gadgetoid is no longer needed.
91
+
92
+ ### UF2 reliability fixes
93
+
94
+ - **Windows drive detection** uses `psutil.disk_partitions(all=True)` and polls twice per
95
+ second so a freshly-mounted removable volume isn't filtered out or missed.
96
+ - **`wait_for_restart()` now returns a bool** via a bounded quiet probe, so callers can
97
+ detect when a board never reconnects.
98
+ - **No more false "copy failed" retries**: mpflash stopped copying file metadata to UF2
99
+ destinations — the bootloader could consume the firmware and disconnect before the
100
+ metadata step, causing a false failure and three useless retries.
101
+
102
+ ### Board & port detection
103
+
104
+ - Added `best_matching_port` and a `sys_platform` attribute to `MPRemoteBoard`, improving
105
+ reconnection to the correct serial port after a reset.
106
+ - Additional known-board mappings.
107
+
108
+ ### Configuration & environment
109
+
110
+ - Loads environment variables from a **`.env`** file and expands `~` in user-supplied paths.
111
+
112
+ ### Linux / udev rules
113
+
114
+ - Bundled udev rules for ST-Link v2 / v2-1 / v3, WCH-Link, CMSIS-DAP, picoprobe and STM32
115
+ DFU (`mpflash/udev_rules/`, with a README), and expanded `docs/stm32_udev_rules.md` to
116
+ cover the debug probes needed by pyOCD.
117
+
118
+ ### Security & quality
119
+
120
+ - Removed use of `eval()` in favor of safe parsing, plus reformatting/cleanups.
121
+
122
+ ### Tooling, CI & docs
123
+
124
+ - **Automated release process**: pushing a `v*` tag triggers build + PyPI trusted
125
+ publishing + GitHub release; new `just release` recipe runs tests, bumps the version,
126
+ tags and pushes. Documented in `docs/developer.md` and `docs/contributing.md`.
127
+ - CI installs all extras and uploads coverage + JUnit test results to Codecov; new **HIL
128
+ testing** support (`--HIL <port>` pytest option and `just hil_*` targets) with a hardware
129
+ filesystem-erase test.
130
+ - Dependency bumps: `actions/checkout` 4→7, `actions/setup-python` 6→7,
131
+ `actions/upload-artifact` 4→7, `actions/download-artifact` 4→8, `astral-sh/setup-uv` 6→7.
132
+
133
+ ### Dependencies
134
+
135
+ - Added `python-dotenv>=1.0.0`.
136
+ - New optional **`pyocd`** extra: `pyocd>=0.44.1`, `mpbuild>=1.0.0` (Python ≥ 3.12) /
137
+ `mpbuild>=0.5.0,<1.0.0` (Python < 3.12). Install with `uv sync --extra pyocd` or
138
+ `pip install "mpflash[pyocd]"`.
139
+
140
+ ### Upgrade notes / breaking changes
141
+
142
+ - **Internal flash modules moved** under `mpflash/flash/builtins/…` (e.g. `flash/stm32.py`
143
+ → `flash/builtins/dfu/`, `flash/esp.py` → `flash/builtins/esp/`, `flash/uf2/` →
144
+ `flash/builtins/uf2/`). Use the public `mpflash.flash.flash_mcu(method=…)` entry point
145
+ rather than importing these paths directly.
146
+ - **`--erase` is now a serial block-device erase** (board must be reachable on
147
+ MicroPython), not a flash-nuke image; the vendored `universal_flash_nuke.uf2` was removed.
148
+
149
+ ## [1.26.0] - Breaking API changes
150
+
151
+ **Important for library users**: the worklist module API was completely refactored, with
152
+ breaking changes. Legacy worklist functions were **removed**.
153
+
154
+ ### Removed
155
+
156
+ - `auto_update_worklist()`, `manual_worklist()`, `manual_board()`,
157
+ `single_auto_worklist()`, `full_auto_worklist()`, `filter_boards()`.
158
+
159
+ ### Changed
160
+
161
+ - New modern interface with `create_worklist()`, the `FlashTask` dataclass and
162
+ `WorklistConfig` objects. See `docs/api-reference.md` for the migration guide.
163
+ - The command-line interface remains fully compatible.
164
+
165
+ ## [1.25.0.post2]
166
+
167
+ ### Added
168
+
169
+ - `--variant` option to select a specific board variant when flashing.
170
+ - SQLite database storing information on all possible MicroPython firmwares and the
171
+ management of downloaded firmware files, for better board identification and firmware matching.
172
+ - Use the MicroPython v1.25.0 `sys.implementation._build` as `board_id` when available.
173
+ - Automatic firmware download when not yet available locally (no longer need the `--download` option).
174
+
175
+ ### Changed
176
+
177
+ - Restructured `mpboard_id` to use a SQLite database to identify more boards and variants.
178
+ - Vendored and adapted `board_database.py` from mpflash — kudos @mattytrentini.
179
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mpflash
3
- Version: 1.28.2
3
+ Version: 1.28.4
4
4
  Summary: Flash and download tool for MicroPython firmwares
5
5
  Project-URL: Homepage, https://github.com/Josverl/mpflash
6
6
  Project-URL: Documentation, https://github.com/Josverl/mpflash/blob/main/README.md
@@ -92,38 +92,23 @@ The interactive prompts use [**rich-inquirer**](https://pypi.org/project/rich-in
92
92
  - `esp32`, using `.bin`, using esptool,
93
93
  - `esp8266`, using `.bin`, using esptool
94
94
  - `stm32`, using ` .dfu`, using pydfu (also in Windows)
95
+ - `nrf`, using `.uf2`, using filecopy
95
96
 
96
- Not yet implemented: `nrf`, `cc3200`, `mimxrt`, `renesas`
97
+ Not yet implemented: `alif`, `mimxrt`, `psoc-edge`, `renesas-ra`, `zephyr`
98
+ Not planned: `cc3200`, `pic16bit`
97
99
 
98
- ## Release v1.25.0(.post2)
99
-
100
- This release includes several new features and improvements:
101
- - **New features:**
102
- - Added support for `--variant` option to specify a specific variant of the board when flashing.
103
- - mpflash now uses a slqlite database to store information on all possible micropython firmwares, and the management of the downloaded firmware files.
104
- - This allows for a better identification of boards, and matches to the correct firmware.
105
- - Use the MicroPython v1.25.0 `sys.implementation._build` to as board_id when avaialable
106
- - Automatically try to download firmware if not yet available locally. No lonmger need to specify the `--download` option.
107
- - Restructured mpboard_id to use a SQLite db to be able to ID more boards and variants
108
- - vendored and adapted `board_database.py` from mpflash, kudos @mattytrentini
109
-
110
- ## ⚠️ Breaking API Changes (v1.26+)
111
-
112
- **Important for Library Users**: The worklist module API has been completely refactored with breaking changes.
113
- Legacy worklist functions have been **removed**.
114
-
115
- - **Removed Functions**: `auto_update_worklist()`, `manual_worklist()`, `manual_board()`, `single_auto_worklist()`, `full_auto_worklist()`, `filter_boards()`
116
- - **New API**: Modern interface with `create_worklist()`, `FlashTask` dataclass, and `WorklistConfig` objects
117
- - **CLI Unchanged**: Command-line interface remains fully compatible
100
+ ## Features
118
101
 
119
- See [API Documentation](docs/api-reference.md) for complete migration guide.
102
+ - **List connected boards** — show firmware details for all attached boards in a table or JSON format.
103
+ - **Download firmware** — fetch MicroPython firmware for a version, matched to a specified board or your attached board(s).
104
+ - **Flash boards** — flash one or all connected boards with a specific firmware or version, downloading it if needed.
105
+ - **Flash via a debug probe (pyOCD)** — program `stm32`, `rp2` and `samd` targets over SWD/JTAG using a CMSIS-DAP / ST-Link / J-Link probe with `mpflash flash --method pyocd`. CMSIS packs for missing targets are installed automatically. Install with `pip install "mpflash[pyocd]"`.
106
+ - **Build firmware locally (mpbuild)** — use `mpflash flash --build` to compile MicroPython with [mpbuild](https://pypi.org/project/mpbuild/) (requires Docker) right before flashing.
107
+ - **Pluggable flash & bootloader backends** — flashing and bootloader activation are selectable, port-agnostic plugins, and third-party backends can register their own. List them with `mpflash plugins`.
108
+ - **Filesystem erase over serial** — `--erase` wipes the MicroPython filesystem via its block device.
109
+ - **Filesystem format over serial** — `--format` recreates an empty MicroPython filesystem after flashing, keeping the same filesystem type (`VfsLfs2` or `VfsFat`).
110
+ - **Probe & target info** — inspect probes and supported targets with `mpflash list-probes`, `mpflash pyocd-info` and `mpflash pyocd-targets`.
120
111
 
121
-
122
- ## Features
123
- 1. List the connected boards including their firmware details, in a tabular or json format
124
- 2. Download MicroPython firmware for versions, and matching a specified board or matches your current attached board.
125
- 3. Flash one or all connected MicroPython boards with a specific firmware or version.
126
-
127
112
  ## Installation
128
113
  To install mpflash, you can use either of the following commands:
129
114
  - `uv tool install mpflash`
@@ -138,6 +123,8 @@ You can use mpflash to perform various operations on your MicroPython boards. He
138
123
  | `mpflash list` | List the connected board(s) including their firmware details |
139
124
  | `mpflash flash` | Flash the latest stable firmware to the connected board(s), downloading the firmware if needed |
140
125
  | `mpflash download` | Download the MicroPython firmware(s) for the connected board(s) |
126
+ | `mpflash format` | Reformat the filesystem of the connected board(s) without flashing new firmware |
127
+ | `mpflash erase` | Erase the filesystem of the connected board(s) and reboot, without flashing new firmware |
141
128
 
142
129
  **Listing connected boards:**
143
130
  `mpflash list` will list all connected boards in a table , including their serial port, family, board name, CPU, version and build number.
@@ -18,38 +18,23 @@ The interactive prompts use [**rich-inquirer**](https://pypi.org/project/rich-in
18
18
  - `esp32`, using `.bin`, using esptool,
19
19
  - `esp8266`, using `.bin`, using esptool
20
20
  - `stm32`, using ` .dfu`, using pydfu (also in Windows)
21
+ - `nrf`, using `.uf2`, using filecopy
21
22
 
22
- Not yet implemented: `nrf`, `cc3200`, `mimxrt`, `renesas`
23
+ Not yet implemented: `alif`, `mimxrt`, `psoc-edge`, `renesas-ra`, `zephyr`
24
+ Not planned: `cc3200`, `pic16bit`
23
25
 
24
- ## Release v1.25.0(.post2)
25
-
26
- This release includes several new features and improvements:
27
- - **New features:**
28
- - Added support for `--variant` option to specify a specific variant of the board when flashing.
29
- - mpflash now uses a slqlite database to store information on all possible micropython firmwares, and the management of the downloaded firmware files.
30
- - This allows for a better identification of boards, and matches to the correct firmware.
31
- - Use the MicroPython v1.25.0 `sys.implementation._build` to as board_id when avaialable
32
- - Automatically try to download firmware if not yet available locally. No lonmger need to specify the `--download` option.
33
- - Restructured mpboard_id to use a SQLite db to be able to ID more boards and variants
34
- - vendored and adapted `board_database.py` from mpflash, kudos @mattytrentini
35
-
36
- ## ⚠️ Breaking API Changes (v1.26+)
37
-
38
- **Important for Library Users**: The worklist module API has been completely refactored with breaking changes.
39
- Legacy worklist functions have been **removed**.
40
-
41
- - **Removed Functions**: `auto_update_worklist()`, `manual_worklist()`, `manual_board()`, `single_auto_worklist()`, `full_auto_worklist()`, `filter_boards()`
42
- - **New API**: Modern interface with `create_worklist()`, `FlashTask` dataclass, and `WorklistConfig` objects
43
- - **CLI Unchanged**: Command-line interface remains fully compatible
26
+ ## Features
44
27
 
45
- See [API Documentation](docs/api-reference.md) for complete migration guide.
28
+ - **List connected boards** — show firmware details for all attached boards in a table or JSON format.
29
+ - **Download firmware** — fetch MicroPython firmware for a version, matched to a specified board or your attached board(s).
30
+ - **Flash boards** — flash one or all connected boards with a specific firmware or version, downloading it if needed.
31
+ - **Flash via a debug probe (pyOCD)** — program `stm32`, `rp2` and `samd` targets over SWD/JTAG using a CMSIS-DAP / ST-Link / J-Link probe with `mpflash flash --method pyocd`. CMSIS packs for missing targets are installed automatically. Install with `pip install "mpflash[pyocd]"`.
32
+ - **Build firmware locally (mpbuild)** — use `mpflash flash --build` to compile MicroPython with [mpbuild](https://pypi.org/project/mpbuild/) (requires Docker) right before flashing.
33
+ - **Pluggable flash & bootloader backends** — flashing and bootloader activation are selectable, port-agnostic plugins, and third-party backends can register their own. List them with `mpflash plugins`.
34
+ - **Filesystem erase over serial** — `--erase` wipes the MicroPython filesystem via its block device.
35
+ - **Filesystem format over serial** — `--format` recreates an empty MicroPython filesystem after flashing, keeping the same filesystem type (`VfsLfs2` or `VfsFat`).
36
+ - **Probe & target info** — inspect probes and supported targets with `mpflash list-probes`, `mpflash pyocd-info` and `mpflash pyocd-targets`.
46
37
 
47
-
48
- ## Features
49
- 1. List the connected boards including their firmware details, in a tabular or json format
50
- 2. Download MicroPython firmware for versions, and matching a specified board or matches your current attached board.
51
- 3. Flash one or all connected MicroPython boards with a specific firmware or version.
52
-
53
38
  ## Installation
54
39
  To install mpflash, you can use either of the following commands:
55
40
  - `uv tool install mpflash`
@@ -64,6 +49,8 @@ You can use mpflash to perform various operations on your MicroPython boards. He
64
49
  | `mpflash list` | List the connected board(s) including their firmware details |
65
50
  | `mpflash flash` | Flash the latest stable firmware to the connected board(s), downloading the firmware if needed |
66
51
  | `mpflash download` | Download the MicroPython firmware(s) for the connected board(s) |
52
+ | `mpflash format` | Reformat the filesystem of the connected board(s) without flashing new firmware |
53
+ | `mpflash erase` | Erase the filesystem of the connected board(s) and reboot, without flashing new firmware |
67
54
 
68
55
  **Listing connected boards:**
69
56
  `mpflash list` will list all connected boards in a table , including their serial port, family, board name, CPU, version and build number.
@@ -47,7 +47,7 @@ release bump="patch":
47
47
  git add pyproject.toml uv.lock
48
48
  git commit -m "Release v$(uv version --short)"
49
49
  git tag -a "v$(uv version --short)" -m "Release v$(uv version --short)"
50
- git push --follow-tags
50
+ git push --follow-tags --force
51
51
 
52
52
  # manual fallback: publish to PyPI directly (normally handled by GitHub Actions on tag push)
53
53
  [confirm("Are you sure you want to publish to PyPI directly? This is normally handled by GitHub Actions on tag push. Continue?")]
@@ -99,6 +99,11 @@ def get_local_tag(repo: Optional[Union[str, Path]] = None, abbreviate: bool = Tr
99
99
  tag = tag.replace("\r", "").replace("\n", "")
100
100
  if not abbreviate or "-" not in tag:
101
101
  return tag
102
+ # A dirty working tree (e.g. modified git submodules) is a working-tree state
103
+ # marker added by `git describe --dirty`, not part of the version. Drop it so a
104
+ # checkout that is exactly on a tag is not misread as a dev/preview build.
105
+ if tag.endswith("-dirty"):
106
+ tag = tag[: -len("-dirty")]
102
107
  if "-preview" in tag:
103
108
  tag = tag.split("-preview")[0] + "-preview"
104
109
  return tag
@@ -0,0 +1,114 @@
1
+ """CLI command to erase the filesystem of connected MicroPython boards.
2
+
3
+ Reuses the ``--erase`` filesystem implementation: it runs the on-device erase
4
+ script via ``mpremote`` on each selected board, wiping the filesystem block
5
+ device and rebooting the board (``machine.reset()``) without flashing firmware.
6
+ """
7
+
8
+ from typing import List
9
+
10
+ import rich_click as click
11
+
12
+ from .cli_group import cli
13
+ from .config import config
14
+ from .logger import log
15
+
16
+
17
+ @cli.command(
18
+ "erase",
19
+ short_help="Erase the filesystem of connected MicroPython boards and reboot (erases all files).",
20
+ )
21
+ @click.option(
22
+ "--serial",
23
+ "--serial-port",
24
+ "-s",
25
+ "serial",
26
+ default=["*"],
27
+ multiple=True,
28
+ show_default=True,
29
+ help="Which serial port(s) (or globs) to erase.",
30
+ metavar="SERIALPORT",
31
+ )
32
+ @click.option(
33
+ "--ignore",
34
+ "-i",
35
+ is_eager=True,
36
+ help="Serial port(s) to ignore. Defaults to MPFLASH_IGNORE.",
37
+ multiple=True,
38
+ default=[],
39
+ envvar="MPFLASH_IGNORE",
40
+ show_default=True,
41
+ metavar="SERIALPORT",
42
+ )
43
+ @click.option(
44
+ "--bluetooth/--no-bluetooth",
45
+ "--bt/--no-bt",
46
+ is_flag=True,
47
+ default=False,
48
+ show_default=True,
49
+ help="""Include bluetooth ports in the list""",
50
+ )
51
+ @click.option(
52
+ "--yes",
53
+ "-y",
54
+ "assume_yes",
55
+ is_flag=True,
56
+ default=False,
57
+ show_default=True,
58
+ help="""Do not ask for confirmation before erasing.""",
59
+ )
60
+ @click.pass_context
61
+ def cli_erase_board(
62
+ ctx: click.Context,
63
+ serial: List[str],
64
+ ignore: List[str],
65
+ bluetooth: bool,
66
+ assume_yes: bool,
67
+ ) -> int:
68
+ """Erase the filesystem of connected MicroPython boards and reboot, without flashing firmware."""
69
+ from rich.prompt import Confirm
70
+
71
+ from .connected import list_mcus
72
+ from .flash.builtins.uf2.erase import SUPPORTED_PORTS, erase_filesystem
73
+ from .list import show_mcus
74
+
75
+ serial = list(serial)
76
+ ignore = list(ignore)
77
+
78
+ conn_mcus = [mcu for mcu in list_mcus(ignore=ignore, include=serial, bluetooth=bluetooth) if mcu.connected]
79
+ # ignore boards that have the [mpflash] ignore flag set
80
+ conn_mcus = [mcu for mcu in conn_mcus if not (mcu.toml.get("mpflash", {}).get("ignore", False))]
81
+
82
+ if not conn_mcus:
83
+ log.error("No connected MicroPython boards found to erase.")
84
+ ctx.exit(1)
85
+
86
+ # Only boards on a port with a known filesystem block device can be erased.
87
+ to_erase = [mcu for mcu in conn_mcus if mcu.port in SUPPORTED_PORTS]
88
+ for mcu in conn_mcus:
89
+ if mcu.port not in SUPPORTED_PORTS:
90
+ log.warning(f"Skipping {mcu.board} on {mcu.serialport}: erase is not supported for port {mcu.port!r}")
91
+
92
+ if not to_erase:
93
+ log.error(f"None of the connected boards support erasing (supported: {', '.join(sorted(SUPPORTED_PORTS))}).")
94
+ ctx.exit(1)
95
+
96
+ show_mcus(to_erase, title="Boards to erase", refresh=False)
97
+
98
+ if not assume_yes and config.interactive:
99
+ if not Confirm.ask("Erasing wipes ALL files on the selected board(s) and reboots it. Continue?", default=False):
100
+ log.info("Erase cancelled by user.")
101
+ ctx.exit(2)
102
+
103
+ erased = []
104
+ for mcu in to_erase:
105
+ if erase_filesystem(mcu):
106
+ erased.append(mcu)
107
+ else:
108
+ log.error(f"Failed to erase {mcu.board} on {mcu.serialport}")
109
+
110
+ if erased:
111
+ log.info(f"Erased {len(erased)} board(s)")
112
+ ctx.exit(0)
113
+ log.error("No boards were erased")
114
+ ctx.exit(1)
@@ -105,6 +105,13 @@ from mpflash.versions import clean_version
105
105
  show_default=True,
106
106
  help="""Erase flash before writing new firmware.""",
107
107
  )
108
+ @click.option(
109
+ "--format/--no-format",
110
+ "format_fs",
111
+ default=False,
112
+ show_default=True,
113
+ help="""Reformat the board's filesystem after flashing (erases all files).""",
114
+ )
108
115
  @click.option(
109
116
  "--bootloader",
110
117
  "--bl",
@@ -263,6 +270,10 @@ def cli_flash_board(ctx: click.Context, **kwargs) -> int:
263
270
  params.bootloader = BootloaderMethod(params.bootloader)
264
271
  reflash_commands: List[str] = []
265
272
 
273
+ # --erase and --format are mutually exclusive; only one makes sense at a time.
274
+ if params.erase and params.format_fs:
275
+ raise click.UsageError("--erase and --format cannot be used together; specify only one.")
276
+
266
277
  # make it simple for the user to flash one board by asking for the serial port if not specified
267
278
  if params.boards == ["?"] or params.serial == "?": # or params.variant == "?":
268
279
  params.serial = ["?"]
@@ -474,6 +485,7 @@ def cli_flash_board(ctx: click.Context, **kwargs) -> int:
474
485
  params.erase,
475
486
  params.bootloader,
476
487
  method=flash_method,
488
+ format_fs=params.format_fs,
477
489
  probe_id=probe_id,
478
490
  auto_install_packs=auto_install_packs,
479
491
  target_override=pyocd_target,
@@ -0,0 +1,115 @@
1
+ """CLI command to reformat the filesystem of connected MicroPython boards.
2
+
3
+ Runs the on-device format script via ``mpremote`` on each selected board,
4
+ recreating an empty filesystem of the same type without flashing new firmware.
5
+ """
6
+
7
+ from typing import List
8
+
9
+ import rich_click as click
10
+
11
+ from .cli_group import cli
12
+ from .config import config
13
+ from .errors import MPFlashError
14
+ from .logger import log
15
+
16
+
17
+ @cli.command(
18
+ "format",
19
+ short_help="Reformat the filesystem of connected MicroPython boards (erases all files).",
20
+ )
21
+ @click.option(
22
+ "--serial",
23
+ "--serial-port",
24
+ "-s",
25
+ "serial",
26
+ default=["*"],
27
+ multiple=True,
28
+ show_default=True,
29
+ help="Which serial port(s) (or globs) to format.",
30
+ metavar="SERIALPORT",
31
+ )
32
+ @click.option(
33
+ "--ignore",
34
+ "-i",
35
+ is_eager=True,
36
+ help="Serial port(s) to ignore. Defaults to MPFLASH_IGNORE.",
37
+ multiple=True,
38
+ default=[],
39
+ envvar="MPFLASH_IGNORE",
40
+ show_default=True,
41
+ metavar="SERIALPORT",
42
+ )
43
+ @click.option(
44
+ "--bluetooth/--no-bluetooth",
45
+ "--bt/--no-bt",
46
+ is_flag=True,
47
+ default=False,
48
+ show_default=True,
49
+ help="""Include bluetooth ports in the list""",
50
+ )
51
+ @click.option(
52
+ "--yes",
53
+ "-y",
54
+ "assume_yes",
55
+ is_flag=True,
56
+ default=False,
57
+ show_default=True,
58
+ help="""Do not ask for confirmation before formatting.""",
59
+ )
60
+ @click.pass_context
61
+ def cli_format_board(
62
+ ctx: click.Context,
63
+ serial: List[str],
64
+ ignore: List[str],
65
+ bluetooth: bool,
66
+ assume_yes: bool,
67
+ ) -> int:
68
+ """Reformat the filesystem of connected MicroPython boards without flashing firmware."""
69
+ from rich.prompt import Confirm
70
+
71
+ from .connected import list_mcus
72
+ from .flash.format_fs import SUPPORTED_FORMAT_PORTS, format_filesystem
73
+ from .list import show_mcus
74
+
75
+ serial = list(serial)
76
+ ignore = list(ignore)
77
+
78
+ conn_mcus = [mcu for mcu in list_mcus(ignore=ignore, include=serial, bluetooth=bluetooth) if mcu.connected]
79
+ # ignore boards that have the [mpflash] ignore flag set
80
+ conn_mcus = [mcu for mcu in conn_mcus if not (mcu.toml.get("mpflash", {}).get("ignore", False))]
81
+
82
+ if not conn_mcus:
83
+ log.error("No connected MicroPython boards found to format.")
84
+ ctx.exit(1)
85
+
86
+ # Only boards on a port with a known filesystem block device can be formatted.
87
+ to_format = [mcu for mcu in conn_mcus if mcu.port in SUPPORTED_FORMAT_PORTS]
88
+ for mcu in conn_mcus:
89
+ if mcu.port not in SUPPORTED_FORMAT_PORTS:
90
+ log.warning(f"Skipping {mcu.board} on {mcu.serialport}: format is not supported for port {mcu.port!r}")
91
+
92
+ if not to_format:
93
+ log.error(f"None of the connected boards support formatting (supported: {', '.join(sorted(SUPPORTED_FORMAT_PORTS))}).")
94
+ ctx.exit(1)
95
+
96
+ show_mcus(to_format, title="Boards to format", refresh=False)
97
+
98
+ if not assume_yes and config.interactive:
99
+ if not Confirm.ask("Formatting erases ALL files on the selected board(s). Continue?", default=False):
100
+ log.info("Format cancelled by user.")
101
+ ctx.exit(2)
102
+
103
+ formatted = []
104
+ for mcu in to_format:
105
+ try:
106
+ if format_filesystem(mcu):
107
+ formatted.append(mcu)
108
+ except MPFlashError as e:
109
+ log.error(f"Failed to format {mcu.board} on {mcu.serialport}: {e}")
110
+
111
+ if formatted:
112
+ log.info(f"Formatted {len(formatted)} board(s)")
113
+ ctx.exit(0)
114
+ log.error("No boards were formatted")
115
+ ctx.exit(1)
@@ -21,7 +21,9 @@ from mpflash.errors import MPFlashError
21
21
 
22
22
  from .cli_add import cli_add_custom
23
23
  from .cli_download import cli_download
24
+ from .cli_erase import cli_erase_board
24
25
  from .cli_flash import cli_flash_board
26
+ from .cli_format import cli_format_board
25
27
  from .cli_group import cli
26
28
  from .cli_list import cli_list_mcus
27
29
  from . import cli_pyocd # noqa: F401 - registers pyOCD subcommands via @cli.command
@@ -37,6 +39,8 @@ def mpflash():
37
39
  cli.add_command(cli_download)
38
40
  cli.add_command(cli_flash_board)
39
41
  cli.add_command(cli_add_custom)
42
+ cli.add_command(cli_format_board)
43
+ cli.add_command(cli_erase_board)
40
44
 
41
45
  # cli(auto_envvar_prefix="MPFLASH")
42
46
  if False and os.environ.get("COMPUTERNAME").upper().startswith("JOSVERL"):
@@ -72,6 +72,7 @@ class FlashParams(Params):
72
72
  """Parameters for flashing a board"""
73
73
 
74
74
  erase: bool = True
75
+ format_fs: bool = False
75
76
  bootloader: BootloaderMethod = BootloaderMethod.NONE
76
77
  cpu: str = ""
77
78
  flash_mode: str = "keep" # keep, qio, qout, dio, dout
@@ -62,6 +62,7 @@ def flash_tasks(
62
62
  erase: bool,
63
63
  bootloader: BootloaderMethod,
64
64
  method: FlashMethod = FlashMethod.AUTO,
65
+ format_fs: bool = False,
65
66
  **kwargs,
66
67
  ):
67
68
  """Flash every entry in ``tasks`` and return the updated boards."""
@@ -236,6 +237,13 @@ def flash_tasks(
236
237
  else:
237
238
  mcu.toml["mpflash"].pop("custom_id", None)
238
239
  mcu.set_board_info_toml()
240
+ if format_fs:
241
+ from mpflash.flash.format_fs import format_filesystem
242
+
243
+ try:
244
+ format_filesystem(updated)
245
+ except MPFlashError as e:
246
+ log.error(f"Failed to format filesystem on {mcu.serialport}: {e}")
239
247
  flashed.append(updated)
240
248
  else:
241
249
  log.error(f"Failed to flash {mcu.board} on {mcu.serialport}")