mpflash 1.25.0rc4__py3-none-any.whl → 1.25.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.
mpflash/flash/worklist.py CHANGED
@@ -1,11 +1,12 @@
1
1
  """Worklist for updating boards"""
2
2
 
3
- from pathlib import Path
4
- from typing import Dict, List, Optional, Tuple
3
+ from typing import List, Optional, Tuple
5
4
 
6
5
  from loguru import logger as log
6
+ from serial.tools.list_ports_common import ListPortInfo
7
+ from typing_extensions import TypeAlias
7
8
 
8
- from mpflash.common import filtered_comports
9
+ from mpflash.common import filtered_portinfos
9
10
  from mpflash.db.models import Firmware
10
11
  from mpflash.downloaded import find_downloaded_firmware
11
12
  from mpflash.errors import MPFlashError
@@ -14,11 +15,12 @@ from mpflash.mpboard_id import find_known_board
14
15
  from mpflash.mpremoteboard import MPRemoteBoard
15
16
 
16
17
  # #########################################################################################################
17
- WorkList = List[Tuple[MPRemoteBoard, Optional[Firmware]]]
18
+ FlashItem: TypeAlias = Tuple[MPRemoteBoard, Optional[Firmware]]
19
+ WorkList: TypeAlias = List[FlashItem]
18
20
  # #########################################################################################################
19
21
 
20
22
 
