mpflash 1.24.5__py3-none-any.whl → 1.24.6__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.
mpflash/basicgit.py CHANGED
@@ -136,6 +136,9 @@ def get_local_tags(repo: Optional[Path] = None, minver: Optional[str] = None) ->
136
136
  return sorted(tags)
137
137
 
138
138
 
139
+ from github.GithubException import BadCredentialsException
140
+
141
+
139
142
  @cachetools.func.ttl_cache(maxsize=16, ttl=60) # 60 seconds
140
143
  def get_tags(repo: str, minver: Optional[str] = None) -> List[str]:
141
144
  """
@@ -176,7 +179,7 @@ def checkout_tag(tag: str, repo: Optional[Union[str, Path]] = None) -> bool:
176
179
  return True
177
180
 
178
181
 
179
- def sync_submodules(repo: Optional[Union[Path, str]] = None) -> bool:
182
+ def sync_submodules(repo: Union[Path, str]) -> bool:
180
183
  """
181
184
  make sure any submodules are in sync
182
185
  """
@@ -191,9 +194,26 @@ def sync_submodules(repo: Optional[Union[Path, str]] = None) -> bool:
191
194
  log.debug(result.stderr)
192
195
  else:
193
196
  return False
197
+ checkout_arduino_lib(Path(repo))
194
198
  return True
195
199
 
196
200
 
201
+ def checkout_arduino_lib(mpy_path: Path):
202
+ """
203
+ Checkout the arduino-lib submodule repo if it exists
204
+
205
+ This is needed as some of the arduino boards freeze modules originationg from the arduino-lib
206
+ """
207
+ # arduino_lib_path = mpy_path / "lib/arduino-lib"
208
+ if (mpy_path / "lib/arduino-lib").exists():
209
+ cmd = ["git", "submodule", "update", "--init", "lib/arduino-lib"]
210
+ try:
211
+ result = subprocess.run(cmd, cwd=mpy_path, check=True)
212
+ log.info(f"checkout arduino-lib: {result.returncode}")
213
+ except subprocess.CalledProcessError as e:
214
+ log.warning("Could not check out arduino-lib, error: ", e)
215
+
216
+
197
217
  def checkout_commit(commit_hash: str, repo: Optional[Union[Path, str]] = None) -> bool:
198
218
  """
199
219
  Checkout a specific commit
@@ -242,7 +262,7 @@ def switch_branch(branch: str, repo: Optional[Union[Path, str]] = None) -> bool:
242
262
 
243
263
  def fetch(repo: Union[Path, str]) -> bool:
