mpflash 1.0.0__py3-none-any.whl → 1.0.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.
Files changed (52) hide show
  1. mpflash/add_firmware.py +98 -98
  2. mpflash/ask_input.py +236 -236
  3. mpflash/basicgit.py +284 -284
  4. mpflash/bootloader/__init__.py +2 -2
  5. mpflash/bootloader/activate.py +60 -60
  6. mpflash/bootloader/detect.py +82 -82
  7. mpflash/bootloader/manual.py +101 -101
  8. mpflash/bootloader/micropython.py +12 -12
  9. mpflash/bootloader/touch1200.py +36 -36
  10. mpflash/cli_download.py +129 -129
  11. mpflash/cli_flash.py +224 -216
  12. mpflash/cli_group.py +111 -111
  13. mpflash/cli_list.py +87 -87
  14. mpflash/cli_main.py +39 -39
  15. mpflash/common.py +210 -166
  16. mpflash/config.py +44 -44
  17. mpflash/connected.py +104 -77
  18. mpflash/download.py +364 -364
  19. mpflash/downloaded.py +130 -130
  20. mpflash/errors.py +9 -9
  21. mpflash/flash/__init__.py +55 -55
  22. mpflash/flash/esp.py +59 -59
  23. mpflash/flash/stm32.py +19 -19
  24. mpflash/flash/stm32_dfu.py +104 -104
  25. mpflash/flash/uf2/__init__.py +88 -88
  26. mpflash/flash/uf2/boardid.py +15 -15
  27. mpflash/flash/uf2/linux.py +136 -130
  28. mpflash/flash/uf2/macos.py +42 -42
  29. mpflash/flash/uf2/uf2disk.py +12 -12
  30. mpflash/flash/uf2/windows.py +43 -43
  31. mpflash/flash/worklist.py +170 -170
  32. mpflash/list.py +106 -106
  33. mpflash/logger.py +41 -41
  34. mpflash/mpboard_id/__init__.py +93 -93
  35. mpflash/mpboard_id/add_boards.py +251 -251
  36. mpflash/mpboard_id/board.py +37 -37
  37. mpflash/mpboard_id/board_id.py +86 -86
  38. mpflash/mpboard_id/store.py +43 -43
  39. mpflash/mpremoteboard/__init__.py +266 -266
  40. mpflash/mpremoteboard/mpy_fw_info.py +141 -141
  41. mpflash/mpremoteboard/runner.py +140 -140
  42. mpflash/vendor/click_aliases.py +91 -91
  43. mpflash/vendor/dfu.py +165 -165
  44. mpflash/vendor/pydfu.py +605 -605
  45. mpflash/vendor/readme.md +2 -2
  46. mpflash/versions.py +135 -135
  47. {mpflash-1.0.0.dist-info → mpflash-1.0.2.dist-info}/LICENSE +20 -20
  48. {mpflash-1.0.0.dist-info → mpflash-1.0.2.dist-info}/METADATA +1 -1
  49. mpflash-1.0.2.dist-info/RECORD +53 -0
  50. mpflash-1.0.0.dist-info/RECORD +0 -53
  51. {mpflash-1.0.0.dist-info → mpflash-1.0.2.dist-info}/WHEEL +0 -0
  52. {mpflash-1.0.0.dist-info → mpflash-1.0.2.dist-info}/entry_points.txt +0 -0
