micropython-stubber 1.20.0__py3-none-any.whl → 1.20.1__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.
@@ -1,203 +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
- }
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
+ }
@@ -12,7 +12,7 @@ from typing import Dict, List, Sequence, Tuple, Union
12
12
  from loguru import logger as log
13
13
 
14
14
  from mpflash.config import config
15
- from mpflash.mpboard_id import known_stored_boards, local_mp_ports
15
+ from mpflash.mpboard_id import get_stored_boards_for_port, known_stored_boards, local_mp_ports
16
16
  from mpflash.mpremoteboard import MPRemoteBoard
17
17
  from mpflash.vendor.versions import micropython_versions
18
18
 
@@ -131,7 +131,7 @@ def filter_matching_boards(answers: dict) -> Sequence[Tuple[str, str]]:
131
131
  # Get the values of the dictionary, which are the unique items from the original list
132
132
  some_boards = list(unique_dict.values())
133
133
  else:
134
- some_boards = [("No boards found", "")]
134
+ some_boards = [(f"No {answers['port']} boards found for version(s) {_versions}", "")]
135
135
  return some_boards
136
136
 
137
137
 
@@ -186,12 +186,27 @@ def ask_versions(questions: list, *, action: str):
186
186
  """
187
187
  # import only when needed to reduce load time
188
188
  import inquirer
189
+ import inquirer.errors
189
190
 
190
191
  input_ux = inquirer.Checkbox if action == "download" else inquirer.List
191
192
  mp_versions: List[str] = micropython_versions()
192
193
  mp_versions = [v for v in mp_versions if "preview" not in v]
194
+
195
+ # remove the versions for which there are no known boards in the board_info.json
196
+ # todo: this may be a little slow
197
+ mp_versions = [v for v in mp_versions if get_stored_boards_for_port("stm32", [v])]
198
+
193
199
  mp_versions.append("preview")
194
200
  mp_versions.reverse() # newest first
201
+
202
+ def at_least_one_validation(answers, current) -> bool:
203
+ if not current:
204
+ raise inquirer.errors.ValidationError("", reason="Please select at least one version")
205
+ if isinstance(current, list):
206
+ if not any(current):
207
+ raise inquirer.errors.ValidationError("", reason="Please select at least one version")
208
+ return True
209
+
195
210
  questions.append(
196
211
  input_ux(
197
212
  # inquirer.List(
@@ -201,7 +216,7 @@ def ask_versions(questions: list, *, action: str):
201
216
  # hints=["Use space to select multiple options"],
202
217
  choices=mp_versions,
203
218
  autocomplete=True,
204
- validate=lambda _, x: True if x else "Please select at least one version", # type: ignore
219
+ validate=at_least_one_validation,
205
220
  )
206
221
  )
207
222
 
@@ -6,6 +6,7 @@ from typing import List, Tuple
6
6
  import rich_click as click
7
7
  from loguru import logger as log
8
8
 
9
+ from mpflash.errors import MPFlashError
9
10
  from mpflash.mpboard_id import find_stored_board
10
11
  from mpflash.vendor.versions import clean_version
11
12
 
@@ -62,9 +63,7 @@ from .download import download
62
63
  show_default=True,
63
64
  help="""Force download of firmware even if it already exists.""",
64
65
  )
65
- def cli_download(
66
- **kwargs,
67
- ):
66
+ def cli_download(**kwargs) -> int:
68
67
  params = DownloadParams(**kwargs)
69
68
  params.versions = list(params.versions)
70
69
  params.boards = list(params.boards)
@@ -77,18 +76,23 @@ def cli_download(
77
76
 
78
77
  params = ask_missing_params(params, action="download")
79
78
  if not params: # Cancelled by user
80
- exit(1)
79
+ return 2
81
80
  params.versions = [clean_version(v, drop_v=True) for v in params.versions]
82
81
  assert isinstance(params, DownloadParams)
83
82
 
84
- download(
85
- params.fw_folder,
86
- params.ports,
87
- params.boards,
88
- params.versions,
89
- params.force,
90
- params.clean,
91
- )
83
+ try:
84
+ download(
85
+ params.fw_folder,
86
+ params.ports,
87
+ params.boards,
88
+ params.versions,
89
+ params.force,
90
+ params.clean,
91
+ )
92
+ return 0
93
+ except MPFlashError as e:
94
+ log.error(f"{e}")
95
+ return 1
92
96
 
93
97
 
94
98
  def connected_ports_boards() -> Tuple[List[str], List[str]]:
@@ -28,7 +28,7 @@ from .worklist import MPRemoteBoard, WorkList, full_auto_worklist, manual_workli
28
28
  "--firmware",
29
29
  "-f",
30
30
  "fw_folder",
31
- type=click.Path(exists=True, file_okay=False, dir_okay=True, path_type=Path),
31
+ type=click.Path(file_okay=False, dir_okay=True, path_type=Path),
32
32
  default=config.firmware_folder,
33
33
  show_default=True,
34
34
  help="The folder to retrieve the firmware from.",
@@ -91,7 +91,7 @@ from .worklist import MPRemoteBoard, WorkList, full_auto_worklist, manual_workli
91
91
  show_default=True,
92
92
  help="""Enter micropython bootloader mode before flashing.""",
93
93
  )
94
- def cli_flash_board(**kwargs):
94
+ def cli_flash_board(**kwargs) -> int:
95
95
  # version to versions, board to boards
96
96
  kwargs["versions"] = [kwargs.pop("version")] if kwargs["version"] != None else []
97
97
  if kwargs["board"] is None:
@@ -127,7 +127,7 @@ def cli_flash_board(**kwargs):
127
127
  # Ask for missing input if needed
128
128
  params = ask_missing_params(params, action="flash")
129
129
  if not params: # Cancelled by user
130
- exit(1)
130
+ return 2
131
131
  # TODO: Just in time Download of firmware
132
132
 
133
133
  assert isinstance(params, FlashParams)
@@ -168,3 +168,7 @@ def cli_flash_board(**kwargs):
168
168
  ):
169
169
  log.info(f"Flashed {len(flashed)} boards")
170
170
  show_mcus(flashed, title="Updated boards after flashing")
171
+ return 0
172
+ else:
173
+ log.error("No boards were flashed")
174
+ return 1
@@ -26,7 +26,7 @@ from .logger import make_quiet
26
26
  show_default=True,
27
27
  help="""Show progress""",
28
28
  )
29
- def cli_list_mcus(as_json: bool, progress: bool = True):
29
+ def cli_list_mcus(as_json: bool, progress: bool = True) -> int:
30
30
  """List the connected MCU boards, and output in a nice table or json."""
31
31
  if as_json:
32
32
  # avoid noise in json output
@@ -38,4 +38,4 @@ def cli_list_mcus(as_json: bool, progress: bool = True):
38
38
  progress = False
39
39
  if progress:
40
40
  show_mcus(conn_mcus, refresh=False)
41
- return conn_mcus
41
+ return 0 if conn_mcus else 1
@@ -2,13 +2,13 @@
2
2
 
3
3
  # import rich_click as click
4
4
 
5
+ import click
6
+
5
7
  from .cli_download import cli_download
6
8
  from .cli_flash import cli_flash_board
7
9
  from .cli_group import cli
8
10
  from .cli_list import cli_list_mcus
9
11
 
10
- # from loguru import logger as log
11
-
12
12
 
13
13
  def mpflash():
14
14
  cli.add_command(cli_flash_board)
@@ -16,7 +16,8 @@ def mpflash():
16
16
  cli.add_command(cli_download)
17
17
  # cli(auto_envvar_prefix="MPFLASH")
18
18
  try:
19
- exit(cli())
19
+ result = cli(standalone_mode=False)
20
+ exit(result)
20
21
  except AttributeError as e:
21
22
  print(f"Error: {e}")
22
23
  exit(-1)
@@ -19,6 +19,7 @@ from loguru import logger as log
19
19
  from rich.progress import track
20
20
 
21
21
  from mpflash.common import PORT_FWTYPES
22
+ from mpflash.errors import MPFlashError
22
23
 
23
24
  jsonlines.ujson = None # type: ignore
24
25
  # #########################################################################################################
@@ -165,7 +166,7 @@ def download_firmwares(
165
166
  *,
166
167
  force: bool = False,
167
168
  clean: bool = True,
168
- ):
169
+ ) -> int:
169
170
  skipped = downloaded = 0
170
171
  if versions is None:
171
172
  versions = []
@@ -200,6 +201,7 @@ def download_firmwares(
200
201
  writer.write(board)
201
202
  downloaded += 1
202
203
  log.info(f"Downloaded {downloaded} firmwares, skipped {skipped} existing files.")
204
+ return downloaded + skipped
203
205
 
204
206
 
205
207
  def get_firmware_list(ports: List[str], boards: List[str], versions: List[str], clean: bool):
@@ -246,7 +248,7 @@ def download(
246
248
  versions: List[str],
247
249
  force: bool,
248
250
  clean: bool,
249
- ):
251
+ ) -> int:
250
252
  """