21
- def auto_update(
23
+ def auto_update_worklist(
22
24
  conn_boards: List[MPRemoteBoard],
23
25
  target_version: str,
24
26
  ) -> WorkList:
@@ -32,6 +34,7 @@ def auto_update(
32
34
  Returns:
33
35
  WorkList: List of boards and firmware information to update
34
36
  """
37
+ log.debug(f"auto_update_worklist: {len(conn_boards)} boards, target version: {target_version}")
35
38
  wl: WorkList = []
36
39
  for mcu in conn_boards:
37
40
  if mcu.family not in ("micropython", "unknown"):
@@ -59,12 +62,29 @@ def auto_update(
59
62
 
60
63
 
61
64
  def manual_worklist(
62
- serial: str,
65
+ serial: List[str],
63
66
  *,
64
67
  board_id: str,
65
68
  version: str,
69
+ custom: bool = False,
66
70
  ) -> WorkList:
67
- """Create a worklist for a single board specified manually.
71
+ """Create a worklist for manually specified boards."""
72
+ log.debug(f"manual_worklist: {len(serial)} serial ports, board_id: {board_id}, version: {version}")
73
+ wl: WorkList = []
74
+ for comport in serial:
75
+ log.trace(f"Manual updating {comport} to {board_id} {version}")
76
+ wl.append(manual_board(comport, board_id=board_id, version=version, custom=custom))
77
+ return wl
78
+
79
+
80
+ def manual_board(
81
+ serial: str,
82
+ *,
83
+ board_id: str,
84
+ version: str,
85
+ custom: bool = False,
86
+ ) -> FlashItem:
87
+ """Create a Flash work item for a single board specified manually.
68
88
 
69
89
  Args:
70
90
  serial (str): Serial port of the board
@@ -72,9 +92,9 @@ def manual_worklist(
72
92
  version (str): Firmware version
73
93
 
74
94
  Returns:
75
- WorkList: List of boards and firmware information to update
95
+ FlashItem: Board and firmware information to update
76
96
  """
77
- log.trace(f"Manual updating {serial} to {board_id} {version}")
97
+ log.debug(f"manual_board: {serial} {board_id} {version}")
78
98
  mcu = MPRemoteBoard(serial)
79
99
  # Lookup the matching port and cpu in board_info based in the board name
80
100
  try:
@@ -85,14 +105,14 @@ def manual_worklist(
85
105
  except (LookupError, MPFlashError) as e:
86
106
  log.error(f"Board {board_id} not found in board database")
87
107
  log.exception(e)
88
- return []
108
+ return (mcu, None)
89
109
  mcu.board = board_id
90
- firmwares = find_downloaded_firmware(board_id=board_id, version=version, port=mcu.port)
110
+ firmwares = find_downloaded_firmware(board_id=board_id, version=version, port=mcu.port, custom=custom)
91
111
  if not firmwares:
92
- log.error(f"No firmware found for {mcu.port} {board_id} version {version}")
93
- return []
112
+ log.trace(f"No firmware found for {mcu.port} {board_id} version {version}")
113
+ return (mcu, None)
94
114
  # use the most recent matching firmware
95
- return [(mcu, firmwares[-1])] # type: ignore
115
+ return (mcu, firmwares[-1]) # type: ignore
96
116
 
97
117
 
98
118
  def single_auto_worklist(
@@ -109,9 +129,10 @@ def single_auto_worklist(
109
129
  Returns:
110
130
  WorkList: List of boards and firmware information to update
111
131
  """
132
+ log.debug(f"single_auto_worklist: {serial} version: {version}")
112
133
  log.trace(f"Auto updating {serial} to {version}")
113
134
  conn_boards = [MPRemoteBoard(serial)]
114
- todo = auto_update(conn_boards, version) # type: ignore # List / list
135
+ todo = auto_update_worklist(conn_boards, version) # type: ignore # List / list
115
136
  show_mcus(conn_boards)
116
137
  return todo
117
138
 
@@ -125,7 +146,7 @@ def full_auto_worklist(
125
146
  ) -> WorkList:
126
147
  """
127
148
  Create a worklist for all connected micropython boards based on the information retrieved from the board.
128
- This allows the firmware version of one or moae boards to be changed without needing to specify the port or board_id manually.
149
+ This allows the firmware version of one or more boards to be changed without needing to specify the port or board_id manually.
129
150
 
130
151
  Args:
131
152
  version (str): Firmware version
@@ -133,9 +154,9 @@ def full_auto_worklist(
133
154
  Returns:
134
155
  WorkList: List of boards and firmware information to update
135
156
  """
136
- log.trace(f"Auto updating all boards to {version}")
157
+ log.debug(f"full_auto_worklist: {len(all_boards)} boards, include: {include}, ignore: {ignore}, version: {version}")
137
158
  if selected_boards := filter_boards(all_boards, include=include, ignore=ignore):
138
- return auto_update(selected_boards, version)
159
+ return auto_update_worklist(selected_boards, version)
139
160
  else:
140
161
  return []
141
162
 
@@ -149,7 +170,7 @@ def filter_boards(
149
170
  try:
150
171
  comports = [
151
172
  p.device
152
- for p in filtered_comports(
173
+ for p in filtered_portinfos(
153
174
  ignore=ignore,
154
175
  include=include,
155
176
  bluetooth=False,
mpflash/list.py CHANGED
@@ -90,6 +90,7 @@ def mcu_table(
90
90
  if needs_build:
91
91
  table.add_column("Build" if is_wide else "Bld", justify="right")
92
92
  if config.usb:
93
+ table.add_column("vid:pid", overflow="fold", max_width=14)
93
94
  table.add_column("Location", overflow="fold", max_width=60)
94
95
  # fill the table with the data
95
96
  for mcu in conn_mcus:
@@ -111,6 +112,7 @@ def mcu_table(
111
112
  if needs_build:
112
113
  row.append(mcu.build)
113
114
  if config.usb:
115
+ row.append(f"{mcu.vid:04x}:{mcu.pid:04x}")
114
116
  row.append(mcu.location)
115
117
 
116
118
  table.add_row(*row)
mpflash/logger.py CHANGED
@@ -5,6 +5,7 @@ Ensures log messages are compatible with the current console encoding.
5
5
  Removes or replaces Unicode icons if the encoding is not UTF-8.
6
6
  """
7
7
 
8
+ import functools
8
9
  import sys
9
10
 
10
11
  from loguru import logger as log
@@ -14,12 +15,17 @@ from .config import config
14
15
 
15
16
  console = Console()
16
17
 
18
+
17
19
  # Detect if the output encoding supports Unicode (UTF-8)
20
+ @functools.lru_cache(maxsize=1)
18
21
  def _is_utf8_encoding() -> bool:
19
- encoding = getattr(sys.stdout, "encoding", None)
20
- if encoding is None:
22
+ try:
23
+ encoding = getattr(sys.stdout, "encoding", None)
24
+ if encoding is None:
25
+ return False
26
+ return encoding.lower().replace("-", "") == "utf8"
27
+ except BaseException:
21
28
  return False
22
- return encoding.lower().replace("-", "") == "utf8"
23
29
 
24
30
 
25
31
  def _log_formatter(record: dict) -> str:
@@ -27,6 +33,7 @@ def _log_formatter(record: dict) -> str:
27
33
  Log message formatter for loguru and rich.
28
34
 
29
35
  Removes Unicode icons if console encoding is not UTF-8.
36
+ Handles messages containing curly braces safely.
30
37
  """
31
38
  color_map = {
32
39
  "TRACE": "cyan",
@@ -43,21 +50,34 @@ def _log_formatter(record: dict) -> str:
43
50
  icon = record["level"].icon
44
51
  else:
45
52
  icon = record["level"].name # fallback to text
46
- # Insert color directly using f-string
47
- return f"[not bold green]{{time:HH:mm:ss}}[/not bold green] | {icon} [{lvl_color}]{record['message']}[/{lvl_color}]"
53
+ # Escape curly braces in the message to prevent format conflicts
54
+ safe_message = record["message"].replace("{", "{{").replace("}", "}}")
55
+ # Use string concatenation to avoid f-string format conflicts
56
+ time_part = "[not bold green]{time:HH:mm:ss}[/not bold green]"
57
+ message_part = f"[{lvl_color}]{safe_message}[/{lvl_color}]"
58
+ return f"{time_part} | {icon} {message_part}"
48
59
 
49
60
 
50
61
  def set_loglevel(loglevel: str) -> None:
51
62
  """
52
63
  Set the log level for the logger.
53
64
 
54
- Ensures Unicode safety for log output.
65
+ Ensures Unicode safety for log output and handles format errors.
55
66
  """
56
67
  try:
57
68
  log.remove()
58
69
  except ValueError:
59
70
  pass
60
- log.add(console.print, level=loglevel.upper(), colorize=False, format=_log_formatter) # type: ignore
71
+
72
+ # Add error handling for format issues
73
+ def safe_format_wrapper(message):
74
+ try:
75
+ console.print(message)
76
+ except (KeyError, ValueError) as e:
77
+ # Fallback to simple text output if formatting fails
78
+ console.print(f"[LOG FORMAT ERROR] {message} (Error: {e})")
79
+
80
+ log.add(safe_format_wrapper, level=loglevel.upper(), colorize=False, format=_log_formatter) # type: ignore
61
81
 
62
82
 
63
83
  def make_quiet() -> None:
@@ -2,7 +2,6 @@
2
2
  Translate board description to board designator
3
3
  """
4
4
 
5
-
6
5
  from typing import List, Optional
7
6
 
8
7
  from mpflash.db.core import Session
@@ -17,25 +16,24 @@ def find_board_id_by_description(
17
16
  short_descr: str,
18
17
  *,
19
18
  version: str,
20
- ) -> Optional[str]:
19
+ ) -> str:
21
20
  """Find the MicroPython BOARD_ID based on the description in the firmware"""
22
21
  version = clean_version(version) if version else ""
23
- try:
22
+ boards = _find_board_id_by_description(
23
+ descr=descr,
24
+ short_descr=short_descr,
25
+ version=version,
26
+ )
27
+ if not boards:
28
+ log.debug(f"Version {version} not found in board info, using any version")
24
29
  boards = _find_board_id_by_description(
25
30
  descr=descr,
26
31
  short_descr=short_descr,
27
- version=version,
32
+ version="%", # any version
28
33
  )
29
- if not boards:
30
- log.debug(f"Version {version} not found in board info, using any version")
31
- boards = _find_board_id_by_description(
32
- descr=descr,
33
- short_descr=short_descr,
34
- version="%", # any version
35
- )
36
- return boards[0].board_id if boards else None
37
- except MPFlashError:
38
- return "UNKNOWN_BOARD"
34
+ if not boards:
35
+ raise MPFlashError(f"No board info found for description '{descr}' or '{short_descr}'")
36
+ return boards[0].board_id
39
37
 
40
38
 
41
39
  def _find_board_id_by_description(
@@ -63,7 +61,5 @@ def _find_board_id_by_description(
63
61
  )
64
62
  boards = qry.all()
65
63
 
66
- if not boards:
67
- raise MPFlashError(f"No board info found for description '{descr}' or '{short_descr}'")
68
- return boards
69
64
 
65
+ return boards
@@ -64,9 +64,15 @@ def known_stored_boards(port: str, versions: List[str] = []) -> List[Tuple[str,
64
64
 
65
65
 
66
66
  def find_known_board(board_id: str, version="") -> Board:
67
- """Find the board for the given BOARD_ID or 'board description' and return the board info as a Board object"""
67
+ """
68
+ Find the board for the given BOARD_ID or 'board description'
69
+ if the board_id is not found, it will try to find it by description.
70
+
71
+ if the board_id contains an @, it will split it and use the first part as the board_id
72
+ Returns the board info as a Board object
73
+ """
68
74
  with Session() as session:
69
- qry = session.query(Board).filter(Board.board_id == board_id)
75
+ qry = session.query(Board).filter(Board.board_id == board_id.split("@")[0])
70
76
  if version:
71
77
  qry = qry.filter(Board.version == version)
72
78
  board = qry.first()
@@ -3,6 +3,7 @@ Module to run mpremote commands, and retry on failure or timeout
3
3
  """
4
4
 
5
5
  import contextlib
6
+ import re
6
7
  import sys
7
8
  import time
8
9
  from pathlib import Path
@@ -22,6 +23,8 @@ if sys.version_info >= (3, 11):
22
23
  else:
23
24
  import tomli as tomllib # type: ignore
24
25
 
26
+ import tomli_w
27
+
25
28
  ###############################################################################################
26
29
  HERE = Path(__file__).parent
27
30
 
@@ -61,6 +64,13 @@ class MPRemoteBoard:
61
64
  self.build = ""
62
65
  self.location = location # USB location
63
66
  self.toml = {}
67
+ portinfo = list(serial.tools.list_ports.grep(serialport)) # type: ignore
68
+ if not portinfo or len(portinfo) != 1:
69
+ self.vid = 0x00
70
+ self.pid = 0x00
71
+ else:
72
+ self.vid = portinfo[0].vid
73
+ self.pid = portinfo[0].pid
64
74
  if update:
65
75
  self.get_mcu_info()
66
76
 
@@ -76,7 +86,14 @@ class MPRemoteBoard:
76
86
 
77
87
  @property
78
88
  def board(self) -> str:
79
- return self._board_id.split("-")[0]
89
+ _board = self._board_id.split("-")[0]
90
+ # Workaround for Pimoroni boards
91
+ if not "-" in self._board_id:
92
+ # match with the regex : (.*)(_\d+MB)$
93
+ match = re.match(r"(.*)_(\d+MB)$", self._board_id)
94
+ if match:
95
+ _board = match.group(1)
96
+ return _board
80
97
 
81
98
  @board.setter
82
99
  def board(self, value: str) -> None:
@@ -84,7 +101,14 @@ class MPRemoteBoard:
84
101
 
85
102
  @property
86
103
  def variant(self) -> str:
87
- return self._board_id.split("-")[1] if "-" in self._board_id else ""
104
+ _variant = self._board_id.split("-")[1] if "-" in self._board_id else ""
105
+ if not _variant:
106
+ # Workaround for Pimoroni boards
107
+ # match with the regex : (.*)(_\d+MB)$
108
+ match = re.match(r"(.*)_(\d+MB)$", self._board_id)
109
+ if match:
110
+ _variant = match.group(2)
111
+ return _variant
88
112
 
89
113
  @variant.setter
90
114
  def variant(self, value: str) -> None:
@@ -216,14 +240,48 @@ class MPRemoteBoard:
216
240
  self.toml = {}
217
241
  if rc in [OK]: # sometimes we get an -9 ???
218
242
  try:
243
+ log.trace(result)
219
244
  # Ok we have the info, now parse it
220
245
  self.toml = tomllib.loads("".join(result))
221
- log.debug(f"board_info.toml: {self.toml}")
246
+ log.debug(f"board_info.toml: {self.toml['description']}")
222
247
  except Exception as e:
223
248
  log.error(f"Failed to parse board_info.toml: {e}")
224
249
  else:
225
250
  log.trace(f"Did not find a board_info.toml: {result}")
226
251
 
252
+ def set_board_info_toml(self, timeout: int = 1):
253
+ """
254
+ Writes the current board information to the board_info.toml file on the connected board.
255
+
256
+ Parameters:
257
+ - timeout (int): The timeout value in seconds.
258
+ """
259
+ if not self.connected:
260
+ raise MPFlashError("Board is not connected")
261
+ if not self.toml:
262
+ log.warning("No board_info.toml to write")
263
+ return
264
+ # write the toml file to a temp file, then copy to the board
265
+
266
+ toml_path = HERE / "tmp_board_info.toml"
267
+ try:
268
+ with open(toml_path, "wb") as f:
269
+ tomli_w.dump(self.toml, f)
270
+
271
+ log.debug(f"Writing board_info.toml to {self.serialport}")
272
+ rc, result = self.run_command(
273
+ ["cp", str(toml_path), ":board_info.toml"],
274
+ no_info=True,
275
+ timeout=timeout,
276
+ log_errors=False,
277
+ )
278
+ except Exception as e:
279
+ raise MPFlashError(f"Failed to write board_info.toml for {self.serialport}: {e}") from e
280
+ finally:
281
+ # remove the temp file
282
+ if toml_path.exists():
283
+ toml_path.unlink()
284
+
227
285
  def disconnect(self) -> bool:
228
286
  """
229
287
  Disconnect from a board.
@@ -92,6 +92,7 @@ def run(
92
92
  except FileNotFoundError as e:
93
93
  raise FileNotFoundError(f"Failed to start {cmd[0]}") from e
94
94
  _timed_out = False
95
+
95
96
  def timed_out():
96
97
  _timed_out = True
97
98
  if log_warnings:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: mpflash
3
- Version: 1.25.0rc4
3
+ Version: 1.25.2
4
4
  Summary: Flash and download tool for MicroPython firmwares
5
5
  License: MIT
6
6
  Keywords: MicroPython,firmware,flash,download,UF2,esptool
@@ -37,6 +37,7 @@ Requires-Dist: requests (>=2.31.0,<3.0.0)
37
37
  Requires-Dist: rich-click (>=1.8.1,<2.0.0)
38
38
  Requires-Dist: sqlalchemy (>=2.0.41,<3.0.0)
39
39
  Requires-Dist: tenacity (==9.0.0)
40
+ Requires-Dist: tomli-w (>=1.2.0,<2.0.0)
40
41
  Project-URL: Homepage, https://github.com/Josverl/mpflash/blob/main/README.md
41
42
  Project-URL: Repository, https://github.com/Josverl/mpflash
42
43
  Description-Content-Type: text/markdown
@@ -58,9 +59,22 @@ This tool was initially created to be used in a CI/CD pipeline to automate the p
58
59
  - `samd`, using ` .uf2`, using filecopy
59
60
  - `esp32`, using `.bin`, using esptool,
60
61
  - `esp8266`, using `.bin`, using esptool
61
- - `stm32`, using ` .dfu`, using pydfu
62
+ - `stm32`, using ` .dfu`, using pydfu (also in Windows)
62
63
 
63
64
  Not yet implemented: `nrf`, `cc3200`, `mimxrt`, `renesas`
65
+
66
+ ## Release v1.25.0(.post2)
67
+
68
+ This release includes several new features and improvements:
69
+ - **New features:**
70
+ - Added support for `--variant` option to specify a specific variant of the board when flashing.
71
+ - mpflash now uses a slqlite database to store information on all possible micropython firmwares, and the management of the downloaded firmware files.
72
+ - This allows for a better identification of boards, and matches to the correct firmware.
73
+ - Use the MicroPython v1.25.0 `sys.implementation._build` to as board_id when avaialable
74
+ - Automatically try to download firmware if not yet available locally. No lonmger need to specify the `--download` option.
75
+ - Restructured mpboard_id to use a SQLite db to be able to ID more boards and variants
76
+ - vendored and adapted `board_database.py` from mpflash, kudos @mattytrentini
77
+
64
78
 
65
79
  ## Features
66
80
  1. List the connected boards including their firmware details, in a tabular or json format
@@ -79,15 +93,54 @@ You can use mpflash to perform various operations on your MicroPython boards. He
79
93
  | Command | Description |
80
94
  |---------|-------------|
81
95
  | `mpflash list` | List the connected board(s) including their firmware details |
96
+ | `mpflash flash` | Flash the latest stable firmware to the connected board(s), downloading the firmware if needed |
82
97
  | `mpflash download` | Download the MicroPython firmware(s) for the connected board(s) |
83
- | `mpflash flash` | Flash the latest stable firmware to the connected board(s) |
84
98
 
85
- ## selecting or ignoring specific serial ports
99
+ **Listing connected boards:**
100
+ `mpflash list` will list all connected boards in a table , including their serial port, family, board name, CPU, version and build number.
101
+ Options are available to list the boards in a json format, or to filter the list by serial port or board type.
102
+
103
+
104
+ **Flashing boards with new firmware:**
105
+ `mpflash flash` will flash the latest stable firmware to all connected boards, downloading the firmware if needed.
106
+ It will try to determine the current micropython borad and variant, download the firmware if needed, and flash the correct firmware to each board.
107
+
108
+ Common options are:
109
+
110
+ - `--version` to specify the version of the firmware to flash, defaults to the latest stable version.
111
+ - `--serial` to specify the serial port(s) to flash, defaults to all connected boards.
112
+ - `--board` to specify which firmware to flash to a single board
113
+ - `--variant` to specify a specific variant of the board
114
+
115
+ **Downloading firmware:**
116
+ `mpflash download` will download the latest stable firmware for all connected boards, or a specific board if specified. It will download the firmware from the official MicroPython website and save it in your `Downloads/firmware` directory.
117
+ When a board is specified for which multiple variants are available, all variants will be downloaded.
118
+
119
+ Common options are:
120
+
121
+ - `--version` to specify the version of the firmware to download, defaults to the latest stable version. (e.g. `stable`, `preview`, `x.y.z`)
122
+ - `--serial` to specify the serial port(s) to flash, defaults to all connected boards.
123
+ - `--board` to specify which firmware to flash to a single board
86
124
 
87
- You can use the `--serial` option to select a specific serial port to flash, or the `--ignore` option to ignore a specific serial port.
88
- both options can be specified multiple times
89
- Both can be globs (e.g. COM*) or exact port names (e.g. COM1)
90
- in addition there is a --bluetooth option to simplify ignoring bluetooth ports
125
+ ## Setting the Firmware Files and Database Location
126
+
127
+ You can override the default location for firmware files and the MPFlash database by setting the `MPFLASH_FIRMWARE` environment variable. For example, in a Bash shell:
128
+
129
+ ```bash
130
+ export MPFLASH_FIRMWARE="/path/to/custom/firmware"
131
+ ```
132
+
133
+ When this variable is set, `mpflash` will use that location to store firmware files and estabish it's database.
134
+
135
+ ## Selecting or ignoring specific serial ports
136
+
137
+ You can use the `--serial` option to select a specific serial port(s) to flash,
138
+ Or you can use the `--ignore` option to ignore a specific serial port(s).
139
+
140
+ Either option can be specified multiple times, can be globs (e.g. COM*) or exact port names (e.g. /dev/ttyUSB0).
141
+ To permenently ignore a port, you can set the `MPFLASH_IGNORE` environment variable to a space-separated list of serial ports or globs.
142
+
143
+ In addition there is a --bluetooth option to simplify ignoring bluetooth ports, where the default is to ignore bluetooth ports.
91
144
 
92
145
  ```
93
146
  --serial,--serial-port -s SERIALPORT Serial port(s) (or globs) to list. [default: *] > > --ignore -i SERIALPORT Serial port(s) (or globs) to ignore. Defaults to MPFLASH_IGNORE. │
@@ -102,9 +155,9 @@ This file can contain a description of the board, which will be shown in the lis
102
155
  description = "Blue Norwegian actuator"
103
156
  ```
104
157
 
105
- If you want the board to be ignored by mpflash, you can add the following to the board_info.toml file:
158
+ If you want the board to be ignored by mpflash, no matter which serial port it is connected to, you can add the following to the `board_info.toml` file:
106
159
  ```toml
107
- description = "Blue Norwegian feeder"
160
+ description = "Blue Norwegian actuator"
108
161
  [mpflash]
109
162
  ignore = true
110
163
  ```
@@ -1,36 +1,38 @@
1
1
  mpflash/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- mpflash/add_firmware.py,sha256=P1yaNUdExfzC_qnhE-P5ALZg1Uh7XT6Xf7NYccJP7Rc,4317
3
2
  mpflash/ask_input.py,sha256=YUx65Xwj6dNPwWcbQiWG7U4wDW69zEdno2HcT1KwPBg,8886
4
- mpflash/basicgit.py,sha256=Aiz6rF6PVhQir-FU-T1NhbjsW803y39Js6xnWs8-yu4,9676
3
+ mpflash/basicgit.py,sha256=J1jWsM3QuYZLjj-e9yTsj7dLkxPvT4MFz3_YaEttyXg,10190
5
4
  mpflash/bootloader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
5
  mpflash/bootloader/activate.py,sha256=orQOw4XTkXVZI-rMInRb0T5Wp3qA_BlzbJUA2gyBToU,2361
7
6
  mpflash/bootloader/detect.py,sha256=OagP2QVWeLLWkZt2paqEF6r4_x3QDcBGNCPOWfMy9NQ,2686
8
7
  mpflash/bootloader/manual.py,sha256=WYC4x-dxrSwVUfgnKTlu34pCzckrWJKZnWsARDocycI,3169
9
8
  mpflash/bootloader/micropython.py,sha256=v_kZkvg0uWZDbMrT78gmiYHbD83QLdnrctvEClI8iRg,529
10
9
  mpflash/bootloader/touch1200.py,sha256=VND7_YniS9Vx6WEaAxjI72RZZ6WBOwmBTsKJkbuaAHk,1105
11
- mpflash/cli_download.py,sha256=sMMIVTE4P9O2GpWB9jcbOiKQX-XJ0nu2bBylRbWu0X8,3872
12
- mpflash/cli_flash.py,sha256=QQ7fml84UBK_dUDb1G7DT5_MBDbZbXcWEhkgOq2P8gA,7962
13
- mpflash/cli_group.py,sha256=Uf_1ZmeeSIsaGLuuKn3KPPPVi8fJVbIacJYFZx_oPHc,2684
14
- mpflash/cli_list.py,sha256=ZuRalXXjDGo6FhgMTv54BQD_PNss7eeopeZQ_uE1J90,2632
15
- mpflash/cli_main.py,sha256=NMhEtMtSe7ApE-210Q4p-g7ZgewgO-4z1Q-vNKLQ47Y,1277
16
- mpflash/common.py,sha256=iKDoc6Ut8XbZ8fYLEI2XsoU7GuG_pFG0KGcRWXPl1wE,5922
17
- mpflash/config.py,sha256=bmwNSJzk27iHcI-r3C6hm6-TeOat2ymzbbv-Q-xuO2o,3048
18
- mpflash/connected.py,sha256=oxZdk1o-AfNPhJsSxr3KrMH_gdYfrjqc_IpT6J8Ng9k,3496
10
+ mpflash/cli_add.py,sha256=hI-o-9hAGD3U8cbpXvy9Nuv1KHNTZ6mS57LC4BTBtj8,3495
11
+ mpflash/cli_download.py,sha256=EeAK5NcuJq0UeePSyHtPvBj_jEt92gh0jBmeNUcA7i0,3555
12
+ mpflash/cli_flash.py,sha256=SekC3goAu9_8UvMRMTEzIiiOK8js1GJRC6ymyA3BQWg,8820
13
+ mpflash/cli_group.py,sha256=RITn2u1_77jKptapX0Vz3oUriPtGMzLVmjZOtM5SP88,2686
14
+ mpflash/cli_list.py,sha256=dznrQrWQXvev20ai5AFvz2DFe3MNDR5RIrJmtvQou6A,2693
15
+ mpflash/cli_main.py,sha256=w5o3swYWDZUnYwIH46hGMCiFdPKVL1-R1YJRM-RSMiY,1496
16
+ mpflash/common.py,sha256=wO3BjG1wtbfi37wNWPnmLk3jNi7kRUl1vTzgJUOwm9I,6355
17
+ mpflash/config.py,sha256=3JIOuKcVIWzV3Y24n6ag_XJpSczMcCbd1fa6FpWGiz8,4143
18
+ mpflash/connected.py,sha256=SZvqbnLztJH-DBByjGrWT24S5DGTSevWSwYncH6dFqk,3707
19
+ mpflash/custom/__init__.py,sha256=l9RU9hRm9j7IuRgacw-gHYjA2Op-5prvRO5yyODhFMQ,5269
20
+ mpflash/custom/naming.py,sha256=uHQzFIDzuWQUNajeGSUcf_A-o7cxX37kfgXhzpFHNtk,3304
19
21
  mpflash/db/__init__.py,sha256=wnIlO4nOXsPGXMbn2OCqHRsR-hUmtJsko8VdqjH3ZUE,45
20
- mpflash/db/core.py,sha256=hyzurZp8QMl8Q9B00Q-tOkOUp68T8XhM7tj3dm5cDHw,2283
21
- mpflash/db/gather_boards.py,sha256=8QS7NIt3n9ROqtgVAnoqU8YMeObLGaN2pvJL7d_kULA,3905
22
- mpflash/db/loader.py,sha256=0L4I3ySaGLFlzy9FlV7_nzbqzA6MHwi0FhgDG5FJ_9U,4848
23
- mpflash/db/meta.py,sha256=I7JycEx37MVVYowA0VFfUYFX9IURiTTsWQ1RhFgGqes,2251
24
- mpflash/db/micropython_boards.zip,sha256=cc4m7VSskj__rhabw3j5OZCiz1yEi6yCx7JGFn1QB0k,16647
25
- mpflash/db/models.py,sha256=Q4yjZPcNRIGWevoACeGDS1i31QX6jq1q5TsyPjmdmz4,3448
22
+ mpflash/db/core.py,sha256=6Ftp-Br3fmVO5prsvR7oc-XfF3qLJrTOy2YKosQeQQk,5271
23
+ mpflash/db/gather_boards.py,sha256=r867g1U4xRRSGLie8cYtdotLyqy9Y7plxfqGQb-1ayw,3970
24
+ mpflash/db/loader.py,sha256=CDlTj2T6w9Ch9s3RHi00E1TbUhjFsgXAsYSQr5kliB0,4889
25
+ mpflash/db/meta.py,sha256=2pFTpFH-1zejGIDp2vs0hbX5rqUONt7B1WIvf8qBx5s,2248
26
+ mpflash/db/micropython_boards.zip,sha256=K9Y0P6JBYlgoY_mR6m_pEVtNxzO9JHaQlb_TCZACcPI,17059
27
+ mpflash/db/models.py,sha256=hZrum-nS-TNFaZAksApjxYMBgGKI_kJ-4oFxc8a4WRk,3572
26
28
  mpflash/db/tools.py,sha256=6SEGfshNob4yRQ4h-Cj_xcWMRY28sbA8CWauNXV_uMI,814
27
- mpflash/download/__init__.py,sha256=zidXvsSFCfR-BZCZ6TiB7uEucEuUqXnZhKSfTs60lzU,7930
29
+ mpflash/download/__init__.py,sha256=EQez0Gj70rgrcJDbWEMYlezQyGgD747ipwmB0nt9eUI,9575
28
30
  mpflash/download/from_web.py,sha256=PVJDaFfYLJGXlPva5fExh4Yg2H7j3idyJEcfOiVVJBs,7608
29
- mpflash/download/fwinfo.py,sha256=gpa92PkysT1B7mxPAFJ-b_6y03QCNgHKm-J6T_RFNMI,1852
30
- mpflash/download/jid.py,sha256=503HW4jIB22fsb9vYphXqqO33LTMtvPdENG81wKDgMs,2334
31
- mpflash/downloaded.py,sha256=508sqROPf0Ymz7UxMzReXtK6mG1EcoXA-ysGdzV-VM0,4040
31
+ mpflash/download/fwinfo.py,sha256=XGWOWoJ9cqRVtBAgzVYWCIWaBZpLK595SniXn7bzrRk,1844
32
+ mpflash/download/jid.py,sha256=V57M4K0uXXxBYOB4zOKkmXvUvEQdM_-w22LZ-iMIJSE,2344
33
+ mpflash/downloaded.py,sha256=xaeMYrTIGj_v4scUBojeJPL-U1kWJG-bdvkvJMbPh4Q,4218
32
34
  mpflash/errors.py,sha256=IAidY3qkZsXy6Pm1rdmVFmGyg81ywHhse3itaPctA2w,247
33
- mpflash/flash/__init__.py,sha256=jif7-ifsXMabidjNdqUQyl1CwD5_USjCAZFhU5W-Aw8,2992
35
+ mpflash/flash/__init__.py,sha256=fkA_3pax9ZLckb14zFxATGk1YWMenpHBlvi66qJCIJA,3433
34
36
  mpflash/flash/esp.py,sha256=4977E1hDqJ4-EIkLzwrUtgZuc0ZTD7NvP1PQZgZ2DoU,3227
35
37
  mpflash/flash/stm32.py,sha256=jNgMpJaxUwtJ-v6VU1luD1t41AQprCUeNVCVEovxQe0,595
36
38
  mpflash/flash/stm32_dfu.py,sha256=W-3JsRQyf3DduoIRXDmGZ35RogqtjQgcJnk-GOtQoLE,3090
@@ -39,20 +41,20 @@ mpflash/flash/uf2/boardid.py,sha256=U5wGM8VA3wEpUxQCMtuXpMZZomdVH8J_Zd5_GekUMuU,
39
41
  mpflash/flash/uf2/linux.py,sha256=uTgqyS7C7xfQ25RrTcSUkt-m2u2Ks_o7bPLzIecPoC8,4355
40
42
  mpflash/flash/uf2/macos.py,sha256=JTaIpqnR_0k4oSEvzs9amhmK-PMxUJyZLnZ_wZwxa-0,1228
41
43
  mpflash/flash/uf2/uf2disk.py,sha256=4_P2l-kedM7VSliA2u706LQLxvu3xWSod1-lj-xjZis,298
42
- mpflash/flash/uf2/windows.py,sha256=tf2doFbhS1iA8hGUFFiHHASJvo71PgsmozhVnav79cI,1342
43
- mpflash/flash/worklist.py,sha256=ZqbgYChXFGEVLVlGKeS9eJJDToxBYqjrfWE2NIa7Cck,5622
44
- mpflash/list.py,sha256=NNhKpRh3ARZMdq56GLJgJ67GeuUf9SxjTzFhQjDsi9A,4008
45
- mpflash/logger.py,sha256=oMGBhfHv0edPJaUxiqAjkQ5Na2B687f94LqE-IR7C-U,1885
44
+ mpflash/flash/uf2/windows.py,sha256=OEeskObPtpIE4a5NzYIcBqg3FkM5MGPGEa4lGGOfntY,1338
45
+ mpflash/flash/worklist.py,sha256=wf-R9yPsmcE54dnoPA29pEEzNPZI3JwY85V_DB0hXNI,6584
46
+ mpflash/list.py,sha256=IrJa3UBjhHHfStbb9fPVYA8JJzoFTyXtbcKGNRSH8sE,4132
47
+ mpflash/logger.py,sha256=XLu4VzMhMPlCdOo2HeS4GfyatE1swwwonV8c6a-GoD4,2651
46
48
  mpflash/mpboard_id/__init__.py,sha256=Z6gDDWTCSKPp2fsuaUz80zgrklBR9XDlSLF9y_evR9A,391
47
49
  mpflash/mpboard_id/alternate.py,sha256=ZhqfdA9sLJmyOfJ6WwK9wrzzUn6JQdkAreiL0q5XEQg,1913
48
- mpflash/mpboard_id/board_id.py,sha256=dGbYnqaGHm6Z68P6aCq5bv95pyhi9KKhQleQXmlyO8Y,2046
50
+ mpflash/mpboard_id/board_id.py,sha256=xdOna_ZpTHVnsV8XQ5rrTIRCuzU69HD_ZJoY19d7dCE,1894
49
51
  mpflash/mpboard_id/board_info.json,sha256=A3ZIt38KvAy2NMB5srHorSBd3Q3wOZIXufWiIs3XLrs,1019745
50
52
  mpflash/mpboard_id/board_info.zip,sha256=-2bnQGRsIQuJUfz-7_-GQ8pMWJ1evhCez6yfjhXocNw,23213
51
- mpflash/mpboard_id/known.py,sha256=GrNe4FtzVIdi9L9xuJ1gzorzXTvdfrugX1iVc_Nblb8,3325
53
+ mpflash/mpboard_id/known.py,sha256=t-oREfW5P5Zue5zbte7WB9e7-mpZBF-NfHGTEUsOVLM,3521
52
54
  mpflash/mpboard_id/resolve.py,sha256=5KCZ0Tcg3FYZ3HK_zux5EguwoSC2E03kCpW2fh4rN2A,779
53
- mpflash/mpremoteboard/__init__.py,sha256=kZ-MziZPwx6UOs_ybLYEYeUDndC1XyylMcpGTiEHpTk,12043
55
+ mpflash/mpremoteboard/__init__.py,sha256=4OIKAry-GeYUSgnEcs5TRb0xea0bstVQCOb28MjLDyk,14210
54
56
  mpflash/mpremoteboard/mpy_fw_info.py,sha256=ZDEPJN9XJnoG_oeWcLNiLJAD5bkVX2yI_j4K7msUxWM,5196
55
- mpflash/mpremoteboard/runner.py,sha256=auJuK7uBq_qdZOX9DgzRARyAsTyhT8c9ycP02VqhMf4,4943
57
+ mpflash/mpremoteboard/runner.py,sha256=H5f5JBcRnpF06Ui3xDY7IoDdO2Hex9lsI_eGMq5c2A4,4945
56
58
  mpflash/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
59
  mpflash/vendor/board_database.py,sha256=Cb8fEhJaZ2siMkLPW5rPwV9yzBsTtKGOqWUd9TxNgFM,8763
58
60
  mpflash/vendor/click_aliases.py,sha256=adLhqLxNpJEPjSCIRSTkR-QzSgavGFKT0cwRbjxpzRU,5395
@@ -62,8 +64,8 @@ mpflash/vendor/pico-universal-flash-nuke/universal_flash_nuke.uf2,sha256=QuPMppq
62
64
  mpflash/vendor/pydfu.py,sha256=KD1RHHuhvhWi-l1UB6GyggkxouDKtZgkG4ivRbIfwC4,21264
63
65
  mpflash/vendor/readme.md,sha256=BQ7Uxf8joeYMjTUuSLLBG49ob6a9MgFPIEwuc72-Mfw,415
64
66
  mpflash/versions.py,sha256=HuujLNdMKY_mQXyEqwXVHcU8nbuXeBiWP2TMA5JQhr4,4884
65
- mpflash-1.25.0rc4.dist-info/entry_points.txt,sha256=Jk_visOhYOsZIcSP2Ms9hKqfKy1iorR-6dYltSoWCpY,52
66
- mpflash-1.25.0rc4.dist-info/LICENSE,sha256=mWpNhsIxWzetYNnTpr4eb3HtgsxGIC8KcYWxXEcxQvE,1077
67
- mpflash-1.25.0rc4.dist-info/METADATA,sha256=F4Y4RJ0G1QmdX4COxOVvue11y15q12e-8My2QIRdmUA,23938
68
- mpflash-1.25.0rc4.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
69
- mpflash-1.25.0rc4.dist-info/RECORD,,
67
+ mpflash-1.25.2.dist-info/entry_points.txt,sha256=Jk_visOhYOsZIcSP2Ms9hKqfKy1iorR-6dYltSoWCpY,52
68
+ mpflash-1.25.2.dist-info/LICENSE,sha256=mWpNhsIxWzetYNnTpr4eb3HtgsxGIC8KcYWxXEcxQvE,1077
69
+ mpflash-1.25.2.dist-info/METADATA,sha256=FkHpU3o9_3njLQFFOODMRmgFcoejObaRF9w2JoJ3mrM,27149
70
+ mpflash-1.25.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
71
+ mpflash-1.25.2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.1
2
+ Generator: poetry-core 2.1.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any