mpflash/flash/worklist.py CHANGED
@@ -1,170 +1,170 @@
1
- """Worklist for updating boards"""
2
-
3
- from pathlib import Path
4
- from typing import Dict, List, Optional, Tuple
5
-
6
- from loguru import logger as log
7
-
8
- from mpflash.common import FWInfo, filtered_comports
9
- from mpflash.downloaded import find_downloaded_firmware
10
- from mpflash.errors import MPFlashError
11
- from mpflash.list import show_mcus
12
- from mpflash.mpboard_id import find_known_board
13
- from mpflash.mpremoteboard import MPRemoteBoard
14
-
15
- # #########################################################################################################
16
- WorkList = List[Tuple[MPRemoteBoard, FWInfo]]
17
- # #########################################################################################################
18
-
19
-
20
- def auto_update(
21
- conn_boards: List[MPRemoteBoard],
22
- target_version: str,
23
- fw_folder: Path,
24
- *,
25
- selector: Optional[Dict[str, str]] = None,
26
- ) -> WorkList:
27
- """Builds a list of boards to update based on the connected boards and the firmwares available locally in the firmware folder.
28
-
29
- Args:
30
- conn_boards (List[MPRemoteBoard]): List of connected boards
31
- target_version (str): Target firmware version
32
- fw_folder (Path): Path to the firmware folder
33
- selector (Optional[Dict[str, str]], optional): Selector for filtering firmware. Defaults to None.
34
-
35
- Returns:
36
- WorkList: List of boards and firmware information to update
37
- """
38
- if selector is None:
39
- selector = {}
40
- wl: WorkList = []
41
- for mcu in conn_boards:
42
- if mcu.family not in ("micropython", "unknown"):
43
- log.warning(f"Skipping flashing {mcu.family} {mcu.port} {mcu.board} on {mcu.serialport} as it is not a MicroPython firmware")
44
- continue
45
- board_firmwares = find_downloaded_firmware(
46
- fw_folder=fw_folder,
47
- board_id=mcu.board,
48
- version=target_version,
49
- port=mcu.port,
50
- selector=selector,
51
- )
52
-
53
- if not board_firmwares:
54
- log.error(f"No {target_version} firmware found for {mcu.board} on {mcu.serialport}.")
55
- continue
56
-
57
- if len(board_firmwares) > 1:
58
- log.warning(f"Multiple {target_version} firmwares found for {mcu.board} on {mcu.serialport}.")
59
-
60
- # just use the last firmware
61
- fw_info = board_firmwares[-1]
62
- log.info(f"Found {target_version} firmware {fw_info.filename} for {mcu.board} on {mcu.serialport}.")
63
- wl.append((mcu, fw_info))
64
- return wl
65
-
66
-
67
- def manual_worklist(
68
- serial: str,
69
- *,
70
- board_id: str,
71
- version: str,
72
- fw_folder: Path,
73
- ) -> WorkList:
74
- """Create a worklist for a single board specified manually.
75
-
76
- Args:
77
- serial (str): Serial port of the board
78
- board (str): Board_ID
79
- version (str): Firmware version
80
- fw_folder (Path): Path to the firmware folder
81
-
82
- Returns:
83
- WorkList: List of boards and firmware information to update
84
- """
85
- log.trace(f"Manual updating {serial} to {board_id} {version}")
86
- mcu = MPRemoteBoard(serial)
87
- # Lookup the matching port and cpu in board_info based in the board name
88
- try:
89
- info = find_known_board(board_id)
90
- mcu.port = info.port
91
- # need the CPU type for the esptool
92
- mcu.cpu = info.cpu
93
- except (LookupError, MPFlashError) as e:
94
- log.error(f"Board {board_id} not found in board_info.zip")
95
- log.exception(e)
96
- return []
97
- mcu.board = board_id
98
- firmwares = find_downloaded_firmware(fw_folder=fw_folder, board_id=board_id, version=version, port=mcu.port)
99
- if not firmwares:
100
- log.error(f"No firmware found for {mcu.port} {board_id} version {version}")
101
- return []
102
- # use the most recent matching firmware
103
- return [(mcu, firmwares[-1])] # type: ignore
104
-
105
-
106
- def single_auto_worklist(
107
- serial: str,
108
- *,
109
- version: str,
110
- fw_folder: Path,
111
- ) -> WorkList:
112
- """Create a worklist for a single serial-port.
113
-
114
- Args:
115
- serial_port (str): Serial port of the board
116
- version (str): Firmware version
117
- fw_folder (Path): Path to the firmware folder
118
-
119
- Returns:
120
- WorkList: List of boards and firmware information to update
121
- """
122
- log.trace(f"Auto updating {serial} to {version}")
123
- conn_boards = [MPRemoteBoard(serial)]
124
- todo = auto_update(conn_boards, version, fw_folder) # type: ignore # List / list
125
- show_mcus(conn_boards) # type: ignore
126
- return todo
127
-
128
-
129
- def full_auto_worklist(
130
- all_boards: List[MPRemoteBoard], *, include: List[str], ignore: List[str], version: str, fw_folder: Path
131
- ) -> WorkList:
132
- """
133
- Create a worklist for all connected micropython boards based on the information retrieved from the board.
134
- This allows the firmware version of one or moae boards to be changed without needing to specify the port or board_id manually.
135
-
136
- Args:
137
- version (str): Firmware version
138
- fw_folder (Path): Path to the firmware folder
139
-
140
- Returns:
141
- WorkList: List of boards and firmware information to update
142
- """
143
- log.trace(f"Auto updating all boards to {version}")
144
- if selected_boards := filter_boards(all_boards, include=include, ignore=ignore):
145
- return auto_update(selected_boards, version, fw_folder)
146
- else:
147
- return []
148
-
149
-
150
- def filter_boards(
151
- all_boards: List[MPRemoteBoard],
152
- *,
153
- include: List[str],
154
- ignore: List[str],
155
- ):
156
- try:
157
- comports = [
158
- p.device
159
- for p in filtered_comports(
160
- ignore=ignore,
161
- include=include,
162
- bluetooth=False,
163
- )
164
- ]
165
- selected_boards = [b for b in all_boards if b.serialport in comports]
166
- # [MPRemoteBoard(port.device, update=True) for port in comports]
167
- except ConnectionError as e:
168
- log.error(f"Error connecting to boards: {e}")
169
- return []
170
- return selected_boards # type: ignore
1
+ """Worklist for updating boards"""
2
+
3
+ from pathlib import Path
4
+ from typing import Dict, List, Optional, Tuple
5
+
6
+ from loguru import logger as log
7
+
8
+ from mpflash.common import FWInfo, filtered_comports
9
+ from mpflash.downloaded import find_downloaded_firmware
10
+ from mpflash.errors import MPFlashError
11
+ from mpflash.list import show_mcus
12
+ from mpflash.mpboard_id import find_known_board
13
+ from mpflash.mpremoteboard import MPRemoteBoard
14
+
15
+ # #########################################################################################################
16
+ WorkList = List[Tuple[MPRemoteBoard, FWInfo]]
17
+ # #########################################################################################################
18
+
19
+
20
+ def auto_update(
21
+ conn_boards: List[MPRemoteBoard],
22
+ target_version: str,
23
+ fw_folder: Path,
24
+ *,
25
+ selector: Optional[Dict[str, str]] = None,
26
+ ) -> WorkList:
27
+ """Builds a list of boards to update based on the connected boards and the firmwares available locally in the firmware folder.
28
+
29
+ Args:
30
+ conn_boards (List[MPRemoteBoard]): List of connected boards
31
+ target_version (str): Target firmware version
32
+ fw_folder (Path): Path to the firmware folder
33
+ selector (Optional[Dict[str, str]], optional): Selector for filtering firmware. Defaults to None.
34
+
35
+ Returns:
36
+ WorkList: List of boards and firmware information to update
37
+ """
38
+ if selector is None:
39
+ selector = {}
40
+ wl: WorkList = []
41
+ for mcu in conn_boards:
42
+ if mcu.family not in ("micropython", "unknown"):
43
+ log.warning(f"Skipping flashing {mcu.family} {mcu.port} {mcu.board} on {mcu.serialport} as it is not a MicroPython firmware")
44
+ continue
45
+ board_firmwares = find_downloaded_firmware(
46
+ fw_folder=fw_folder,
47
+ board_id=mcu.board,
48
+ version=target_version,
49
+ port=mcu.port,
50
+ selector=selector,
51
+ )
52
+
53
+ if not board_firmwares:
54
+ log.error(f"No {target_version} firmware found for {mcu.board} on {mcu.serialport}.")
55
+ continue
56
+
57
+ if len(board_firmwares) > 1:
58
+ log.warning(f"Multiple {target_version} firmwares found for {mcu.board} on {mcu.serialport}.")
59
+
60
+ # just use the last firmware
61
+ fw_info = board_firmwares[-1]
62
+ log.info(f"Found {target_version} firmware {fw_info.filename} for {mcu.board} on {mcu.serialport}.")
63
+ wl.append((mcu, fw_info))
64
+ return wl
65
+
66
+
67
+ def manual_worklist(
68
+ serial: str,
69
+ *,
70
+ board_id: str,
71
+ version: str,
72
+ fw_folder: Path,
73
+ ) -> WorkList:
74
+ """Create a worklist for a single board specified manually.
75
+
76
+ Args:
77
+ serial (str): Serial port of the board
78
+ board (str): Board_ID
79
+ version (str): Firmware version
80
+ fw_folder (Path): Path to the firmware folder
81
+
82
+ Returns:
83
+ WorkList: List of boards and firmware information to update
84
+ """
85
+ log.trace(f"Manual updating {serial} to {board_id} {version}")
86
+ mcu = MPRemoteBoard(serial)
87
+ # Lookup the matching port and cpu in board_info based in the board name
88
+ try:
89
+ info = find_known_board(board_id)
90
+ mcu.port = info.port
91
+ # need the CPU type for the esptool
92
+ mcu.cpu = info.cpu
93
+ except (LookupError, MPFlashError) as e:
94
+ log.error(f"Board {board_id} not found in board_info.zip")
95
+ log.exception(e)
96
+ return []
97
+ mcu.board = board_id
98
+ firmwares = find_downloaded_firmware(fw_folder=fw_folder, board_id=board_id, version=version, port=mcu.port)
99
+ if not firmwares:
100
+ log.error(f"No firmware found for {mcu.port} {board_id} version {version}")
101
+ return []
102
+ # use the most recent matching firmware
103
+ return [(mcu, firmwares[-1])] # type: ignore
104
+
105
+
106
+ def single_auto_worklist(
107
+ serial: str,
108
+ *,
109
+ version: str,
110
+ fw_folder: Path,
111
+ ) -> WorkList:
112
+ """Create a worklist for a single serial-port.
113
+
114
+ Args:
115
+ serial_port (str): Serial port of the board
116
+ version (str): Firmware version
117
+ fw_folder (Path): Path to the firmware folder
118
+
119
+ Returns:
120
+ WorkList: List of boards and firmware information to update
121
+ """
122
+ log.trace(f"Auto updating {serial} to {version}")
123
+ conn_boards = [MPRemoteBoard(serial)]
124
+ todo = auto_update(conn_boards, version, fw_folder) # type: ignore # List / list
125
+ show_mcus(conn_boards) # type: ignore
126
+ return todo
127
+
128
+
129
+ def full_auto_worklist(
130
+ all_boards: List[MPRemoteBoard], *, include: List[str], ignore: List[str], version: str, fw_folder: Path
131
+ ) -> WorkList:
132
+ """
133
+ Create a worklist for all connected micropython boards based on the information retrieved from the board.
134
+ This allows the firmware version of one or moae boards to be changed without needing to specify the port or board_id manually.
135
+
136
+ Args:
137
+ version (str): Firmware version
138
+ fw_folder (Path): Path to the firmware folder
139
+
140
+ Returns:
141
+ WorkList: List of boards and firmware information to update
142
+ """
143
+ log.trace(f"Auto updating all boards to {version}")
144
+ if selected_boards := filter_boards(all_boards, include=include, ignore=ignore):
145
+ return auto_update(selected_boards, version, fw_folder)
146
+ else:
147
+ return []
148
+
149
+
150
+ def filter_boards(
151
+ all_boards: List[MPRemoteBoard],
152
+ *,
153
+ include: List[str],
154
+ ignore: List[str],
155
+ ):
156
+ try:
157
+ comports = [
158
+ p.device
159
+ for p in filtered_comports(
160
+ ignore=ignore,
161
+ include=include,
162
+ bluetooth=False,
163
+ )
164
+ ]
165
+ selected_boards = [b for b in all_boards if b.serialport in comports]
166
+ # [MPRemoteBoard(port.device, update=True) for port in comports]
167
+ except ConnectionError as e:
168
+ log.error(f"Error connecting to boards: {e}")
169
+ return []
170
+ return selected_boards # type: ignore
mpflash/list.py CHANGED
@@ -1,106 +1,106 @@
1
- from typing import List
2
-
3
- from rich.progress import track
4
- from rich.table import Table
5
-
6
- from mpflash.config import config
7
- from mpflash.mpremoteboard import MPRemoteBoard
8
- from mpflash.versions import clean_version
9
-
10
- from .logger import console
11
-
12
-
13
- def show_mcus(
14
- conn_mcus: List[MPRemoteBoard],
15
- title: str = "Connected boards",
16
- refresh: bool = True,
17
- ):
18
- console.print(mcu_table(conn_mcus, title, refresh))
19
-
20
-
21
- def abbrv_family(family: str, is_wide: bool) -> str:
22
- if not is_wide:
23
- ABRV = {"micropython": "upy", "circuitpython": "cpy", "unknown": "?"}
24
- return ABRV.get(family, family[:4])
25
- return family
26
-
27
-
28
- def mcu_table(
29
- conn_mcus: List[MPRemoteBoard],
30
- title: str = "Connected boards",
31
- refresh: bool = True,
32
- ):
33
- """
34
- builds a rich table with the connected boards information
35
- The columns of the table are adjusted to the terminal width
36
- the columns are :
37
- Narrow Wide
38
- - Serial Yes Yes
39
- - Family abbrv. Yes
40
- - Port - yes
41
- - Board Yes Yes BOARD_ID and Description, and the description from board_info.toml
42
- - CPU - Yes
43
- - Version Yes Yes
44
- - Build * * only if any of the mcus have a build
45
- - Location - - only if --usb is given
46
- """
47
- # refresh if requested
48
- if refresh:
49
- for mcu in track(
50
- conn_mcus,
51
- description="Updating board info",
52
- transient=True,
53
- show_speed=False,
54
- refresh_per_second=1,
55
- ):
56
- try:
57
- mcu.get_mcu_info()
58
- except ConnectionError:
59
- continue
60
- table = Table(
61
- title=title,
62
- title_style="magenta",
63
- header_style="bold magenta",
64
- collapse_padding=True,
65
- padding=(0, 0),
66
- )
67
- # Build the table
68
- # check if the terminal is wide enough to show all columns or if we need to collapse some
69
- is_wide = console.width > 99
70
- needs_build = any(mcu.build for mcu in conn_mcus)
71
-
72
- table.add_column("Serial" if is_wide else "Ser.", overflow="fold")
73
- table.add_column("Family" if is_wide else "Fam.", overflow="crop", max_width=None if is_wide else 4)
74
- if is_wide:
75
- table.add_column("Port")
76
- table.add_column("Board", overflow="fold")
77
- # table.add_column("Variant") # TODO: add variant
78
- if is_wide:
79
- table.add_column("CPU")
80
- table.add_column("Version", overflow="fold", min_width=5, max_width=16)
81
- if needs_build:
82
- table.add_column("Build" if is_wide else "Bld", justify="right")
83
- if config.usb:
84
- table.add_column("Location", overflow="fold", max_width=40)
85
- # fill the table with the data
86
- for mcu in conn_mcus:
87
- description = f"[italic bright_cyan]{mcu.description}" if mcu.description else ""
88
- if "description" in mcu.toml:
89
- description += f"\n[italic bright_green]{mcu.toml['description']}"
90
- row = [
91
- mcu.serialport.replace("/dev/", ""),
92
- abbrv_family(mcu.family, is_wide),
93
- ]
94
- if is_wide:
95
- row.append(mcu.port)
96
- row.append(f"{mcu.board}\n{description}".strip())
97
- if is_wide:
98
- row.append(mcu.cpu)
99
- row.append(clean_version(mcu.version))
100
- if needs_build:
101
- row.append(mcu.build)
102
- if config.usb:
103
- row.append(mcu.location)
104
-
105
- table.add_row(*row)
106
- return table
1
+ from typing import List
2
+
3
+ from rich.progress import track
4
+ from rich.table import Table
5
+
6
+ from mpflash.config import config
7
+ from mpflash.mpremoteboard import MPRemoteBoard
8
+ from mpflash.versions import clean_version
9
+
10
+ from .logger import console
11
+
12
+
13
+ def show_mcus(
14
+ conn_mcus: List[MPRemoteBoard],
15
+ title: str = "Connected boards",
16
+ refresh: bool = True,
17
+ ):
18
+ console.print(mcu_table(conn_mcus, title, refresh))
19
+
20
+
21
+ def abbrv_family(family: str, is_wide: bool) -> str:
22
+ if not is_wide:
23
+ ABRV = {"micropython": "upy", "circuitpython": "cpy", "unknown": "?"}
24
+ return ABRV.get(family, family[:4])
25
+ return family
26
+
27
+
28
+ def mcu_table(
29
+ conn_mcus: List[MPRemoteBoard],
30
+ title: str = "Connected boards",
31
+ refresh: bool = True,
32
+ ):
33
+ """
34
+ builds a rich table with the connected boards information
35
+ The columns of the table are adjusted to the terminal width
36
+ the columns are :
37
+ Narrow Wide
38
+ - Serial Yes Yes
39
+ - Family abbrv. Yes
40
+ - Port - yes
41
+ - Board Yes Yes BOARD_ID and Description, and the description from board_info.toml
42
+ - CPU - Yes
43
+ - Version Yes Yes
44
+ - Build * * only if any of the mcus have a build
45
+ - Location - - only if --usb is given
46
+ """
47
+ # refresh if requested
48
+ if refresh:
49
+ for mcu in track(
50
+ conn_mcus,
51
+ description="Updating board info",
52
+ transient=True,
53
+ show_speed=False,
54
+ refresh_per_second=1,
55
+ ):
56
+ try:
57
+ mcu.get_mcu_info()
58
+ except ConnectionError:
59
+ continue
60
+ table = Table(
61
+ title=title,
62
+ title_style="magenta",
63
+ header_style="bold magenta",
64
+ collapse_padding=True,
65
+ padding=(0, 0),
66
+ )
67
+ # Build the table
68
+ # check if the terminal is wide enough to show all columns or if we need to collapse some
69
+ is_wide = console.width > 99
70
+ needs_build = any(mcu.build for mcu in conn_mcus)
71
+
72
+ table.add_column("Serial" if is_wide else "Ser.", overflow="fold")
73
+ table.add_column("Family" if is_wide else "Fam.", overflow="crop", max_width=None if is_wide else 4)
74
+ if is_wide:
75
+ table.add_column("Port")
76
+ table.add_column("Board", overflow="fold")
77
+ # table.add_column("Variant") # TODO: add variant
78
+ if is_wide:
79
+ table.add_column("CPU")
80
+ table.add_column("Version", overflow="fold", min_width=5, max_width=16)
81
+ if needs_build:
82
+ table.add_column("Build" if is_wide else "Bld", justify="right")
83
+ if config.usb:
84
+ table.add_column("Location", overflow="fold", max_width=60)
85
+ # fill the table with the data
86
+ for mcu in conn_mcus:
87
+ description = f"[italic bright_cyan]{mcu.description}" if mcu.description else ""
88
+ if "description" in mcu.toml:
89
+ description += f"\n[italic bright_green]{mcu.toml['description']}"
90
+ row = [
91
+ mcu.serialport if is_wide else mcu.serialport.replace("/dev/tty", "tty"),
92
+ abbrv_family(mcu.family, is_wide),
93
+ ]
94
+ if is_wide:
95
+ row.append(mcu.port)
96
+ row.append(f"{mcu.board}\n{description}".strip())
97
+ if is_wide:
98
+ row.append(mcu.cpu)
99
+ row.append(clean_version(mcu.version))
100
+ if needs_build:
101
+ row.append(mcu.build)
102
+ if config.usb:
103
+ row.append(mcu.location)
104
+
105
+ table.add_row(*row)
106
+ return table
mpflash/logger.py CHANGED
@@ -1,41 +1,41 @@
1
- """Logging."""
2
-
3
- from loguru import logger as log
4
- from rich.console import Console
5
-
6
- from .config import config
7
-
8
- console = Console()
9
-
10
-
11
- def _log_formatter(record: dict) -> str:
12
- """Log message formatter to combine loguru and rich formatting."""
13
- color_map = {
14
- "TRACE": "dim blue",
15
- "DEBUG": "cyan",
16
- "INFO": "bold",
17
- "SUCCESS": "bold green",
18
- "WARNING": "yellow",
19
- "ERROR": "bold red",
20
- "CRITICAL": "bold white on red",
21
- }
22
- lvl_color = color_map.get(record["level"].name, "cyan")
23
- return (
24
- "[not bold green]{time:HH:mm:ss}[/not bold green] | {level.icon} " + f"[{lvl_color}]{{message}}[/{lvl_color}]"
25
- )
26
-
27
-
28
- def set_loglevel(loglevel: str):
29
- """Set the log level for the logger"""
30
- try:
31
- log.remove()
32
- except ValueError:
33
- pass
34
- log.add(console.print, level=loglevel.upper(), colorize=False, format=_log_formatter) # type: ignore
35
-
36
-
37
- def make_quiet():
38
- """Make the logger quiet"""
39
- config.quiet = True
40
- console.quiet = True
41
- set_loglevel("CRITICAL")
1
+ """Logging."""
2
+
3
+ from loguru import logger as log
4
+ from rich.console import Console
5
+
6
+ from .config import config
7
+
8
+ console = Console()
9
+
10
+
11
+ def _log_formatter(record: dict) -> str:
12
+ """Log message formatter to combine loguru and rich formatting."""
13
+ color_map = {
14
+ "TRACE": "dim blue",
15
+ "DEBUG": "cyan",
16
+ "INFO": "bold",
17
+ "SUCCESS": "bold green",
18
+ "WARNING": "yellow",
19
+ "ERROR": "bold red",
20
+ "CRITICAL": "bold white on red",
21
+ }
22
+ lvl_color = color_map.get(record["level"].name, "cyan")
23
+ return (
24
+ "[not bold green]{time:HH:mm:ss}[/not bold green] | {level.icon} " + f"[{lvl_color}]{{message}}[/{lvl_color}]"
25
+ )
26
+
27
+
28
+ def set_loglevel(loglevel: str):
29
+ """Set the log level for the logger"""
30
+ try:
31
+ log.remove()
32
+ except ValueError:
33
+ pass
34
+ log.add(console.print, level=loglevel.upper(), colorize=False, format=_log_formatter) # type: ignore
35
+
36
+
37
+ def make_quiet():
38
+ """Make the logger quiet"""
39
+ config.quiet = True
40
+ console.quiet = True
41
+ set_loglevel("CRITICAL")