micropython-stubber 1.23.1__py3-none-any.whl → 1.23.2__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.
- {micropython_stubber-1.23.1.dist-info → micropython_stubber-1.23.2.dist-info}/LICENSE +30 -30
- {micropython_stubber-1.23.1.dist-info → micropython_stubber-1.23.2.dist-info}/METADATA +32 -15
- micropython_stubber-1.23.2.dist-info/RECORD +158 -0
- micropython_stubber-1.23.2.dist-info/entry_points.txt +5 -0
- mpflash/README.md +220 -194
- mpflash/libusb_flash.ipynb +203 -203
- mpflash/mpflash/add_firmware.py +98 -98
- mpflash/mpflash/ask_input.py +236 -236
- mpflash/mpflash/basicgit.py +284 -284
- mpflash/mpflash/bootloader/__init__.py +2 -2
- mpflash/mpflash/bootloader/activate.py +60 -60
- mpflash/mpflash/bootloader/detect.py +82 -82
- mpflash/mpflash/bootloader/manual.py +101 -101
- mpflash/mpflash/bootloader/micropython.py +12 -12
- mpflash/mpflash/bootloader/touch1200.py +36 -36
- mpflash/mpflash/cli_download.py +129 -129
- mpflash/mpflash/cli_flash.py +224 -219
- mpflash/mpflash/cli_group.py +111 -111
- mpflash/mpflash/cli_list.py +87 -81
- mpflash/mpflash/cli_main.py +39 -39
- mpflash/mpflash/common.py +210 -165
- mpflash/mpflash/config.py +44 -44
- mpflash/mpflash/connected.py +96 -78
- mpflash/mpflash/download.py +364 -364
- mpflash/mpflash/downloaded.py +130 -130
- mpflash/mpflash/errors.py +9 -9
- mpflash/mpflash/flash/__init__.py +55 -55
- mpflash/mpflash/flash/esp.py +59 -59
- mpflash/mpflash/flash/stm32.py +19 -19
- mpflash/mpflash/flash/stm32_dfu.py +104 -104
- mpflash/mpflash/flash/uf2/__init__.py +88 -88
- mpflash/mpflash/flash/uf2/boardid.py +15 -15
- mpflash/mpflash/flash/uf2/linux.py +136 -130
- mpflash/mpflash/flash/uf2/macos.py +42 -42
- mpflash/mpflash/flash/uf2/uf2disk.py +12 -12
- mpflash/mpflash/flash/uf2/windows.py +43 -43
- mpflash/mpflash/flash/worklist.py +170 -170
- mpflash/mpflash/list.py +106 -99
- mpflash/mpflash/logger.py +41 -41
- mpflash/mpflash/mpboard_id/__init__.py +93 -93
- mpflash/mpflash/mpboard_id/add_boards.py +251 -251
- mpflash/mpflash/mpboard_id/board.py +37 -37
- mpflash/mpflash/mpboard_id/board_id.py +86 -86
- mpflash/mpflash/mpboard_id/store.py +43 -43
- mpflash/mpflash/mpremoteboard/__init__.py +266 -222
- mpflash/mpflash/mpremoteboard/mpy_fw_info.py +141 -141
- mpflash/mpflash/mpremoteboard/runner.py +140 -140
- mpflash/mpflash/vendor/click_aliases.py +91 -91
- mpflash/mpflash/vendor/dfu.py +165 -165
- mpflash/mpflash/vendor/pydfu.py +605 -605
- mpflash/mpflash/vendor/readme.md +2 -2
- mpflash/mpflash/versions.py +135 -135
- mpflash/poetry.lock +1599 -1599
- mpflash/pyproject.toml +65 -65
- mpflash/stm32_udev_rules.md +62 -62
- stubber/__init__.py +3 -3
- stubber/board/board_info.csv +193 -193
- stubber/board/boot.py +34 -34
- stubber/board/createstubs.py +1004 -986
- stubber/board/createstubs_db.py +826 -825
- stubber/board/createstubs_db_min.py +332 -331
- stubber/board/createstubs_db_mpy.mpy +0 -0
- stubber/board/createstubs_lvgl.py +741 -741
- stubber/board/createstubs_lvgl_min.py +741 -741
- stubber/board/createstubs_mem.py +767 -766
- stubber/board/createstubs_mem_min.py +307 -306
- stubber/board/createstubs_mem_mpy.mpy +0 -0
- stubber/board/createstubs_min.py +295 -294
- stubber/board/createstubs_mpy.mpy +0 -0
- stubber/board/fw_info.py +141 -141
- stubber/board/info.py +183 -183
- stubber/board/main.py +19 -19
- stubber/board/modulelist.txt +247 -247
- stubber/board/pyrightconfig.json +34 -34
- stubber/bulk/mcu_stubber.py +437 -454
- stubber/codemod/_partials/__init__.py +48 -48
- stubber/codemod/_partials/db_main.py +147 -147
- stubber/codemod/_partials/lvgl_main.py +77 -77
- stubber/codemod/_partials/modules_reader.py +80 -80
- stubber/codemod/add_comment.py +53 -53
- stubber/codemod/add_method.py +65 -65
- stubber/codemod/board.py +317 -317
- stubber/codemod/enrich.py +151 -145
- stubber/codemod/merge_docstub.py +284 -284
- stubber/codemod/modify_list.py +54 -54
- stubber/codemod/utils.py +56 -56
- stubber/commands/build_cmd.py +94 -94
- stubber/commands/cli.py +49 -55
- stubber/commands/clone_cmd.py +78 -78
- stubber/commands/config_cmd.py +29 -29
- stubber/commands/enrich_folder_cmd.py +71 -71
- stubber/commands/get_core_cmd.py +71 -71
- stubber/commands/get_docstubs_cmd.py +92 -89
- stubber/commands/get_frozen_cmd.py +117 -114
- stubber/commands/get_mcu_cmd.py +102 -61
- stubber/commands/merge_cmd.py +66 -66
- stubber/commands/publish_cmd.py +118 -118
- stubber/commands/stub_cmd.py +31 -31
- stubber/commands/switch_cmd.py +62 -62
- stubber/commands/variants_cmd.py +48 -48
- stubber/cst_transformer.py +178 -178
- stubber/data/board_info.csv +193 -193
- stubber/data/board_info.json +1729 -1729
- stubber/data/micropython_tags.csv +15 -15
- stubber/data/requirements-core-micropython.txt +38 -38
- stubber/data/requirements-core-pycopy.txt +39 -39
- stubber/downloader.py +37 -36
- stubber/freeze/common.py +72 -68
- stubber/freeze/freeze_folder.py +69 -69
- stubber/freeze/freeze_manifest_2.py +126 -113
- stubber/freeze/get_frozen.py +131 -127
- stubber/get_cpython.py +112 -101
- stubber/get_lobo.py +59 -59
- stubber/minify.py +423 -419
- stubber/publish/bump.py +86 -86
- stubber/publish/candidates.py +275 -256
- stubber/publish/database.py +18 -18
- stubber/publish/defaults.py +40 -40
- stubber/publish/enums.py +24 -24
- stubber/publish/helpers.py +29 -29
- stubber/publish/merge_docstubs.py +136 -130
- stubber/publish/missing_class_methods.py +51 -49
- stubber/publish/package.py +150 -146
- stubber/publish/pathnames.py +51 -51
- stubber/publish/publish.py +120 -120
- stubber/publish/pypi.py +42 -38
- stubber/publish/stubpackage.py +1055 -1027
- stubber/rst/__init__.py +9 -9
- stubber/rst/classsort.py +78 -77
- stubber/rst/lookup.py +533 -530
- stubber/rst/output_dict.py +401 -401
- stubber/rst/reader.py +814 -814
- stubber/rst/report_return.py +77 -69
- stubber/rst/rst_utils.py +541 -540
- stubber/stubber.py +38 -38
- stubber/stubs_from_docs.py +90 -90
- stubber/tools/manifestfile.py +654 -654
- stubber/tools/readme.md +6 -6
- stubber/update_fallback.py +117 -117
- stubber/update_module_list.py +123 -123
- stubber/utils/__init__.py +6 -6
- stubber/utils/config.py +137 -125
- stubber/utils/makeversionhdr.py +54 -54
- stubber/utils/manifest.py +90 -90
- stubber/utils/post.py +80 -79
- stubber/utils/repos.py +156 -150
- stubber/utils/stubmaker.py +139 -139
- stubber/utils/typed_config_toml.py +80 -77
- stubber/variants.py +106 -106
- micropython_stubber-1.23.1.dist-info/RECORD +0 -159
- micropython_stubber-1.23.1.dist-info/entry_points.txt +0 -3
- mpflash/basicgit.py +0 -288
- {micropython_stubber-1.23.1.dist-info → micropython_stubber-1.23.2.dist-info}/WHEEL +0 -0
mpflash/mpflash/common.py
CHANGED
@@ -1,165 +1,210 @@
|
|
1
|
-
import fnmatch
|
2
|
-
import
|
3
|
-
import
|
4
|
-
|
5
|
-
|
6
|
-
from
|
7
|
-
from
|
8
|
-
|
9
|
-
from
|
10
|
-
|
11
|
-
from
|
12
|
-
|
13
|
-
from .
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
"
|
21
|
-
"
|
22
|
-
"
|
23
|
-
|
24
|
-
"
|
25
|
-
|
26
|
-
"
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
if
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
1
|
+
import fnmatch
|
2
|
+
import glob
|
3
|
+
import os
|
4
|
+
import platform
|
5
|
+
import sys
|
6
|
+
from dataclasses import dataclass, field
|
7
|
+
from enum import Enum
|
8
|
+
from pathlib import Path
|
9
|
+
from typing import List, Optional, Union
|
10
|
+
|
11
|
+
from github import Auth, Github
|
12
|
+
from serial.tools import list_ports
|
13
|
+
from serial.tools.list_ports_common import ListPortInfo
|
14
|
+
|
15
|
+
from .logger import log
|
16
|
+
|
17
|
+
# from mpflash.mpremoteboard import MPRemoteBoard
|
18
|
+
|
19
|
+
PORT_FWTYPES = {
|
20
|
+
"stm32": [".dfu"], # need .dfu for pydfu.py - .hex for cube cli/GUI
|
21
|
+
"esp32": [".bin"],
|
22
|
+
"esp8266": [".bin"],
|
23
|
+
"rp2": [".uf2"],
|
24
|
+
"samd": [".uf2"],
|
25
|
+
# below this not yet implemented / tested
|
26
|
+
"mimxrt": [".hex"],
|
27
|
+
"nrf": [".uf2"],
|
28
|
+
"renesas-ra": [".hex"],
|
29
|
+
}
|
30
|
+
|
31
|
+
# Token with no permissions to avoid throttling
|
32
|
+
# https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28#getting-a-higher-rate-limit
|
33
|
+
PAT_NO_ACCESS = (
|
34
|
+
"github_pat"
|
35
|
+
+ "_11AAHPVFQ0qAkDnSUaMKSp"
|
36
|
+
+ "_ZkDl5NRRwBsUN6EYg9ahp1Dvj4FDDONnXVgimxC2EtpY7Q7BUKBoQ0Jq72X"
|
37
|
+
)
|
38
|
+
PAT = os.environ.get("GITHUB_TOKEN") or PAT_NO_ACCESS
|
39
|
+
GH_CLIENT = Github(auth=Auth.Token(PAT))
|
40
|
+
|
41
|
+
|
42
|
+
@dataclass
|
43
|
+
class FWInfo:
|
44
|
+
"""
|
45
|
+
Downloaded Firmware information
|
46
|
+
is somewhat related to the BOARD class in the mpboard_id module
|
47
|
+
"""
|
48
|
+
|
49
|
+
port: str # MicroPython port
|
50
|
+
board: str # MicroPython board
|
51
|
+
filename: str = field(default="") # relative filename of the firmware image
|
52
|
+
firmware: str = field(default="") # url or path to original firmware image
|
53
|
+
variant: str = field(default="") # MicroPython variant
|
54
|
+
preview: bool = field(default=False) # True if the firmware is a preview version
|
55
|
+
version: str = field(default="") # MicroPython version (NO v prefix)
|
56
|
+
url: str = field(default="") # url to the firmware image download folder
|
57
|
+
build: str = field(default="0") # The build = number of commits since the last release
|
58
|
+
ext: str = field(default="") # the file extension of the firmware
|
59
|
+
family: str = field(default="micropython") # The family of the firmware
|
60
|
+
custom: bool = field(default=False) # True if the firmware is a custom build
|
61
|
+
description: str = field(default="") # Description used by this firmware (custom only)
|
62
|
+
|
63
|
+
def to_dict(self) -> dict:
|
64
|
+
"""Convert the object to a dictionary"""
|
65
|
+
return self.__dict__
|
66
|
+
|
67
|
+
@classmethod
|
68
|
+
def from_dict(cls, data: dict) -> "FWInfo":
|
69
|
+
"""Create a FWInfo object from a dictionary"""
|
70
|
+
# add missing keys
|
71
|
+
if "ext" not in data:
|
72
|
+
data["ext"] = Path(data["firmware"]).suffix
|
73
|
+
if "family" not in data:
|
74
|
+
data["family"] = "micropython"
|
75
|
+
return cls(**data)
|
76
|
+
|
77
|
+
|
78
|
+
@dataclass
|
79
|
+
class Params:
|
80
|
+
"""Common parameters for downloading and flashing firmware"""
|
81
|
+
|
82
|
+
ports: List[str] = field(default_factory=list)
|
83
|
+
boards: List[str] = field(default_factory=list)
|
84
|
+
versions: List[str] = field(default_factory=list)
|
85
|
+
fw_folder: Path = Path()
|
86
|
+
serial: List[str] = field(default_factory=list)
|
87
|
+
ignore: List[str] = field(default_factory=list)
|
88
|
+
bluetooth: bool = False
|
89
|
+
|
90
|
+
|
91
|
+
@dataclass
|
92
|
+
class DownloadParams(Params):
|
93
|
+
"""Parameters for downloading firmware"""
|
94
|
+
|
95
|
+
clean: bool = False
|
96
|
+
force: bool = False
|
97
|
+
|
98
|
+
|
99
|
+
class BootloaderMethod(Enum):
|
100
|
+
AUTO = "auto"
|
101
|
+
MANUAL = "manual"
|
102
|
+
MPY = "mpy"
|
103
|
+
TOUCH_1200 = "touch1200"
|
104
|
+
NONE = "none"
|
105
|
+
|
106
|
+
|
107
|
+
@dataclass
|
108
|
+
class FlashParams(Params):
|
109
|
+
"""Parameters for flashing a board"""
|
110
|
+
|
111
|
+
erase: bool = True
|
112
|
+
bootloader: BootloaderMethod = BootloaderMethod.NONE
|
113
|
+
cpu: str = ""
|
114
|
+
|
115
|
+
def __post_init__(self):
|
116
|
+
if isinstance(self.bootloader, str):
|
117
|
+
self.bootloader = BootloaderMethod(self.bootloader)
|
118
|
+
|
119
|
+
|
120
|
+
ParamType = Union[DownloadParams, FlashParams]
|
121
|
+
|
122
|
+
|
123
|
+
def filtered_comports(
|
124
|
+
ignore: Optional[List[str]] = None,
|
125
|
+
include: Optional[List[str]] = None,
|
126
|
+
bluetooth: bool = False,
|
127
|
+
) -> List[ListPortInfo]: # sourcery skip: assign-if-exp
|
128
|
+
"""
|
129
|
+
Get a list of filtered comports using the include and ignore lists.
|
130
|
+
both can be globs (e.g. COM*) or exact port names (e.g. COM1)
|
131
|
+
"""
|
132
|
+
if not ignore:
|
133
|
+
ignore = []
|
134
|
+
elif not isinstance(ignore, list): # type: ignore
|
135
|
+
ignore = list(ignore)
|
136
|
+
if not include:
|
137
|
+
include = ["*"]
|
138
|
+
elif not isinstance(include, list): # type: ignore
|
139
|
+
include = list(include)
|
140
|
+
|
141
|
+
# remove ports that are to be ignored
|
142
|
+
log.trace(f"{include=}, {ignore=}, {bluetooth=}")
|
143
|
+
|
144
|
+
comports = [
|
145
|
+
p for p in list_ports.comports() if not any(fnmatch.fnmatch(p.device, i) for i in ignore)
|
146
|
+
]
|
147
|
+
if platform.system() == "Linux":
|
148
|
+
# use p.location to filter out the bogus ports on newer Linux kernels
|
149
|
+
# filter out the bogus ports on newer Linux kernels
|
150
|
+
comports = [p for p in comports if p.location]
|
151
|
+
|
152
|
+
log.trace(f"comports: {[p.device for p in comports]}")
|
153
|
+
# remove bluetooth ports
|
154
|
+
|
155
|
+
if include != ["*"]:
|
156
|
+
# if there are explicit ports to include, add them to the list
|
157
|
+
explicit = [
|
158
|
+
p for p in list_ports.comports() if any(fnmatch.fnmatch(p.device, i) for i in include)
|
159
|
+
]
|
160
|
+
log.trace(f"explicit: {[p.device for p in explicit]}")
|
161
|
+
if ignore == []:
|
162
|
+
# if nothing to ignore, just use the explicit list as a sinple sane default
|
163
|
+
comports = explicit
|
164
|
+
else:
|
165
|
+
# if there are ports to ignore, add the explicit list to the filtered list
|
166
|
+
comports = list(set(explicit) | set(comports))
|
167
|
+
if not bluetooth:
|
168
|
+
# filter out bluetooth ports
|
169
|
+
comports = [p for p in comports if "bluetooth" not in p.description.lower()]
|
170
|
+
comports = [p for p in comports if "BTHENUM" not in p.hwid]
|
171
|
+
if sys.platform == "darwin":
|
172
|
+
comports = [p for p in comports if ".Bluetooth" not in p.device]
|
173
|
+
log.trace(f"no Bluetooth: {[p.device for p in comports]}")
|
174
|
+
log.debug(f"filtered_comports: {[p.device for p in comports]}")
|
175
|
+
# sort
|
176
|
+
if sys.platform == "win32":
|
177
|
+
# Windows sort of comports by number - but fallback to device name
|
178
|
+
return sorted(
|
179
|
+
comports,
|
180
|
+
key=lambda x: int(x.device.split()[0][3:]) if x.device.split()[0][3:].isdigit() else x,
|
181
|
+
)
|
182
|
+
# sort by device name
|
183
|
+
return sorted(comports, key=lambda x: x.device)
|
184
|
+
|
185
|
+
|
186
|
+
def find_serial_by_path(target_port: str):
|
187
|
+
"""Find the symbolic link path of a serial port by its device path."""
|
188
|
+
# sourcery skip: use-next
|
189
|
+
|
190
|
+
if os.name == "nt":
|
191
|
+
return None
|
192
|
+
# List all available serial ports
|
193
|
+
available_ports = list_ports.comports()
|
194
|
+
# Filter to get the device path of the target port
|
195
|
+
target_device_path = None
|
196
|
+
for port in available_ports:
|
197
|
+
if port.device == target_port:
|
198
|
+
target_device_path = port.device
|
199
|
+
break
|
200
|
+
|
201
|
+
if not target_device_path:
|
202
|
+
return None # Target port not found among available ports
|
203
|
+
|
204
|
+
# Search for all symbolic links in /dev/serial/by-path/
|
205
|
+
for symlink in glob.glob("/dev/serial/by-path/*"):
|
206
|
+
# Resolve the symbolic link to its target
|
207
|
+
if os.path.realpath(symlink) == target_device_path:
|
208
|
+
return symlink # Return the matching symlink path
|
209
|
+
|
210
|
+
return None # Return None if no match is found
|
mpflash/mpflash/config.py
CHANGED
@@ -1,44 +1,44 @@
|
|
1
|
-
"""centralized configuration for mpflash"""
|
2
|
-
|
3
|
-
import os
|
4
|
-
from importlib.metadata import version
|
5
|
-
from pathlib import Path
|
6
|
-
from typing import List
|
7
|
-
|
8
|
-
import platformdirs
|
9
|
-
|
10
|
-
from mpflash.logger import log
|
11
|
-
|
12
|
-
|
13
|
-
def get_version():
|
14
|
-
name = __package__ or "mpflash"
|
15
|
-
return version(name)
|
16
|
-
|
17
|
-
|
18
|
-
class MPtoolConfig:
|
19
|
-
"""Centralized configuration for mpflash"""
|
20
|
-
|
21
|
-
quiet: bool = False
|
22
|
-
verbose: bool = False
|
23
|
-
usb: bool = False
|
24
|
-
ignore_ports: List[str] = []
|
25
|
-
firmware_folder: Path = platformdirs.user_downloads_path() / "firmware"
|
26
|
-
# test options specified on the commandline
|
27
|
-
tests: List[str] = []
|
28
|
-
_interactive: bool = True
|
29
|
-
|
30
|
-
@property
|
31
|
-
def interactive(self):
|
32
|
-
# No interactions in CI
|
33
|
-
if os.getenv("GITHUB_ACTIONS") == "true":
|
34
|
-
log.warning("Disabling interactive mode in CI")
|
35
|
-
return False
|
36
|
-
return self._interactive
|
37
|
-
|
38
|
-
@interactive.setter
|
39
|
-
def interactive(self, value: bool):
|
40
|
-
self._interactive = value
|
41
|
-
|
42
|
-
|
43
|
-
config = MPtoolConfig()
|
44
|
-
__version__ = get_version()
|
1
|
+
"""centralized configuration for mpflash"""
|
2
|
+
|
3
|
+
import os
|
4
|
+
from importlib.metadata import version
|
5
|
+
from pathlib import Path
|
6
|
+
from typing import List
|
7
|
+
|
8
|
+
import platformdirs
|
9
|
+
|
10
|
+
from mpflash.logger import log
|
11
|
+
|
12
|
+
|
13
|
+
def get_version():
|
14
|
+
name = __package__ or "mpflash"
|
15
|
+
return version(name)
|
16
|
+
|
17
|
+
|
18
|
+
class MPtoolConfig:
|
19
|
+
"""Centralized configuration for mpflash"""
|
20
|
+
|
21
|
+
quiet: bool = False
|
22
|
+
verbose: bool = False
|
23
|
+
usb: bool = False
|
24
|
+
ignore_ports: List[str] = []
|
25
|
+
firmware_folder: Path = platformdirs.user_downloads_path() / "firmware"
|
26
|
+
# test options specified on the commandline
|
27
|
+
tests: List[str] = []
|
28
|
+
_interactive: bool = True
|
29
|
+
|
30
|
+
@property
|
31
|
+
def interactive(self):
|
32
|
+
# No interactions in CI
|
33
|
+
if os.getenv("GITHUB_ACTIONS") == "true":
|
34
|
+
log.warning("Disabling interactive mode in CI")
|
35
|
+
return False
|
36
|
+
return self._interactive
|
37
|
+
|
38
|
+
@interactive.setter
|
39
|
+
def interactive(self, value: bool):
|
40
|
+
self._interactive = value
|
41
|
+
|
42
|
+
|
43
|
+
config = MPtoolConfig()
|
44
|
+
__version__ = get_version()
|
mpflash/mpflash/connected.py
CHANGED
@@ -1,78 +1,96 @@
|
|
1
|
-
from typing import List, Tuple
|
2
|
-
|
3
|
-
from rich import print
|
4
|
-
from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
|
5
|
-
from rich.table import Column
|
6
|
-
|
7
|
-
from mpflash.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
Returns
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
#
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
1
|
+
from typing import List, Tuple
|
2
|
+
|
3
|
+
from rich import print
|
4
|
+
from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
|
5
|
+
from rich.table import Column
|
6
|
+
|
7
|
+
from mpflash.common import filtered_comports
|
8
|
+
from mpflash.mpremoteboard import MPRemoteBoard
|
9
|
+
|
10
|
+
from mpflash.common import find_serial_by_path
|
11
|
+
|
12
|
+
|
13
|
+
def connected_ports_boards(
|
14
|
+
*, include: List[str], ignore: List[str], bluetooth: bool = False
|
15
|
+
) -> Tuple[List[str], List[str], List[MPRemoteBoard]]:
|
16
|
+
"""
|
17
|
+
Returns a tuple containing lists of unique ports and boards from the connected MCUs.
|
18
|
+
Boards that are physically connected, but give no tangible response are ignored.
|
19
|
+
|
20
|
+
Returns:
|
21
|
+
A tuple containing three lists:
|
22
|
+
- A list of unique ports where MCUs are connected.
|
23
|
+
- A list of unique board names of the connected MCUs.
|
24
|
+
- A list of MPRemoteBoard instances of the connected MCUs.
|
25
|
+
"""
|
26
|
+
conn_mcus = [
|
27
|
+
b for b in list_mcus(include=include, ignore=ignore, bluetooth=bluetooth) if b.connected
|
28
|
+
]
|
29
|
+
# ignore boards that have the [micropython-stubber] ignore flag set
|
30
|
+
conn_mcus = [
|
31
|
+
item for item in conn_mcus if not (item.toml.get("mpflash", {}).get("ignore", False))
|
32
|
+
]
|
33
|
+
|
34
|
+
ports = list({b.port for b in conn_mcus})
|
35
|
+
boards = list({b.board for b in conn_mcus})
|
36
|
+
return (ports, boards, conn_mcus)
|
37
|
+
|
38
|
+
|
39
|
+
# #########################################################################################################
|
40
|
+
rp_spinner = SpinnerColumn(finished_text="✅")
|
41
|
+
rp_text = TextColumn("{task.description} {task.fields[device]}", table_column=Column())
|
42
|
+
rp_bar = BarColumn(bar_width=None, table_column=Column())
|
43
|
+
|
44
|
+
|
45
|
+
def list_mcus(
|
46
|
+
*, ignore: List[str], include: List[str], bluetooth: bool = False
|
47
|
+
) -> List[MPRemoteBoard]:
|
48
|
+
"""
|
49
|
+
Retrieves information about connected microcontroller boards.
|
50
|
+
|
51
|
+
Returns:
|
52
|
+
List[MPRemoteBoard]: A list of MPRemoteBoard instances with board information.
|
53
|
+
Raises:
|
54
|
+
ConnectionError: If there is an error connecting to a board.
|
55
|
+
"""
|
56
|
+
# conn_mcus = [MPRemoteBoard(sp) for sp in MPRemoteBoard.connected_boards(bluetooth) if sp not in config.ignore_ports]
|
57
|
+
|
58
|
+
comports = filtered_comports(
|
59
|
+
ignore=ignore,
|
60
|
+
include=include,
|
61
|
+
bluetooth=bluetooth,
|
62
|
+
)
|
63
|
+
connected_mcus = [
|
64
|
+
MPRemoteBoard(
|
65
|
+
c.device,
|
66
|
+
location=find_serial_by_path(c.device) or c.location or c.hwid or "?",
|
67
|
+
)
|
68
|
+
for c in comports
|
69
|
+
]
|
70
|
+
|
71
|
+
# a lot of boilerplate to show a progress bar with the comport currently scanned
|
72
|
+
# low update rate to facilitate screen readers/narration
|
73
|
+
with Progress(
|
74
|
+
rp_spinner,
|
75
|
+
rp_text,
|
76
|
+
rp_bar,
|
77
|
+
TimeElapsedColumn(),
|
78
|
+
refresh_per_second=1,
|
79
|
+
) as progress:
|
80
|
+
tsk_scan = progress.add_task("[green]Scanning", visible=False, total=None)
|
81
|
+
progress.tasks[tsk_scan].fields["device"] = "..."
|
82
|
+
progress.tasks[tsk_scan].visible = True
|
83
|
+
progress.start_task(tsk_scan)
|
84
|
+
try:
|
85
|
+
for mcu in connected_mcus:
|
86
|
+
progress.update(tsk_scan, device=mcu.serialport.replace("/dev/tty", "tty"))
|
87
|
+
try:
|
88
|
+
mcu.get_mcu_info()
|
89
|
+
except ConnectionError as e:
|
90
|
+
print(f"Error: {e}")
|
91
|
+
continue
|
92
|
+
finally:
|
93
|
+
# transient
|
94
|
+
progress.stop_task(tsk_scan)
|
95
|
+
progress.tasks[tsk_scan].visible = False
|
96
|
+
return connected_mcus
|