244
264
  """
245
- fetches a repo
265
+ fetches a repo and all tags
246
266
  repo should be in the form of : path/.git
247
267
  repo = '../micropython/.git'
248
268
  returns True on success
mpflash/common.py CHANGED
@@ -7,10 +7,11 @@ from enum import Enum
7
7
  from pathlib import Path
8
8
  from typing import List, Optional, Union
9
9
 
10
- from github import Auth, Github
11
10
  from serial.tools import list_ports
12
11
  from serial.tools.list_ports_common import ListPortInfo
13
12
 
13
+ from mpflash.basicgit import GH_CLIENT as GH_CLIENT
14
+
14
15
  from .logger import log
15
16
 
16
17
  # from mpflash.mpremoteboard import MPRemoteBoard
@@ -27,17 +28,6 @@ PORT_FWTYPES = {
27
28
  "renesas-ra": [".hex"],
28
29
  }
29
30
 
30
- # Token with no permissions to avoid throttling
31
- # 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
32
- PAT_NO_ACCESS = (
33
- "github_pat_"
34
- + "11AAHPVFQ0G4NTaQ73Bw5J"
35
- + "_fAp7K9sZ1qL8VFnI9g78eUlCdmOXHB3WzSdj2jtEYb4XF3N7PDJBl32qIxq"
36
- )
37
-
38
- PAT = os.environ.get("GITHUB_TOKEN") or PAT_NO_ACCESS
39
- GH_CLIENT = Github(auth=Auth.Token(PAT))
40
-
41
31
 
42
32
  @dataclass
43
33
  class FWInfo:
@@ -150,9 +140,10 @@ def filtered_comports(
150
140
  comports = [
151
141
  p for p in list_ports.comports() if not any(fnmatch.fnmatch(p.device, i) for i in ignore)
152
142
  ]
153
-
143
+
154
144
  if False:
155
145
  import jsons
146
+
156
147
  print(jsons.dumps(comports).replace('{"description":', '\n{"description":'))
157
148
 
158
149
  if platform.system() == "Linux":
mpflash/downloaded.py CHANGED
@@ -14,11 +14,15 @@ from .config import config
14
14
  def downloaded_firmwares(fw_folder: Path) -> List[FWInfo]:
15
15
  """Load a list of locally downloaded firmwares from the jsonl file"""
16
16
  firmwares: List[FWInfo] = []
17
+ log.debug(f"Reading {fw_folder / 'firmware.jsonl' }")
17
18
  try:
18
19
  with jsonlines.open(fw_folder / "firmware.jsonl") as reader:
19
20
  firmwares = [FWInfo.from_dict(item) for item in reader]
20
21
  except FileNotFoundError:
21
22
  log.error(f"No firmware.jsonl found in {fw_folder}")
23
+ except jsonlines.InvalidLineError as e:
24
+ log.error(f"Invalid firmware.jsonl found in {fw_folder} : {e}")
25
+
22
26
  # sort by filename
23
27
  firmwares.sort(key=lambda x: x.filename)
24
28
  return firmwares
@@ -109,7 +113,11 @@ def filter_downloaded_fwlist(
109
113
  log.trace(f"Filtering firmware for {version} : {len(fw_list)} found.")
110
114
  # filter by port
111
115
  if port:
112
- fw_list = [fw for fw in fw_list if fw.port == port and Path(fw.firmware).suffix in PORT_FWTYPES[port]]
116
+ fw_list = [
117
+ fw
118
+ for fw in fw_list
119
+ if fw.port == port and Path(fw.firmware).suffix in PORT_FWTYPES[port]
120
+ ]
113
121
  log.trace(f"Filtering firmware for {port} : {len(fw_list)} found.")
114
122
 
115
123
  if board_id:
@@ -120,7 +128,7 @@ def filter_downloaded_fwlist(
120
128
  # the firmware variant should match exactly the board_id
121
129
  fw_list = [fw for fw in fw_list if fw.variant == board_id]
122
130
  log.trace(f"Filtering firmware for {board_id} : {len(fw_list)} found.")
123
-
131
+
124
132
  if selector and port in selector:
125
133
  fw_list = [fw for fw in fw_list if fw.filename.endswith(selector[port])]
126
134
  return fw_list
@@ -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.cmake files
27
-
28
- RE_CMAKE_MICROPY_HW_BOARD_NAME = re.compile(r"MICROPY_HW_BOARD_NAME\s?=\s?\"(?P<variant>[\w\s\S]*)\"")
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
- if not family:
46
- family = "micropython"
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 variants in the .cmake files
55
+ # look for boards in the .cmake files
57
56
  board_list.extend(boards_from_headers(mpy_path, version, family))
58
- # TODO:? look for variants in the Makefile files
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.cmake"):
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 = f"{board_name} with {mcu_name}" if mcu_name != "-" else board_name
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.description, *(board.port, board.board_name)]
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 = [inquirer.Text("mpy_path", message="Enter the path to the MicroPython repository", default=".\\repos\\micropython")]
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 Union
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
- # TODO: add variant
23
+ variant: str = field(default="")
24
24
 
25
25
  def __post_init__(self):
26
26
  if not self.cpu:
Binary file
@@ -55,7 +55,7 @@ class MPRemoteBoard:
55
55
  self.arch = ""
56
56
  self.mpy = ""
57
57
  self.build = ""
58
- self.location = location # USB 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(output, key=lambda x: int(x.split()[0][3:]) if x.split()[0][3:].isdigit() else x)
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=True, # Avoid restarts
121
+ resume=False, # Avoid restarts
120
122
  )
121
- if rc != OK:
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(descr, short_descr, version=self.version):
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"Failed to read board_info.toml: {result}")
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 = False,
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))
@@ -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/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/versions.py CHANGED
@@ -81,34 +81,16 @@ def micropython_versions(minver: str = "v1.20", reverse: bool = False, cache_it=
81
81
  try:
82
82
  gh_client = GH_CLIENT
83
83
  repo = gh_client.get_repo("micropython/micropython")
84
- versions = [tag.name for tag in repo.get_tags() if parse(tag.name) >= parse(minver)]
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)]
85
86
  # Only keep the last preview
86
- versions = [v for v in versions if not v.endswith(V_PREVIEW) or v == versions[-1]]
87
+ preview = sorted([v for v in tags if v.endswith(V_PREVIEW)], reverse=True)[0]
88
+ versions.append(preview)
87
89
  except Exception as e:
88
- versions = [
89
- "v9.99.9-preview",
90
- "v1.22.2",
91
- "v1.22.1",
92
- "v1.22.0",
93
- "v1.21.1",
94
- "v1.21.0",
95
- "v1.20.0",
96
- "v1.19.1",
97
- "v1.19",
98
- "v1.18",
99
- "v1.17",
100
- "v1.16",
101
- "v1.15",
102
- "v1.14",
103
- "v1.13",
104
- "v1.12",
105
- "v1.11",
106
- "v1.10",
107
- ]
108
- cache_it = False
109
- versions = [v for v in versions if parse(v) >= parse(minver)]
110
- # remove all but the most recent (preview) version
111
- versions = versions[:1] + [v for v in versions if "preview" not in v]
90
+ log.error(e)
91
+ versions = []
92
+ # returns - but does not cache
93
+ raise NoCacheCondition(function_value=versions)
112
94
  # remove any duplicates and sort
113
95
  versions = sorted(list(set(versions)), reverse=reverse, key=lambda s: (not is_version(s), s))
114
96
  if cache_it:
@@ -117,16 +99,18 @@ def micropython_versions(minver: str = "v1.20", reverse: bool = False, cache_it=
117
99
  raise NoCacheCondition(function_value=versions)
118
100
 
119
101
 
120
- def get_stable_mp_version() -> str:
102
+ def get_stable_mp_version(cache_it=True) -> str:
121
103
  # read the versions from the git tags
122
- all_versions = micropython_versions(minver=OLDEST_VERSION)
123
- return [v for v in all_versions if not v.endswith(V_PREVIEW)][-1]
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 ""
124
107
 
125
108
 
126
- def get_preview_mp_version() -> str:
109
+ def get_preview_mp_version(cache_it=True) -> str:
127
110
  # read the versions from the git tags
128
- all_versions = micropython_versions(minver=OLDEST_VERSION)
129
- return [v for v in all_versions if v.endswith(V_PREVIEW)][-1]
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 ""
130
114
 
131
115
 
132
116
  # Do not cache , same path will have different versions checked out
@@ -1,19 +1,19 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: mpflash
3
- Version: 1.24.5
3
+ Version: 1.24.6
4
4
  Summary: Flash and download tool for MicroPython firmwares
5
- Home-page: https://github.com/Josverl/micropython-stubber/blob/main/src/mpflash/README.md
6
5
  License: MIT
7
6
  Keywords: MicroPython,firmware,flash,download,UF2,esptool
8
7
  Author: Jos Verlinde
9
8
  Author-email: jos_verlinde@hotmail.com
10
- Requires-Python: >=3.8.1,<4.0
9
+ Requires-Python: >=3.9,<4.0
11
10
  Classifier: License :: OSI Approved :: MIT License
12
11
  Classifier: Programming Language :: Python :: 3
13
12
  Classifier: Programming Language :: Python :: 3.9
14
13
  Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
17
  Classifier: Programming Language :: Python :: Implementation :: CPython
18
18
  Classifier: Programming Language :: Python :: Implementation :: MicroPython
19
19
  Classifier: Topic :: Software Development :: Build Tools
@@ -29,14 +29,16 @@ Requires-Dist: jsons (>=1.6.3,<2.0.0)
29
29
  Requires-Dist: libusb (>=1.0.27,<2.0.0) ; sys_platform == "win32"
30
30
  Requires-Dist: loguru (>=0.7.2,<0.8.0)
31
31
  Requires-Dist: mpremote (>=1.22.0,<2.0.0)
32
- Requires-Dist: packaging (==23.2)
32
+ Requires-Dist: packaging (>=24.2,<25.0)
33
33
  Requires-Dist: platformdirs (>=4.2.0,<5.0.0)
34
+ Requires-Dist: poetry (>=2.0.1,<3.0.0)
34
35
  Requires-Dist: psutil (>=5.9.8,<6.0.0)
35
36
  Requires-Dist: pygithub (>=2.1.1,<3.0.0)
36
37
  Requires-Dist: pyusb (>=1.2.1,<2.0.0)
37
38
  Requires-Dist: requests (>=2.31.0,<3.0.0)
38
39
  Requires-Dist: rich-click (>=1.8.1,<2.0.0)
39
40
  Requires-Dist: tenacity (==8.2.3)
41
+ Project-URL: Homepage, https://github.com/Josverl/micropython-stubber/blob/main/src/mpflash/README.md
40
42
  Project-URL: Repository, https://github.com/Josverl/micropython-stubber
41
43
  Description-Content-Type: text/markdown
42
44
 
@@ -1,7 +1,7 @@
1
1
  mpflash/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  mpflash/add_firmware.py,sha256=1h0HsA-EVi3HXLmoEvzwY_a-GuWYzPwulTYHHBB8THg,3428
3
3
  mpflash/ask_input.py,sha256=RJHGGrhYniSu-bdoKnKptE3DtpiCREJGRTZmFazvG-E,8946
4
- mpflash/basicgit.py,sha256=6dKexwx844R55q6X39ZDCF4HDB3t94OHyDJuuicZvjw,9959
4
+ mpflash/basicgit.py,sha256=NO27JTPUsnMWQ2bKI_zsIFsFTfCZO3QKbvQ23kIehxU,10734
5
5
  mpflash/bootloader/__init__.py,sha256=Qy3E6tETPnzMga9LgD5UgOvJ0zZIBEqhtEVb4v8CTWQ,107
6
6
  mpflash/bootloader/activate.py,sha256=FlO4XQlKyoOuvmDdj_0u_mjNPhjGwB_K17jQ-8nSXRA,2361
7
7
  mpflash/bootloader/detect.py,sha256=fBrILi7-ICRaregqms3PYqwiQVAJC0rXVhpyzDkoPQI,2690
@@ -13,11 +13,11 @@ mpflash/cli_flash.py,sha256=pVqEsDocDT3KmIMTpXdym-ZlzThLSIp6oVtYib65dys,7595
13
13
  mpflash/cli_group.py,sha256=VWwYHiPVV19sQEr5lL8LlcPyZ-A6Gs79eMDJy8LLt90,2615
14
14
  mpflash/cli_list.py,sha256=ja21AZ4yghGTtOHkEtV1EOmT6EYxOiU2gzJc-mZaDto,2427
15
15
  mpflash/cli_main.py,sha256=5EkvzsqOUDXvNaW814oSUcPWeNhnwh78Sg0MteDv_fk,1133
16
- mpflash/common.py,sha256=uNd9dUbPQE4KT-p3Y-od8jVE51b3IcHxDWHpY5vi6Yo,7964
16
+ mpflash/common.py,sha256=umTouKs5Wb7Q2zOaaoO9nqmlpHIaiDBRIGYIkZMBVO8,7558
17
17
  mpflash/config.py,sha256=tdpvAvAlpco1GfeG2evn5tAKYluLEanqwrrvkir7QcQ,1073
18
18
  mpflash/connected.py,sha256=woYhuXoWpfzRMDUpBLVQZbVTGtMsKWNd5z1rsR1ELXA,3578
19
19
  mpflash/download.py,sha256=wE4uBSFFMAKOBH4jwHweL0wVYh4vi74t1673ku_IeoA,14305
20
- mpflash/downloaded.py,sha256=5qrf-V1fNTTGeueXaZUAnEqa-Yqru2jLyztx0wdyeuc,4938
20
+ mpflash/downloaded.py,sha256=nxTWU4lvhcthqvVmzpYHnXCnjD8wJv0KFq2KtaoTO1A,5160
21
21
  mpflash/errors.py,sha256=IAidY3qkZsXy6Pm1rdmVFmGyg81ywHhse3itaPctA2w,247
22
22
  mpflash/flash/__init__.py,sha256=g4Fp8MiquaDZXIvRJwYRkkll1MMyRud7x6qmwCk9Lgo,2096
23
23
  mpflash/flash/esp.py,sha256=_VfbyYIEaUgAjsD66tjbdgYL6ElkSAfpIMKz6q4QKig,2287
@@ -33,21 +33,22 @@ mpflash/flash/worklist.py,sha256=owS3xJbWC-SzbK9z6jQER0Kat3OIV09IxnV-f-tjGlY,599
33
33
  mpflash/list.py,sha256=lP_S5xbC0Men9HsXcIxOsP0bFRlCYh5CynMLFJx8cEE,3607
34
34
  mpflash/logger.py,sha256=dI_H_a7EOdQJyvoeRHQuYeZuTKYVUS3DUPTLhE9rkdM,1098
35
35
  mpflash/mpboard_id/__init__.py,sha256=b9PJiKFqmfyYgfi0-pbWGp2mrljdgvO6DNy0ABS8izU,3898
36
- mpflash/mpboard_id/add_boards.py,sha256=47TtN98FVc6PvuOr-3-g3LacYW8JvXpM5Gr_jhdUGEU,9630
37
- mpflash/mpboard_id/board.py,sha256=CwtBux8y7GDUe7CADVxL8YefGRl9Fg8OAJBUhgaBYCI,1151
36
+ mpflash/mpboard_id/add_boards.py,sha256=Bc83FctlVl4u4j0xeKTfEkuQj0WWIqxtdUF1P5RTAvY,9900
37
+ mpflash/mpboard_id/board.py,sha256=JKb4T67HmK7widW-4c1PgilvywMbZYToLk9Fyokm-6Q,1163
38
38
  mpflash/mpboard_id/board_id.py,sha256=MnDWPqp0OqCkWD3E1Mhg-g20qASgPVHdROOCdr5TpOU,3249
39
- mpflash/mpboard_id/board_info.zip,sha256=XkIk35v6LotRMClCU-zEvo1zQiKXZAqkHfwLP4JhfaM,20102
39
+ mpflash/mpboard_id/board_info.zip,sha256=DC_yHwL8A8IC0YsA2ZXjlRLZkLKiw03k4FR2HSTfBXw,21328
40
40
  mpflash/mpboard_id/store.py,sha256=n85vnUAxGKv1C23wkm22ZFAFGK6AZZiCFvc1lGJJjis,1703
41
- mpflash/mpremoteboard/__init__.py,sha256=3F6vZHM1znUOnAo0ne-FalApM6vwbTNYg4kJwkS1gNI,9521
41
+ mpflash/mpremoteboard/__init__.py,sha256=Vydc7jZai32lrGTUjwylZT9U8yulsgLIk39mnuI_k9I,9666
42
42
  mpflash/mpremoteboard/mpy_fw_info.py,sha256=eRjhqN7MpmYE9TiS4iukquZZs3QE_lD5zv_vOPSjNrk,4821
43
43
  mpflash/mpremoteboard/runner.py,sha256=-PgzAeBGbyXaAUlwyiw4mcINsP2U1XRRjP1_QdBrxpg,4786
44
+ mpflash/vendor/board_database.py,sha256=QE3oXj96oTAsx94gNfHMYWu_RgBTHW1v9Wp5dq_Dt-Q,5253
44
45
  mpflash/vendor/click_aliases.py,sha256=c853EHSlkE2DvFqeFvFpwXKuJj3_jsXDP7iotVOKaAw,3156
45
46
  mpflash/vendor/dfu.py,sha256=ZXMcE6aH4-43Wh4tbQT4U-q-BU3RUiL3JAxmP_QAK2s,5755
46
47
  mpflash/vendor/pydfu.py,sha256=_MdBRo1EeNeKDqFPSTB5tNL1jGSBJgsVeVjE5e7Pb8s,20542
47
- mpflash/vendor/readme.md,sha256=iIIZxuLUIGHQ0KODzYVtMezsztvyxCXcNJp_AzwTIPk,86
48
- mpflash/versions.py,sha256=pKl-4GPHTs3_p73xywxSvsouZ3L4R2ljXSCkWj9U8HE,4742
49
- mpflash-1.24.5.dist-info/entry_points.txt,sha256=Jk_visOhYOsZIcSP2Ms9hKqfKy1iorR-6dYltSoWCpY,52
50
- mpflash-1.24.5.dist-info/LICENSE,sha256=mWpNhsIxWzetYNnTpr4eb3HtgsxGIC8KcYWxXEcxQvE,1077
51
- mpflash-1.24.5.dist-info/METADATA,sha256=mJfXKJ0R5EkBVnMLyRoixlpC2DmgbTj3ehYAdoTTzw4,17651
52
- mpflash-1.24.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
53
- mpflash-1.24.5.dist-info/RECORD,,
48
+ mpflash/vendor/readme.md,sha256=KcCbOVb_-9V6Cwwd0J01Avx4LuZphe9UJ40Gs-Hocf4,327
49
+ mpflash/versions.py,sha256=qGkE2LTzQ1QDyHc9-wzsHsRrN7PWK69xt0Vq3EVojms,4452
50
+ mpflash-1.24.6.dist-info/entry_points.txt,sha256=Jk_visOhYOsZIcSP2Ms9hKqfKy1iorR-6dYltSoWCpY,52
51
+ mpflash-1.24.6.dist-info/LICENSE,sha256=mWpNhsIxWzetYNnTpr4eb3HtgsxGIC8KcYWxXEcxQvE,1077
52
+ mpflash-1.24.6.dist-info/METADATA,sha256=H5PkYQyib3lTOeIc2HPGJjP6PTNxUUVb02UP2GoY8TM,17757
53
+ mpflash-1.24.6.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
54
+ mpflash-1.24.6.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.0
2
+ Generator: poetry-core 2.0.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any