251
253
  Downloads firmware files based on the specified destination, ports, boards, versions, force flag, and clean flag.
252
254
 
@@ -259,19 +261,20 @@ def download(
259
261
  clean : A flag indicating whether to perform a clean download.
260
262
 
261
263
  Returns:
262
- None
264
+ int: The number of downloaded firmware files.
263
265
 
264
266
  Raises:
265
- SystemExit: If no boards are found or specified.
267
+ MPFlashError : If no boards are found or specified.
266
268
 
267
269
  """
268
270
  if not boards:
269
271
  log.critical("No boards found, please connect a board or specify boards to download firmware for.")
270
- exit(1)
272
+ raise MPFlashError("No boards found")
271
273
  # versions = [clean_version(v, drop_v=True) for v in versions] # remove leading v from version
272
274
  try:
273
275
  destination.mkdir(exist_ok=True, parents=True)
274
276
  except (PermissionError, FileNotFoundError) as e:
275
- log.critical(f"Could not create folder {destination}\n{e}")
276
- exit(1)
277
- download_firmwares(destination, ports, boards, versions, force=force, clean=clean)
277
+ log.critical(f"Could not create folder {destination}")
278
+ raise MPFlashError(f"Could not create folder {destination}") from e
279
+
280
+ return download_firmwares(destination, ports, boards, versions, force=force, clean=clean)
mpflash/mpflash/list.py CHANGED
@@ -5,6 +5,7 @@ from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn, TimeEl
5
5
  from rich.table import Column, Table
6
6
 
7
7
  from mpflash.mpremoteboard import MPRemoteBoard
8
+ from mpflash.vendor.versions import clean_version
8
9
 
9
10
  from .config import config
10
11
  from .logger import console
@@ -82,7 +83,7 @@ def show_mcus(
82
83
  f"{mcu.board}\n{description}".strip(),
83
84
  # mcu.variant,
84
85
  mcu.cpu,
85
- mcu.version,
86
+ clean_version(mcu.version),
86
87
  mcu.build,
87
88
  )
88
89
  console.print(table)