micropython-stubber 1.23.2__py3-none-any.whl → 1.24.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {micropython_stubber-1.23.2.dist-info → micropython_stubber-1.24.0.dist-info}/METADATA +30 -12
- {micropython_stubber-1.23.2.dist-info → micropython_stubber-1.24.0.dist-info}/RECORD +69 -66
- {micropython_stubber-1.23.2.dist-info → micropython_stubber-1.24.0.dist-info}/WHEEL +1 -1
- mpflash/README.md +2 -2
- mpflash/mpflash/basicgit.py +49 -9
- mpflash/mpflash/common.py +23 -16
- mpflash/mpflash/downloaded.py +10 -2
- mpflash/mpflash/mpboard_id/__init__.py +9 -4
- mpflash/mpflash/mpboard_id/add_boards.py +25 -14
- mpflash/mpflash/mpboard_id/board.py +2 -2
- mpflash/mpflash/mpboard_id/board_id.py +10 -6
- mpflash/mpflash/mpboard_id/board_info.zip +0 -0
- mpflash/mpflash/mpboard_id/store.py +8 -3
- mpflash/mpflash/mpremoteboard/__init__.py +13 -8
- mpflash/mpflash/mpremoteboard/mpy_fw_info.py +27 -16
- mpflash/mpflash/vendor/board_database.py +185 -0
- mpflash/mpflash/vendor/readme.md +10 -1
- mpflash/mpflash/versions.py +28 -40
- mpflash/poetry.lock +1605 -601
- mpflash/pyproject.toml +4 -3
- stubber/__init__.py +1 -1
- stubber/board/createstubs.py +51 -27
- stubber/board/createstubs_db.py +36 -28
- stubber/board/createstubs_db_min.py +171 -165
- stubber/board/createstubs_db_mpy.mpy +0 -0
- stubber/board/createstubs_mem.py +36 -28
- stubber/board/createstubs_mem_min.py +184 -178
- stubber/board/createstubs_mem_mpy.mpy +0 -0
- stubber/board/createstubs_min.py +102 -94
- stubber/board/createstubs_mpy.mpy +0 -0
- stubber/board/modulelist.txt +16 -0
- stubber/codemod/enrich.py +297 -88
- stubber/codemod/merge_docstub.py +250 -65
- stubber/codemod/test_enrich.py +87 -0
- stubber/codemod/visitors/typevars.py +200 -0
- stubber/commands/build_cmd.py +16 -3
- stubber/commands/clone_cmd.py +3 -3
- stubber/commands/config_cmd.py +4 -2
- stubber/commands/enrich_folder_cmd.py +33 -21
- stubber/commands/get_core_cmd.py +1 -2
- stubber/commands/get_docstubs_cmd.py +60 -6
- stubber/commands/get_frozen_cmd.py +15 -12
- stubber/commands/get_mcu_cmd.py +3 -3
- stubber/commands/merge_cmd.py +1 -2
- stubber/commands/publish_cmd.py +19 -4
- stubber/commands/stub_cmd.py +3 -3
- stubber/commands/switch_cmd.py +3 -5
- stubber/commands/variants_cmd.py +3 -3
- stubber/cst_transformer.py +52 -17
- stubber/freeze/common.py +27 -11
- stubber/freeze/freeze_manifest_2.py +8 -1
- stubber/freeze/get_frozen.py +4 -1
- stubber/merge_config.py +111 -0
- stubber/minify.py +1 -2
- stubber/publish/database.py +51 -10
- stubber/publish/merge_docstubs.py +33 -16
- stubber/publish/package.py +32 -18
- stubber/publish/publish.py +8 -8
- stubber/publish/stubpackage.py +110 -47
- stubber/rst/lookup.py +205 -43
- stubber/rst/reader.py +106 -59
- stubber/rst/rst_utils.py +24 -11
- stubber/stubber.py +1 -1
- stubber/stubs_from_docs.py +31 -13
- stubber/update_module_list.py +2 -2
- stubber/utils/config.py +33 -13
- stubber/utils/post.py +9 -6
- stubber/publish/missing_class_methods.py +0 -51
- {micropython_stubber-1.23.2.dist-info → micropython_stubber-1.24.0.dist-info}/LICENSE +0 -0
- {micropython_stubber-1.23.2.dist-info → micropython_stubber-1.24.0.dist-info}/entry_points.txt +0 -0
@@ -23,9 +23,10 @@ from mpflash.versions import micropython_versions
|
|
23
23
|
# and the #define MICROPY_HW_MCU_NAME "STM32F767xx"
|
24
24
|
RE_H_MICROPY_HW_BOARD_NAME = re.compile(r"#define\s+MICROPY_HW_BOARD_NAME\s+\"(.+)\"")
|
25
25
|
RE_H_MICROPY_HW_MCU_NAME = re.compile(r"#define\s+MICROPY_HW_MCU_NAME\s+\"(.+)\"")
|
26
|
-
# find in the mpconfigboard
|
27
|
-
|
28
|
-
|
26
|
+
# find boards and variants in the mpconfigboard*.cmake files
|
27
|
+
RE_CMAKE_MICROPY_HW_BOARD_NAME = re.compile(
|
28
|
+
r"MICROPY_HW_BOARD_NAME\s?=\s?\"(?P<variant>[\w\s\S]*)\""
|
29
|
+
)
|
29
30
|
RE_CMAKE_MICROPY_HW_MCU_NAME = re.compile(r"MICROPY_HW_MCU_NAME\s?=\s?\"(?P<variant>[\w\s\S]*)\"")
|
30
31
|
# TODO: normal make files
|
31
32
|
|
@@ -42,10 +43,8 @@ def boards_from_repo(mpy_path: Path, version: str, family: Optional[str] = None)
|
|
42
43
|
"""
|
43
44
|
if not mpy_path.exists() or not mpy_path.is_dir():
|
44
45
|
raise FileNotFoundError(f"MicroPython path {mpy_path} does not exist.")
|
45
|
-
|
46
|
-
|
47
|
-
if not version:
|
48
|
-
version = git.get_local_tag() # type: ignore
|
46
|
+
family = family or "micropython"
|
47
|
+
version = version or git.get_local_tag() # type: ignore
|
49
48
|
if not version:
|
50
49
|
raise ValueError("No version provided and no local tag found.")
|
51
50
|
|
@@ -53,9 +52,10 @@ def boards_from_repo(mpy_path: Path, version: str, family: Optional[str] = None)
|
|
53
52
|
# look in mpconfigboard.h files
|
54
53
|
board_list = boards_from_cmake(mpy_path, version, family)
|
55
54
|
|
56
|
-
# look for
|
55
|
+
# look for boards in the .cmake files
|
57
56
|
board_list.extend(boards_from_headers(mpy_path, version, family))
|
58
|
-
|
57
|
+
|
58
|
+
# TODO:? look for variants in the board.json files
|
59
59
|
|
60
60
|
return board_list
|
61
61
|
|
@@ -63,7 +63,7 @@ def boards_from_repo(mpy_path: Path, version: str, family: Optional[str] = None)
|
|
63
63
|
def boards_from_cmake(mpy_path: Path, version: str, family: str):
|
64
64
|
"""Get boards from the mpconfigboard.cmake files to the board_list."""
|
65
65
|
board_list = []
|
66
|
-
for path in mpy_path.glob("ports/**/mpconfigboard
|
66
|
+
for path in mpy_path.glob("ports/**/mpconfigboard*.cmake"):
|
67
67
|
board = path.parent.name
|
68
68
|
port = path.parent.parent.parent.name
|
69
69
|
with open(path, "r") as f:
|
@@ -118,7 +118,9 @@ def boards_from_headers(mpy_path: Path, version: str, family: str):
|
|
118
118
|
mcu_name = match[1]
|
119
119
|
found += 1
|
120
120
|
if found == 2:
|
121
|
-
description =
|
121
|
+
description = (
|
122
|
+
f"{board_name} with {mcu_name}" if mcu_name != "-" else board_name
|
123
|
+
)
|
122
124
|
board_list.append(
|
123
125
|
Board(
|
124
126
|
board_id=board,
|
@@ -160,6 +162,8 @@ def boards_for_versions(versions: List[str], mpy_path: Path):
|
|
160
162
|
List[Board]: The list of Board objects.
|
161
163
|
"""
|
162
164
|
board_list: List[Board] = []
|
165
|
+
# first fetch all tags from the repository
|
166
|
+
git.fetch(mpy_path)
|
163
167
|
for version in track(versions, description="Searching MicroPython versions"):
|
164
168
|
if git.checkout_tag(tag=version, repo=mpy_path):
|
165
169
|
new_ones = boards_from_repo(mpy_path, version, family="micropython")
|
@@ -197,9 +201,10 @@ def make_table(board_list: List[Board]) -> rich.table.Table:
|
|
197
201
|
is_wide = True
|
198
202
|
|
199
203
|
table = rich.table.Table(title="MicroPython Board Information")
|
204
|
+
table.add_column("Port", justify="left", style="magenta")
|
200
205
|
table.add_column("BOARD_ID", justify="left", style="green")
|
206
|
+
table.add_column("Variant(s)", justify="left", style="blue")
|
201
207
|
table.add_column("Description", justify="left", style="cyan")
|
202
|
-
table.add_column("Port", justify="left", style="magenta")
|
203
208
|
table.add_column("Board Name", justify="left", style="blue")
|
204
209
|
if is_wide:
|
205
210
|
table.add_column("MCU Name", justify="left", style="blue")
|
@@ -209,7 +214,7 @@ def make_table(board_list: List[Board]) -> rich.table.Table:
|
|
209
214
|
table.add_column("Family", justify="left", style="blue")
|
210
215
|
|
211
216
|
for board in board_list:
|
212
|
-
row = [board.board_id, board.
|
217
|
+
row = [board.port, board.board_id, board.variant, board.description, board.board_name]
|
213
218
|
if is_wide:
|
214
219
|
row.append(board.mcu_name)
|
215
220
|
row.extend((str(Path(board.path).suffix), board.version))
|
@@ -222,7 +227,13 @@ def make_table(board_list: List[Board]) -> rich.table.Table:
|
|
222
227
|
|
223
228
|
def ask_mpy_path():
|
224
229
|
"""Ask the user for the path to the MicroPython repository."""
|
225
|
-
questions = [
|
230
|
+
questions = [
|
231
|
+
inquirer.Text(
|
232
|
+
"mpy_path",
|
233
|
+
message="Enter the path to the MicroPython repository",
|
234
|
+
default=".\\repos\\micropython",
|
235
|
+
)
|
236
|
+
]
|
226
237
|
if answers := inquirer.prompt(questions):
|
227
238
|
return Path(answers["mpy_path"])
|
228
239
|
else:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from dataclasses import dataclass, field
|
2
2
|
from pathlib import Path
|
3
|
-
from typing import
|
3
|
+
from typing import Union
|
4
4
|
|
5
5
|
|
6
6
|
# - source : get_boardnames.py
|
@@ -20,7 +20,7 @@ class Board:
|
|
20
20
|
family: str = field(default="micropython")
|
21
21
|
mcu_name: str = field(default="")
|
22
22
|
cpu: str = field(default="")
|
23
|
-
|
23
|
+
variant: str = field(default="")
|
24
24
|
|
25
25
|
def __post_init__(self):
|
26
26
|
if not self.cpu:
|
@@ -56,14 +56,12 @@ def _find_board_id_by_description(
|
|
56
56
|
Path to the board_info.json file (optional)
|
57
57
|
|
58
58
|
"""
|
59
|
-
#
|
59
|
+
# Some functional overlap with
|
60
60
|
# src\mpflash\mpflash\mpboard_id\__init__.py find_known_board
|
61
61
|
|
62
|
+
candidate_boards = read_known_boardinfo(board_info)
|
62
63
|
if not short_descr and " with " in descr:
|
63
64
|
short_descr = descr.split(" with ")[0]
|
64
|
-
|
65
|
-
candidate_boards = read_known_boardinfo(board_info)
|
66
|
-
|
67
65
|
if version:
|
68
66
|
# filter for matching version
|
69
67
|
if version in ("preview", "stable"):
|
@@ -71,16 +69,22 @@ def _find_board_id_by_description(
|
|
71
69
|
version = get_stable_mp_version()
|
72
70
|
known_versions = sorted({b.version for b in candidate_boards})
|
73
71
|
if version not in known_versions:
|
74
|
-
# FIXME if latest stable is newer than the last version in the boardlist this will fail
|
75
72
|
log.trace(f"Version {version} not found in board info, using latest known version {known_versions[-1]}")
|
76
|
-
version = known_versions[-1]
|
73
|
+
version = '.'.join(known_versions[-1].split('.')[:2]) # take only major.minor
|
77
74
|
if version_matches := [b for b in candidate_boards if b.version.startswith(version)]:
|
78
75
|
candidate_boards = version_matches
|
79
76
|
else:
|
80
77
|
raise MPFlashError(f"No board info found for version {version}")
|
78
|
+
# First try full match on description, then partial match
|
81
79
|
matches = [b for b in candidate_boards if b.description == descr]
|
82
80
|
if not matches and short_descr:
|
83
81
|
matches = [b for b in candidate_boards if b.description == short_descr]
|
82
|
+
if not matches:
|
83
|
+
# partial match (for added VARIANT)
|
84
|
+
matches = [b for b in candidate_boards if b.description.startswith(descr)]
|
85
|
+
if not matches and short_descr:
|
86
|
+
matches = [b for b in candidate_boards if b.description.startswith(short_descr)]
|
84
87
|
if not matches:
|
85
88
|
raise MPFlashError(f"No board info found for description '{descr}' or '{short_descr}'")
|
86
89
|
return sorted(matches, key=lambda x: x.version)
|
90
|
+
|
Binary file
|
@@ -1,18 +1,18 @@
|
|
1
1
|
import functools
|
2
2
|
import zipfile
|
3
3
|
from pathlib import Path
|
4
|
-
from typing import List, Optional
|
4
|
+
from typing import Final, List, Optional
|
5
5
|
|
6
6
|
import jsons
|
7
7
|
|
8
8
|
from mpflash.mpboard_id.board import Board
|
9
9
|
|
10
10
|
###############################################################################################
|
11
|
-
HERE = Path(__file__).parent
|
11
|
+
HERE: Final = Path(__file__).parent
|
12
12
|
###############################################################################################
|
13
13
|
|
14
14
|
|
15
|
-
def write_boardinfo_json(board_list: List[Board], *, folder: Path):
|
15
|
+
def write_boardinfo_json(board_list: List[Board], *, folder: Optional[Path] = None):
|
16
16
|
"""Writes the board information to a JSON file.
|
17
17
|
|
18
18
|
Args:
|
@@ -21,6 +21,8 @@ def write_boardinfo_json(board_list: List[Board], *, folder: Path):
|
|
21
21
|
"""
|
22
22
|
import zipfile
|
23
23
|
|
24
|
+
if not folder:
|
25
|
+
folder = HERE
|
24
26
|
# create a zip file with the json file
|
25
27
|
with zipfile.ZipFile(folder / "board_info.zip", "w", compression=zipfile.ZIP_DEFLATED) as zipf:
|
26
28
|
# write the list to json file inside the zip
|
@@ -30,6 +32,9 @@ def write_boardinfo_json(board_list: List[Board], *, folder: Path):
|
|
30
32
|
|
31
33
|
@functools.lru_cache(maxsize=20)
|
32
34
|
def read_known_boardinfo(board_info: Optional[Path] = None) -> List[Board]:
|
35
|
+
"""Reads the board information from a JSON file in a zip file."""
|
36
|
+
|
37
|
+
import zipfile
|
33
38
|
|
34
39
|
if not board_info:
|
35
40
|
board_info = HERE / "board_info.zip"
|
@@ -55,7 +55,7 @@ class MPRemoteBoard:
|
|
55
55
|
self.arch = ""
|
56
56
|
self.mpy = ""
|
57
57
|
self.build = ""
|
58
|
-
self.location = location
|
58
|
+
self.location = location # USB location
|
59
59
|
self.toml = {}
|
60
60
|
if update:
|
61
61
|
self.get_mcu_info()
|
@@ -97,7 +97,9 @@ class MPRemoteBoard:
|
|
97
97
|
|
98
98
|
if sys.platform == "win32":
|
99
99
|
# Windows sort of comports by number - but fallback to device name
|
100
|
-
return sorted(
|
100
|
+
return sorted(
|
101
|
+
output, key=lambda x: int(x.split()[0][3:]) if x.split()[0][3:].isdigit() else x
|
102
|
+
)
|
101
103
|
# sort by device name
|
102
104
|
return sorted(output)
|
103
105
|
|
@@ -116,9 +118,10 @@ class MPRemoteBoard:
|
|
116
118
|
["run", str(HERE / "mpy_fw_info.py")],
|
117
119
|
no_info=True,
|
118
120
|
timeout=timeout,
|
119
|
-
resume=
|
121
|
+
resume=False, # Avoid restarts
|
120
122
|
)
|
121
|
-
if rc
|
123
|
+
if rc:
|
124
|
+
log.debug(f"rc: {rc}, result: {result}")
|
122
125
|
raise ConnectionError(f"Failed to get mcu_info for {self.serialport}")
|
123
126
|
# Ok we have the info, now parse it
|
124
127
|
raw_info = result[0].strip()
|
@@ -134,7 +137,9 @@ class MPRemoteBoard:
|
|
134
137
|
self.description = descr = info["board"]
|
135
138
|
pos = descr.rfind(" with")
|
136
139
|
short_descr = descr[:pos].strip() if pos != -1 else ""
|
137
|
-
if board_name := find_board_id_by_description(
|
140
|
+
if board_name := find_board_id_by_description(
|
141
|
+
descr, short_descr, version=self.version
|
142
|
+
):
|
138
143
|
self.board = board_name
|
139
144
|
else:
|
140
145
|
self.board = "UNKNOWN_BOARD"
|
@@ -174,7 +179,7 @@ class MPRemoteBoard:
|
|
174
179
|
except Exception as e:
|
175
180
|
log.error(f"Failed to parse board_info.toml: {e}")
|
176
181
|
else:
|
177
|
-
log.trace(f"
|
182
|
+
log.trace(f"Did not find a board_info.toml: {result}")
|
178
183
|
|
179
184
|
def disconnect(self) -> bool:
|
180
185
|
"""
|
@@ -202,7 +207,7 @@ class MPRemoteBoard:
|
|
202
207
|
log_errors: bool = True,
|
203
208
|
no_info: bool = False,
|
204
209
|
timeout: int = 60,
|
205
|
-
resume: bool =
|
210
|
+
resume: Optional[bool] = None,
|
206
211
|
**kwargs,
|
207
212
|
):
|
208
213
|
"""
|
@@ -223,7 +228,7 @@ class MPRemoteBoard:
|
|
223
228
|
if self.serialport:
|
224
229
|
prefix += ["connect", self.serialport]
|
225
230
|
# if connected add resume to keep state between commands
|
226
|
-
if self.connected or resume:
|
231
|
+
if (resume != False) and self.connected or resume:
|
227
232
|
prefix += ["resume"]
|
228
233
|
cmd = prefix + cmd
|
229
234
|
log.debug(" ".join(cmd))
|
@@ -36,7 +36,9 @@ def _info(): # type:() -> dict[str, str]
|
|
36
36
|
"version": "",
|
37
37
|
"build": "",
|
38
38
|
"ver": "",
|
39
|
-
"port":
|
39
|
+
"port": (
|
40
|
+
"stm32" if sys.platform.startswith("pyb") else sys.platform
|
41
|
+
), # port: esp32 / win32 / linux / stm32
|
40
42
|
"board": "GENERIC",
|
41
43
|
"cpu": "",
|
42
44
|
"mpy": "",
|
@@ -48,7 +50,11 @@ def _info(): # type:() -> dict[str, str]
|
|
48
50
|
except AttributeError:
|
49
51
|
pass
|
50
52
|
try:
|
51
|
-
machine =
|
53
|
+
machine = (
|
54
|
+
sys.implementation._machine
|
55
|
+
if "_machine" in dir(sys.implementation)
|
56
|
+
else os.uname().machine
|
57
|
+
)
|
52
58
|
info["board"] = machine.strip()
|
53
59
|
info["cpu"] = machine.split("with")[-1].strip() if "with" in machine else ""
|
54
60
|
info["mpy"] = (
|
@@ -100,7 +106,8 @@ def _info(): # type:() -> dict[str, str]
|
|
100
106
|
if (
|
101
107
|
info["version"]
|
102
108
|
and info["version"].endswith(".0")
|
103
|
-
and info["version"]
|
109
|
+
and info["version"]
|
110
|
+
>= "1.10.0" # versions from 1.10.0 to 1.20.0 do not have a micro .0
|
104
111
|
and info["version"] <= "1.19.9"
|
105
112
|
):
|
106
113
|
# drop the .0 for newer releases
|
@@ -110,19 +117,23 @@ def _info(): # type:() -> dict[str, str]
|
|
110
117
|
if "mpy" in info and info["mpy"]: # mpy on some v1.11+ builds
|
111
118
|
sys_mpy = int(info["mpy"])
|
112
119
|
# .mpy architecture
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
120
|
+
try:
|
121
|
+
arch = [
|
122
|
+
None,
|
123
|
+
"x86",
|
124
|
+
"x64",
|
125
|
+
"armv6",
|
126
|
+
"armv6m",
|
127
|
+
"armv7m",
|
128
|
+
"armv7em",
|
129
|
+
"armv7emsp",
|
130
|
+
"armv7emdp",
|
131
|
+
"xtensa",
|
132
|
+
"xtensawin",
|
133
|
+
"hazard3riscv", # assumed
|
134
|
+
][sys_mpy >> 10]
|
135
|
+
except IndexError:
|
136
|
+
arch = "unknown"
|
126
137
|
if arch:
|
127
138
|
info["arch"] = arch
|
128
139
|
# .mpy version.minor
|
@@ -0,0 +1,185 @@
|
|
1
|
+
"""
|
2
|
+
The micropython git repo contains many 'board.json' files.
|
3
|
+
|
4
|
+
This is an example:
|
5
|
+
ports/stm32/boards/PYBV11/board.json
|
6
|
+
|
7
|
+
{
|
8
|
+
"deploy": [
|
9
|
+
"../PYBV10/deploy.md"
|
10
|
+
],
|
11
|
+
"docs": "",
|
12
|
+
"features": [],
|
13
|
+
"images": [
|
14
|
+
"PYBv1_1.jpg",
|
15
|
+
"PYBv1_1-C.jpg",
|
16
|
+
"PYBv1_1-E.jpg"
|
17
|
+
],
|
18
|
+
"mcu": "stm32f4",
|
19
|
+
"product": "Pyboard v1.1",
|
20
|
+
"thumbnail": "",
|
21
|
+
"url": "https://store.micropython.org/product/PYBv1.1",
|
22
|
+
"variants": {
|
23
|
+
"DP": "Double-precision float",
|
24
|
+
"DP_THREAD": "Double precision float + Threads",
|
25
|
+
"NETWORK": "Wiznet 5200 Driver",
|
26
|
+
"THREAD": "Threading"
|
27
|
+
},
|
28
|
+
"vendor": "George Robotics"
|
29
|
+
}
|
30
|
+
|
31
|
+
This module implements `class Database` which reads all 'board.json' files and
|
32
|
+
provides a way to browse it's data.
|
33
|
+
"""
|
34
|
+
|
35
|
+
from __future__ import annotations
|
36
|
+
|
37
|
+
import json
|
38
|
+
from dataclasses import dataclass, field
|
39
|
+
from glob import glob
|
40
|
+
from pathlib import Path
|
41
|
+
|
42
|
+
|
43
|
+
@dataclass(order=True)
|
44
|
+
class Variant:
|
45
|
+
name: str
|
46
|
+
"""
|
47
|
+
Example: "DP_THREAD"
|
48
|
+
"""
|
49
|
+
text: str
|
50
|
+
"""
|
51
|
+
Example: "Double precision float + Threads"
|
52
|
+
"""
|
53
|
+
board: Board = field(repr=False)
|
54
|
+
|
55
|
+
|
56
|
+
@dataclass(order=True)
|
57
|
+
class Board:
|
58
|
+
name: str
|
59
|
+
"""
|
60
|
+
Example: "PYBV11"
|
61
|
+
"""
|
62
|
+
variants: list[Variant]
|
63
|
+
"""
|
64
|
+
List of variants available for this board.
|
65
|
+
Variants are sorted. May be an empty list if no variants are available.
|
66
|
+
Example key: "DP_THREAD"
|
67
|
+
"""
|
68
|
+
url: str
|
69
|
+
"""
|
70
|
+
Primary URL to link to this board.
|
71
|
+
"""
|
72
|
+
mcu: str
|
73
|
+
"""
|
74
|
+
Example: "stm32f4"
|
75
|
+
"""
|
76
|
+
product: str
|
77
|
+
"""
|
78
|
+
Example: "Pyboard v1.1"
|
79
|
+
"""
|
80
|
+
vendor: str
|
81
|
+
"""
|
82
|
+
Example: "George Robotics"
|
83
|
+
"""
|
84
|
+
images: list[str]
|
85
|
+
"""
|
86
|
+
Images of this board, stored in the micropython-media repository.
|
87
|
+
Example: ["PYBv1_1.jpg", "PYBv1_1-C.jpg", "PYBv1_1-E.jpg"]
|
88
|
+
"""
|
89
|
+
deploy: list[str]
|
90
|
+
"""
|
91
|
+
Files that explain how to deploy for this board:
|
92
|
+
Example: ["../PYBV10/deploy.md"]
|
93
|
+
"""
|
94
|
+
port: Port | None = field(default=None, compare=False)
|
95
|
+
|
96
|
+
@staticmethod
|
97
|
+
def factory(filename_json: Path) -> Board:
|
98
|
+
with filename_json.open() as f:
|
99
|
+
board_json = json.load(f)
|
100
|
+
|
101
|
+
board = Board(
|
102
|
+
name=filename_json.parent.name,
|
103
|
+
variants=[],
|
104
|
+
url=board_json["url"],
|
105
|
+
mcu=board_json["mcu"],
|
106
|
+
product=board_json["product"],
|
107
|
+
vendor=board_json["vendor"],
|
108
|
+
images=board_json["images"],
|
109
|
+
deploy=board_json["deploy"],
|
110
|
+
)
|
111
|
+
board.variants.extend(
|
112
|
+
sorted([Variant(*v, board) for v in board_json.get("variants", {}).items()]) # type: ignore
|
113
|
+
)
|
114
|
+
return board
|
115
|
+
|
116
|
+
|
117
|
+
@dataclass(order=True)
|
118
|
+
class Port:
|
119
|
+
name: str
|
120
|
+
"""
|
121
|
+
Example: "stm32"
|
122
|
+
"""
|
123
|
+
boards: dict[str, Board] = field(default_factory=dict, repr=False)
|
124
|
+
"""
|
125
|
+
Example key: "PYBV11"
|
126
|
+
"""
|
127
|
+
|
128
|
+
|
129
|
+
@dataclass
|
130
|
+
class Database:
|
131
|
+
"""
|
132
|
+
This database contains all information retrieved from all 'board.json' files.
|
133
|
+
"""
|
134
|
+
|
135
|
+
mpy_root_directory: Path = field(repr=False)
|
136
|
+
port_filter: str = field(default="", repr=False)
|
137
|
+
|
138
|
+
ports: dict[str, Port] = field(default_factory=dict)
|
139
|
+
boards: dict[str, Board] = field(default_factory=dict)
|
140
|
+
|
141
|
+
def __post_init__(self) -> None:
|
142
|
+
mpy_dir = self.mpy_root_directory
|
143
|
+
# Take care to avoid using Path.glob! Performance was 15x slower.
|
144
|
+
for p in glob(f"{mpy_dir}/ports/**/boards/**/board.json"):
|
145
|
+
filename_json = Path(p)
|
146
|
+
port_name = filename_json.parent.parent.parent.name
|
147
|
+
if self.port_filter and self.port_filter != port_name:
|
148
|
+
continue
|
149
|
+
|
150
|
+
# Create a port
|
151
|
+
port = self.ports.get(port_name, None)
|
152
|
+
if port is None:
|
153
|
+
port = Port(port_name)
|
154
|
+
self.ports[port_name] = port
|
155
|
+
|
156
|
+
# Load board.json and attach it to the board
|
157
|
+
board = Board.factory(filename_json)
|
158
|
+
board.port = port
|
159
|
+
|
160
|
+
port.boards[board.name] = board
|
161
|
+
self.boards[board.name] = board
|
162
|
+
|
163
|
+
# Add 'special' ports, that don't have boards
|
164
|
+
# TODO(mst) Tidy up later (variant descriptions etc)
|
165
|
+
for special_port_name in ["unix", "webassembly", "windows"]:
|
166
|
+
if self.port_filter and self.port_filter != special_port_name:
|
167
|
+
continue
|
168
|
+
path = Path(mpy_dir, "ports", special_port_name)
|
169
|
+
variant_names = [var.name for var in path.glob("variants/*") if var.is_dir()]
|
170
|
+
board = Board(
|
171
|
+
special_port_name,
|
172
|
+
[],
|
173
|
+
f"https://github.com/micropython/micropython/blob/master/ports/{special_port_name}/README.md",
|
174
|
+
"",
|
175
|
+
"",
|
176
|
+
"",
|
177
|
+
[],
|
178
|
+
[],
|
179
|
+
)
|
180
|
+
board.variants = [Variant(v, "", board) for v in variant_names]
|
181
|
+
port = Port(special_port_name, {special_port_name: board})
|
182
|
+
board.port = port
|
183
|
+
|
184
|
+
self.ports[special_port_name] = port
|
185
|
+
self.boards[board.name] = board
|
mpflash/mpflash/vendor/readme.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
1
|
These modules are vendored from the following repositories:
|
2
2
|
|
3
|
-
micropython/micropython
|
3
|
+
- https://github.com/micropython/micropython (MIT)
|
4
|
+
- dfu.py
|
5
|
+
- pydfy.py
|
6
|
+
|
7
|
+
- https://github.com/mattytrentini/mpbuild (MIT)
|
8
|
+
- board_database.py
|
9
|
+
|
10
|
+
- https://github.com/click-contrib/click-aliases (Public Domain)
|
11
|
+
- click_aliases.py (Robbin Bonthond)
|
12
|
+
|
mpflash/mpflash/versions.py
CHANGED
@@ -1,14 +1,12 @@
|
|
1
1
|
"""
|
2
|
-
|
3
|
-
# Version handling copied from stubber/utils/versions.py
|
4
|
-
#############################################################
|
2
|
+
Version handling for mpflash and micropython-stubber
|
5
3
|
"""
|
6
4
|
|
7
5
|
from pathlib import Path
|
8
6
|
|
9
7
|
from cache_to_disk import NoCacheCondition, cache_to_disk
|
10
8
|
from loguru import logger as log
|
11
|
-
from packaging.version import parse
|
9
|
+
from packaging.version import Version, parse
|
12
10
|
|
13
11
|
import mpflash.basicgit as git
|
14
12
|
from mpflash.common import GH_CLIENT
|
@@ -71,58 +69,48 @@ def clean_version(
|
|
71
69
|
return version
|
72
70
|
|
73
71
|
|
72
|
+
def is_version(version: str):
|
73
|
+
"""Check if the version is a valid version string"""
|
74
|
+
return Version._regex.search(version) is not None
|
75
|
+
|
76
|
+
|
74
77
|
@cache_to_disk(n_days_to_cache=1)
|
75
|
-
def micropython_versions(minver: str = "v1.20", reverse: bool = False):
|
78
|
+
def micropython_versions(minver: str = "v1.20", reverse: bool = False, cache_it=True):
|
76
79
|
"""Get the list of micropython versions from github tags"""
|
77
|
-
|
80
|
+
|
78
81
|
try:
|
79
82
|
gh_client = GH_CLIENT
|
80
83
|
repo = gh_client.get_repo("micropython/micropython")
|
81
|
-
|
84
|
+
tags = [tag.name for tag in repo.get_tags() if parse(tag.name) >= parse(minver)]
|
85
|
+
versions = [v for v in tags if not v.endswith(V_PREVIEW)]
|
82
86
|
# Only keep the last preview
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
"v1.20.0",
|
93
|
-
"v1.19.1",
|
94
|
-
"v1.19",
|
95
|
-
"v1.18",
|
96
|
-
"v1.17",
|
97
|
-
"v1.16",
|
98
|
-
"v1.15",
|
99
|
-
"v1.14",
|
100
|
-
"v1.13",
|
101
|
-
"v1.12",
|
102
|
-
"v1.11",
|
103
|
-
"v1.10",
|
104
|
-
]
|
105
|
-
cache_it = False
|
106
|
-
versions = [v for v in versions if parse(v) >= parse(minver)]
|
107
|
-
# remove all but the most recent (preview) version
|
108
|
-
versions = versions[:1] + [v for v in versions if "preview" not in v]
|
109
|
-
versions = sorted(versions, reverse=reverse)
|
87
|
+
preview = sorted([v for v in tags if v.endswith(V_PREVIEW)], reverse=True)[0]
|
88
|
+
versions.append(preview)
|
89
|
+
except Exception as e:
|
90
|
+
log.error(e)
|
91
|
+
versions = []
|
92
|
+
# returns - but does not cache
|
93
|
+
raise NoCacheCondition(function_value=versions)
|
94
|
+
# remove any duplicates and sort
|
95
|
+
versions = sorted(list(set(versions)), reverse=reverse, key=lambda s: (not is_version(s), s))
|
110
96
|
if cache_it:
|
111
97
|
return versions
|
112
98
|
# returns - but does not cache
|
113
99
|
raise NoCacheCondition(function_value=versions)
|
114
100
|
|
115
101
|
|
116
|
-
def get_stable_mp_version() -> str:
|
102
|
+
def get_stable_mp_version(cache_it=True) -> str:
|
117
103
|
# read the versions from the git tags
|
118
|
-
all_versions = micropython_versions(minver=OLDEST_VERSION)
|
119
|
-
|
104
|
+
all_versions = micropython_versions(minver=OLDEST_VERSION, cache_it=cache_it)
|
105
|
+
versions = [v for v in all_versions if not v.endswith(V_PREVIEW)]
|
106
|
+
return versions[-1] if versions else ""
|
120
107
|
|
121
108
|
|
122
|
-
def get_preview_mp_version() -> str:
|
109
|
+
def get_preview_mp_version(cache_it=True) -> str:
|
123
110
|
# read the versions from the git tags
|
124
|
-
all_versions = micropython_versions(minver=OLDEST_VERSION)
|
125
|
-
|
111
|
+
all_versions = micropython_versions(minver=OLDEST_VERSION, cache_it=cache_it)
|
112
|
+
versions = [v for v in all_versions if v.endswith(V_PREVIEW)]
|
113
|
+
return versions[0] if versions else ""
|
126
114
|
|
127
115
|
|
128
116
|
# Do not cache , same path will have different versions checked out
|