mpflash 1.26.1__py3-none-any.whl → 1.26.3__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/__init__.py +5 -0
- mpflash/db/core.py +2 -1
- mpflash/flash/uf2/__init__.py +16 -5
- mpflash/logger.py +79 -5
- mpflash/mpremoteboard/runner.py +14 -4
- {mpflash-1.26.1.dist-info → mpflash-1.26.3.dist-info}/METADATA +2 -4
- {mpflash-1.26.1.dist-info → mpflash-1.26.3.dist-info}/RECORD +10 -10
- {mpflash-1.26.1.dist-info → mpflash-1.26.3.dist-info}/WHEEL +0 -0
- {mpflash-1.26.1.dist-info → mpflash-1.26.3.dist-info}/entry_points.txt +0 -0
- {mpflash-1.26.1.dist-info → mpflash-1.26.3.dist-info}/licenses/LICENSE +0 -0
mpflash/__init__.py
CHANGED
mpflash/db/core.py
CHANGED
@@ -14,7 +14,8 @@ from .models import Base
|
|
14
14
|
|
15
15
|
TRACE = False
|
16
16
|
connect_str = f"sqlite:///{config.db_path.as_posix()}"
|
17
|
-
|
17
|
+
if TRACE:
|
18
|
+
log.debug(f"Connecting to database at {connect_str}")
|
18
19
|
engine = create_engine(connect_str, echo=TRACE)
|
19
20
|
Session = sessionmaker(bind=engine)
|
20
21
|
|
mpflash/flash/uf2/__init__.py
CHANGED
@@ -4,18 +4,17 @@ Flash SAMD and RP2 via UF2
|
|
4
4
|
|
5
5
|
import shutil
|
6
6
|
import sys
|
7
|
-
from pathlib import Path
|
8
7
|
import time
|
8
|
+
from pathlib import Path
|
9
9
|
from typing import Optional
|
10
10
|
|
11
11
|
import tenacity
|
12
12
|
from loguru import logger as log
|
13
|
-
|
14
13
|
from tenacity import stop_after_attempt, wait_fixed
|
15
14
|
|
15
|
+
from mpflash.common import PORT_FWTYPES
|
16
16
|
from mpflash.mpremoteboard import MPRemoteBoard
|
17
17
|
|
18
|
-
from mpflash.common import PORT_FWTYPES
|
19
18
|
from .boardid import get_board_id
|
20
19
|
from .linux import dismount_uf2_linux, wait_for_UF2_linux
|
21
20
|
from .macos import wait_for_UF2_macos
|
@@ -38,6 +37,10 @@ def flash_uf2(mcu: MPRemoteBoard, fw_file: Path, erase: bool) -> Optional[MPRemo
|
|
38
37
|
if ".uf2" not in PORT_FWTYPES[mcu.port]:
|
39
38
|
log.error(f"UF2 not supported on {mcu.board} on {mcu.serialport}")
|
40
39
|
return None
|
40
|
+
|
41
|
+
# For non-rp2 ports, remember if we need to erase filesystem after flashing
|
42
|
+
erase_filesystem_after_flash = erase and mcu.port != "rp2"
|
43
|
+
|
41
44
|
if erase:
|
42
45
|
if mcu.port == "rp2":
|
43
46
|
rp2_erase =Path(__file__).parent.joinpath("../../vendor/pico-universal-flash-nuke/universal_flash_nuke.uf2").resolve()
|
@@ -52,8 +55,6 @@ def flash_uf2(mcu: MPRemoteBoard, fw_file: Path, erase: bool) -> Optional[MPRemo
|
|
52
55
|
dismount_uf2_linux()
|
53
56
|
# allow for MCU restart after erase
|
54
57
|
time.sleep(0.5)
|
55
|
-
else:
|
56
|
-
log.warning(f"Erase not (yet) supported on .UF2, for port {mcu.port}, skipping erase.")
|
57
58
|
|
58
59
|
destination = waitfor_uf2(board_id=mcu.port.upper())
|
59
60
|
|
@@ -75,6 +76,16 @@ def flash_uf2(mcu: MPRemoteBoard, fw_file: Path, erase: bool) -> Optional[MPRemo
|
|
75
76
|
dismount_uf2_linux()
|
76
77
|
|
77
78
|
mcu.wait_for_restart()
|
79
|
+
|
80
|
+
# For non-rp2 UF2 ports (like SAMD), erase filesystem after flash and restart
|
81
|
+
if erase_filesystem_after_flash:
|
82
|
+
# allow for MCU restart after erase
|
83
|
+
time.sleep(0.5)
|
84
|
+
log.info(f"Erasing {mcu.port} filesystem using mpremote rm -r :/")
|
85
|
+
try:
|
86
|
+
rc, result = mcu.run_command(["rm", "-r", ":/"], timeout=30, resume=True)
|
87
|
+
except Exception as e:
|
88
|
+
log.warning(f"Failed to erase filesystem on {mcu.port}: {e}")
|
78
89
|
return mcu
|
79
90
|
|
80
91
|
|
mpflash/logger.py
CHANGED
@@ -3,6 +3,14 @@ Logger setup for CLI tools with Unicode-safe output.
|
|
3
3
|
|
4
4
|
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
|
+
Prevents Loguru colorization errors with angle bracket notation.
|
7
|
+
|
8
|
+
Usage for external packages:
|
9
|
+
from mpflash.logger import setup_external_logger_safety
|
10
|
+
setup_external_logger_safety()
|
11
|
+
|
12
|
+
This is particularly important when using packages like micropython-stubber
|
13
|
+
that may log messages containing angle bracket notation like <board_default>.
|
6
14
|
"""
|
7
15
|
|
8
16
|
import functools
|
@@ -28,12 +36,23 @@ def _is_utf8_encoding() -> bool:
|
|
28
36
|
return False
|
29
37
|
|
30
38
|
|
31
|
-
def
|
39
|
+
def _sanitize_message(message: str) -> str:
|
40
|
+
"""
|
41
|
+
Sanitize log messages to prevent Loguru colorization issues.
|
42
|
+
|
43
|
+
Escapes angle brackets that could be interpreted as color tags.
|
44
|
+
This prevents errors when logging documentation with placeholders like <board_default>.
|
45
|
+
"""
|
46
|
+
# Escape angle brackets to prevent them from being interpreted as color tags
|
47
|
+
return message.replace("<", "\\<").replace(">", "\\>")
|
48
|
+
|
49
|
+
|
50
|
+
def _log_formatter(record) -> str:
|
32
51
|
"""
|
33
52
|
Log message formatter for loguru and rich.
|
34
53
|
|
35
54
|
Removes Unicode icons if console encoding is not UTF-8.
|
36
|
-
Handles messages containing curly braces safely.
|
55
|
+
Handles messages containing curly braces and angle brackets safely.
|
37
56
|
"""
|
38
57
|
color_map = {
|
39
58
|
"TRACE": "cyan",
|
@@ -50,8 +69,12 @@ def _log_formatter(record: dict) -> str:
|
|
50
69
|
icon = record["level"].icon
|
51
70
|
else:
|
52
71
|
icon = record["level"].name # fallback to text
|
53
|
-
|
54
|
-
|
72
|
+
|
73
|
+
# Sanitize the message to prevent format conflicts and colorization errors
|
74
|
+
safe_message = _sanitize_message(record["message"])
|
75
|
+
# Escape curly braces to prevent format conflicts
|
76
|
+
safe_message = safe_message.replace("{", "{{").replace("}", "}}")
|
77
|
+
|
55
78
|
# Use string concatenation to avoid f-string format conflicts
|
56
79
|
time_part = "[not bold green]{time:HH:mm:ss}[/not bold green]"
|
57
80
|
message_part = f"[{lvl_color}]{safe_message}[/{lvl_color}]"
|
@@ -63,6 +86,7 @@ def set_loglevel(loglevel: str) -> None:
|
|
63
86
|
Set the log level for the logger.
|
64
87
|
|
65
88
|
Ensures Unicode safety for log output and handles format errors.
|
89
|
+
Disables colorization to prevent angle bracket interpretation issues.
|
66
90
|
"""
|
67
91
|
try:
|
68
92
|
log.remove()
|
@@ -77,7 +101,57 @@ def set_loglevel(loglevel: str) -> None:
|
|
77
101
|
# Fallback to simple text output if formatting fails
|
78
102
|
console.print(f"[LOG FORMAT ERROR] {message} (Error: {e})")
|
79
103
|
|
80
|
-
|
104
|
+
# Disable colorization completely to prevent angle bracket interpretation as color tags
|
105
|
+
log.add(
|
106
|
+
safe_format_wrapper,
|
107
|
+
level=loglevel.upper(),
|
108
|
+
colorize=False, # This prevents Loguru from parsing angle brackets as color tags
|
109
|
+
format=_log_formatter,
|
110
|
+
) # type: ignore
|
111
|
+
|
112
|
+
|
113
|
+
def configure_safe_logging() -> None:
|
114
|
+
"""
|
115
|
+
Configure logging to be safe from colorization errors.
|
116
|
+
|
117
|
+
This function helps prevent issues when external packages
|
118
|
+
(like micropython-stubber) log messages with angle brackets
|
119
|
+
that could be misinterpreted as color tags.
|
120
|
+
"""
|
121
|
+
# Remove all existing handlers to start fresh
|
122
|
+
try:
|
123
|
+
log.remove()
|
124
|
+
except ValueError:
|
125
|
+
pass
|
126
|
+
|
127
|
+
# Add a completely safe handler with no colorization
|
128
|
+
log.add(
|
129
|
+
sys.stderr,
|
130
|
+
level="TRACE",
|
131
|
+
colorize=False, # Completely disable colorization
|
132
|
+
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {name}:{function}:{line} - {message}",
|
133
|
+
)
|
134
|
+
|
135
|
+
|
136
|
+
def setup_external_logger_safety() -> None:
|
137
|
+
"""
|
138
|
+
Setup safe logging configuration for external packages.
|
139
|
+
|
140
|
+
Call this function before running tools that might log messages
|
141
|
+
with angle bracket notation (like micropython-stubber) to prevent
|
142
|
+
Loguru colorization errors.
|
143
|
+
"""
|
144
|
+
import logging
|
145
|
+
|
146
|
+
# Configure the root logger to be safe
|
147
|
+
logging.basicConfig(
|
148
|
+
level=logging.DEBUG,
|
149
|
+
format="%(asctime)s | %(levelname)s | %(name)s:%(funcName)s:%(lineno)d - %(message)s",
|
150
|
+
handlers=[logging.StreamHandler(sys.stderr)],
|
151
|
+
)
|
152
|
+
|
153
|
+
# Also configure loguru for safety
|
154
|
+
configure_safe_logging()
|
81
155
|
|
82
156
|
|
83
157
|
def make_quiet() -> None:
|
mpflash/mpremoteboard/runner.py
CHANGED
@@ -6,6 +6,7 @@ import subprocess
|
|
6
6
|
from dataclasses import dataclass
|
7
7
|
from threading import Timer
|
8
8
|
from typing import List, Optional, Tuple
|
9
|
+
from unittest.mock import DEFAULT
|
9
10
|
|
10
11
|
from loguru import logger as log
|
11
12
|
|
@@ -31,6 +32,13 @@ DEFAULT_RESET_TAGS = [
|
|
31
32
|
"rst:0x10 (RTCWDT_RTC_RESET)",
|
32
33
|
]
|
33
34
|
|
35
|
+
DEFAULT_ERROR_TAGS = ["Traceback ", "Error: ", "Exception: ", "ERROR :", "CRIT :"]
|
36
|
+
DEFAULT_WARNING_TAGS = ["WARN :", "TRACE :"]
|
37
|
+
DEFAULT_SUCCESS_TAGS = ["Done", "File saved", "File removed", "File renamed"]
|
38
|
+
DEFAULT_IGNORE_TAGS = [
|
39
|
+
' File "<stdin>",',
|
40
|
+
"mpremote: rm -r: cannot remove :/ Operation not permitted",
|
41
|
+
]
|
34
42
|
|
35
43
|
def run(
|
36
44
|
cmd: List[str],
|
@@ -70,13 +78,13 @@ def run(
|
|
70
78
|
if not reset_tags:
|
71
79
|
reset_tags = DEFAULT_RESET_TAGS
|
72
80
|
if not error_tags:
|
73
|
-
error_tags =
|
81
|
+
error_tags = DEFAULT_ERROR_TAGS
|
74
82
|
if not warning_tags:
|
75
|
-
warning_tags =
|
83
|
+
warning_tags = DEFAULT_WARNING_TAGS
|
76
84
|
if not success_tags:
|
77
|
-
success_tags =
|
85
|
+
success_tags = DEFAULT_SUCCESS_TAGS
|
78
86
|
if not ignore_tags:
|
79
|
-
ignore_tags =
|
87
|
+
ignore_tags = DEFAULT_IGNORE_TAGS
|
80
88
|
|
81
89
|
replace_tags = ["\x1b[1A"]
|
82
90
|
|
@@ -132,6 +140,8 @@ def run(
|
|
132
140
|
log.info(line)
|
133
141
|
if proc.stderr and log_errors:
|
134
142
|
for line in proc.stderr:
|
143
|
+
if any(tag in line for tag in ignore_tags):
|
144
|
+
continue
|
135
145
|
log.warning(line)
|
136
146
|
except UnicodeDecodeError as e:
|
137
147
|
log.error(f"Failed to decode output: {e}")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: mpflash
|
3
|
-
Version: 1.26.
|
3
|
+
Version: 1.26.3
|
4
4
|
Summary: Flash and download tool for MicroPython firmwares
|
5
5
|
Project-URL: Homepage, https://github.com/Josverl/mpflash
|
6
6
|
Project-URL: Documentation, https://github.com/Josverl/mpflash/blob/main/README.md
|
@@ -29,7 +29,7 @@ Requires-Dist: bincopy>=20.0.0
|
|
29
29
|
Requires-Dist: blkinfo>=0.2.0
|
30
30
|
Requires-Dist: cache-to-disk>=2.0.0
|
31
31
|
Requires-Dist: cachetools>=5.3.0
|
32
|
-
Requires-Dist: esptool
|
32
|
+
Requires-Dist: esptool<5.0.0,>=4.7.0
|
33
33
|
Requires-Dist: inquirer>=3.2.4
|
34
34
|
Requires-Dist: jsonlines>=4.0.0
|
35
35
|
Requires-Dist: jsons>=1.6.3
|
@@ -52,8 +52,6 @@ Provides-Extra: dev
|
|
52
52
|
Requires-Dist: ipykernel>=6.29.5; extra == 'dev'
|
53
53
|
Requires-Dist: pandas>=2.2.3; extra == 'dev'
|
54
54
|
Requires-Dist: tornado>=6.5; extra == 'dev'
|
55
|
-
Provides-Extra: perf
|
56
|
-
Requires-Dist: scalene>=1.5.51; extra == 'perf'
|
57
55
|
Provides-Extra: test
|
58
56
|
Requires-Dist: coverage<8.0.0,>=6.4.3; extra == 'test'
|
59
57
|
Requires-Dist: distro>=1.8.0; extra == 'test'
|
@@ -1,4 +1,4 @@
|
|
1
|
-
mpflash/__init__.py,sha256=
|
1
|
+
mpflash/__init__.py,sha256=1CcA1kUb3uUfa9N5O4T4ZQh-Ph0JMFAtBG5IiDIaNVg,201
|
2
2
|
mpflash/ask_input.py,sha256=YUx65Xwj6dNPwWcbQiWG7U4wDW69zEdno2HcT1KwPBg,8886
|
3
3
|
mpflash/basicgit.py,sha256=lpGQxL10Mq8D8S56h87aMrBH0vo18ji_hE9v0KJ9P-o,10245
|
4
4
|
mpflash/cli_add.py,sha256=hI-o-9hAGD3U8cbpXvy9Nuv1KHNTZ6mS57LC4BTBtj8,3495
|
@@ -13,7 +13,7 @@ mpflash/connected.py,sha256=SZvqbnLztJH-DBByjGrWT24S5DGTSevWSwYncH6dFqk,3707
|
|
13
13
|
mpflash/downloaded.py,sha256=xaeMYrTIGj_v4scUBojeJPL-U1kWJG-bdvkvJMbPh4Q,4218
|
14
14
|
mpflash/errors.py,sha256=IAidY3qkZsXy6Pm1rdmVFmGyg81ywHhse3itaPctA2w,247
|
15
15
|
mpflash/list.py,sha256=IrJa3UBjhHHfStbb9fPVYA8JJzoFTyXtbcKGNRSH8sE,4132
|
16
|
-
mpflash/logger.py,sha256=
|
16
|
+
mpflash/logger.py,sha256=h1Ra-uYCVqC2evuDoIoD7GGhTHK-ymkAuqNUsPdZHcI,5212
|
17
17
|
mpflash/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
18
|
mpflash/versions.py,sha256=HuujLNdMKY_mQXyEqwXVHcU8nbuXeBiWP2TMA5JQhr4,4884
|
19
19
|
mpflash/bootloader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -25,7 +25,7 @@ mpflash/bootloader/touch1200.py,sha256=VND7_YniS9Vx6WEaAxjI72RZZ6WBOwmBTsKJkbuaA
|
|
25
25
|
mpflash/custom/__init__.py,sha256=l9RU9hRm9j7IuRgacw-gHYjA2Op-5prvRO5yyODhFMQ,5269
|
26
26
|
mpflash/custom/naming.py,sha256=uHQzFIDzuWQUNajeGSUcf_A-o7cxX37kfgXhzpFHNtk,3304
|
27
27
|
mpflash/db/__init__.py,sha256=wnIlO4nOXsPGXMbn2OCqHRsR-hUmtJsko8VdqjH3ZUE,45
|
28
|
-
mpflash/db/core.py,sha256=
|
28
|
+
mpflash/db/core.py,sha256=PiHpk64pBP-myfacxfVgHo4BvSSvFrtx6LrLgIPMyYY,5286
|
29
29
|
mpflash/db/gather_boards.py,sha256=fzCT1IGZ53FwkFrTY72ZeXH5klSlm5JFETsDU7lGYf4,4134
|
30
30
|
mpflash/db/loader.py,sha256=CDlTj2T6w9Ch9s3RHi00E1TbUhjFsgXAsYSQr5kliB0,4889
|
31
31
|
mpflash/db/meta.py,sha256=2pFTpFH-1zejGIDp2vs0hbX5rqUONt7B1WIvf8qBx5s,2248
|
@@ -41,7 +41,7 @@ mpflash/flash/esp.py,sha256=4977E1hDqJ4-EIkLzwrUtgZuc0ZTD7NvP1PQZgZ2DoU,3227
|
|
41
41
|
mpflash/flash/stm32.py,sha256=jNgMpJaxUwtJ-v6VU1luD1t41AQprCUeNVCVEovxQe0,595
|
42
42
|
mpflash/flash/stm32_dfu.py,sha256=W-3JsRQyf3DduoIRXDmGZ35RogqtjQgcJnk-GOtQoLE,3090
|
43
43
|
mpflash/flash/worklist.py,sha256=wf-R9yPsmcE54dnoPA29pEEzNPZI3JwY85V_DB0hXNI,6584
|
44
|
-
mpflash/flash/uf2/__init__.py,sha256=
|
44
|
+
mpflash/flash/uf2/__init__.py,sha256=fCTQLwI8jigzGY0zVWB1XmqyieNFDRHOWky2slZjZEM,4145
|
45
45
|
mpflash/flash/uf2/boardid.py,sha256=U5wGM8VA3wEpUxQCMtuXpMZZomdVH8J_Zd5_GekUMuU,423
|
46
46
|
mpflash/flash/uf2/linux.py,sha256=uTgqyS7C7xfQ25RrTcSUkt-m2u2Ks_o7bPLzIecPoC8,4355
|
47
47
|
mpflash/flash/uf2/macos.py,sha256=JTaIpqnR_0k4oSEvzs9amhmK-PMxUJyZLnZ_wZwxa-0,1228
|
@@ -56,7 +56,7 @@ mpflash/mpboard_id/known.py,sha256=t-oREfW5P5Zue5zbte7WB9e7-mpZBF-NfHGTEUsOVLM,3
|
|
56
56
|
mpflash/mpboard_id/resolve.py,sha256=5KCZ0Tcg3FYZ3HK_zux5EguwoSC2E03kCpW2fh4rN2A,779
|
57
57
|
mpflash/mpremoteboard/__init__.py,sha256=4OIKAry-GeYUSgnEcs5TRb0xea0bstVQCOb28MjLDyk,14210
|
58
58
|
mpflash/mpremoteboard/mpy_fw_info.py,sha256=ZDEPJN9XJnoG_oeWcLNiLJAD5bkVX2yI_j4K7msUxWM,5196
|
59
|
-
mpflash/mpremoteboard/runner.py,sha256=
|
59
|
+
mpflash/mpremoteboard/runner.py,sha256=4YpL0OA3GRcCvXI47wrj6hJKJZ9uunkdDKDFic2ZM-8,5372
|
60
60
|
mpflash/vendor/board_database.py,sha256=Cb8fEhJaZ2siMkLPW5rPwV9yzBsTtKGOqWUd9TxNgFM,8763
|
61
61
|
mpflash/vendor/click_aliases.py,sha256=adLhqLxNpJEPjSCIRSTkR-QzSgavGFKT0cwRbjxpzRU,5395
|
62
62
|
mpflash/vendor/dfu.py,sha256=6rqGCBS8mTxxaLtkdzJ8O6nc74kFk8jrkmKvxw-x-u8,5693
|
@@ -64,8 +64,8 @@ mpflash/vendor/pydfu.py,sha256=KD1RHHuhvhWi-l1UB6GyggkxouDKtZgkG4ivRbIfwC4,21264
|
|
64
64
|
mpflash/vendor/readme.md,sha256=BQ7Uxf8joeYMjTUuSLLBG49ob6a9MgFPIEwuc72-Mfw,415
|
65
65
|
mpflash/vendor/pico-universal-flash-nuke/LICENSE.txt,sha256=Zkc2iTNbib2NCMwtLjMEz0vFCPglgvaw6Mj7QiWldpQ,1484
|
66
66
|
mpflash/vendor/pico-universal-flash-nuke/universal_flash_nuke.uf2,sha256=QuPMppqHMVOt3vDVU0bikHRLsTiDRQYNUcGQ_OLRFGI,28160
|
67
|
-
mpflash-1.26.
|
68
|
-
mpflash-1.26.
|
69
|
-
mpflash-1.26.
|
70
|
-
mpflash-1.26.
|
71
|
-
mpflash-1.26.
|
67
|
+
mpflash-1.26.3.dist-info/METADATA,sha256=T_PJNISbbh6QLopvV6CosjyXnO94zDJqjibo46havDM,28033
|
68
|
+
mpflash-1.26.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
69
|
+
mpflash-1.26.3.dist-info/entry_points.txt,sha256=DZ24tsMKlCyTkjWet9vCoq5dcFeY43RKtTsLreQI_R8,53
|
70
|
+
mpflash-1.26.3.dist-info/licenses/LICENSE,sha256=mWpNhsIxWzetYNnTpr4eb3HtgsxGIC8KcYWxXEcxQvE,1077
|
71
|
+
mpflash-1.26.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|