micropython-stubber 1.20.4__py3-none-any.whl → 1.20.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.
Files changed (152) hide show
  1. {micropython_stubber-1.20.4.dist-info → micropython_stubber-1.20.6.dist-info}/LICENSE +30 -30
  2. {micropython_stubber-1.20.4.dist-info → micropython_stubber-1.20.6.dist-info}/METADATA +4 -4
  3. micropython_stubber-1.20.6.dist-info/RECORD +159 -0
  4. mpflash/README.md +184 -184
  5. mpflash/libusb_flash.ipynb +203 -203
  6. mpflash/mpflash/add_firmware.py +98 -98
  7. mpflash/mpflash/ask_input.py +236 -226
  8. mpflash/mpflash/bootloader/__init__.py +37 -0
  9. mpflash/mpflash/bootloader/manual.py +102 -0
  10. mpflash/mpflash/bootloader/micropython.py +10 -0
  11. mpflash/mpflash/bootloader/touch1200.py +45 -0
  12. mpflash/mpflash/cli_download.py +129 -128
  13. mpflash/mpflash/cli_flash.py +219 -212
  14. mpflash/mpflash/cli_group.py +98 -92
  15. mpflash/mpflash/cli_list.py +81 -77
  16. mpflash/mpflash/cli_main.py +41 -38
  17. mpflash/mpflash/common.py +164 -151
  18. mpflash/mpflash/config.py +47 -31
  19. mpflash/mpflash/connected.py +74 -74
  20. mpflash/mpflash/download.py +360 -361
  21. mpflash/mpflash/downloaded.py +129 -129
  22. mpflash/mpflash/errors.py +9 -5
  23. mpflash/mpflash/flash.py +52 -69
  24. mpflash/mpflash/flash_esp.py +59 -59
  25. mpflash/mpflash/flash_stm32.py +24 -24
  26. mpflash/mpflash/flash_stm32_cube.py +111 -111
  27. mpflash/mpflash/flash_stm32_dfu.py +101 -101
  28. mpflash/mpflash/flash_uf2.py +67 -67
  29. mpflash/mpflash/flash_uf2_boardid.py +15 -15
  30. mpflash/mpflash/flash_uf2_linux.py +123 -123
  31. mpflash/mpflash/flash_uf2_macos.py +34 -37
  32. mpflash/mpflash/flash_uf2_windows.py +34 -34
  33. mpflash/mpflash/list.py +89 -89
  34. mpflash/mpflash/logger.py +41 -41
  35. mpflash/mpflash/mpboard_id/__init__.py +93 -93
  36. mpflash/mpflash/mpboard_id/add_boards.py +255 -255
  37. mpflash/mpflash/mpboard_id/board.py +37 -37
  38. mpflash/mpflash/mpboard_id/board_id.py +86 -86
  39. mpflash/mpflash/mpboard_id/store.py +43 -43
  40. mpflash/mpflash/mpremoteboard/__init__.py +221 -221
  41. mpflash/mpflash/mpremoteboard/mpy_fw_info.py +141 -141
  42. mpflash/mpflash/mpremoteboard/runner.py +140 -140
  43. mpflash/mpflash/uf2disk.py +12 -12
  44. mpflash/mpflash/vendor/basicgit.py +288 -288
  45. mpflash/mpflash/vendor/click_aliases.py +91 -0
  46. mpflash/mpflash/vendor/dfu.py +165 -165
  47. mpflash/mpflash/vendor/pydfu.py +605 -605
  48. mpflash/mpflash/vendor/readme.md +2 -2
  49. mpflash/mpflash/vendor/versions.py +119 -117
  50. mpflash/mpflash/worklist.py +170 -170
  51. mpflash/poetry.lock +1588 -1623
  52. mpflash/pyproject.toml +60 -60
  53. mpflash/stm32_udev_rules.md +62 -62
  54. stubber/__init__.py +3 -3
  55. stubber/basicgit.py +294 -288
  56. stubber/board/board_info.csv +193 -193
  57. stubber/board/boot.py +34 -34
  58. stubber/board/createstubs.py +986 -987
  59. stubber/board/createstubs_db.py +825 -826
  60. stubber/board/createstubs_db_min.py +331 -331
  61. stubber/board/createstubs_db_mpy.mpy +0 -0
  62. stubber/board/createstubs_lvgl.py +741 -741
  63. stubber/board/createstubs_lvgl_min.py +741 -741
  64. stubber/board/createstubs_mem.py +766 -767
  65. stubber/board/createstubs_mem_min.py +306 -306
  66. stubber/board/createstubs_mem_mpy.mpy +0 -0
  67. stubber/board/createstubs_min.py +294 -294
  68. stubber/board/createstubs_mpy.mpy +0 -0
  69. stubber/board/fw_info.py +141 -141
  70. stubber/board/info.py +183 -183
  71. stubber/board/main.py +19 -19
  72. stubber/board/modulelist.txt +247 -247
  73. stubber/board/pyrightconfig.json +34 -34
  74. stubber/bulk/mcu_stubber.py +454 -455
  75. stubber/codemod/_partials/__init__.py +48 -50
  76. stubber/codemod/_partials/db_main.py +147 -147
  77. stubber/codemod/_partials/lvgl_main.py +77 -77
  78. stubber/codemod/_partials/modules_reader.py +80 -80
  79. stubber/codemod/add_comment.py +53 -53
  80. stubber/codemod/add_method.py +65 -65
  81. stubber/codemod/board.py +317 -317
  82. stubber/codemod/enrich.py +145 -145
  83. stubber/codemod/merge_docstub.py +284 -284
  84. stubber/codemod/modify_list.py +54 -54
  85. stubber/codemod/utils.py +57 -57
  86. stubber/commands/build_cmd.py +94 -94
  87. stubber/commands/cli.py +51 -51
  88. stubber/commands/clone_cmd.py +66 -66
  89. stubber/commands/config_cmd.py +29 -29
  90. stubber/commands/enrich_folder_cmd.py +70 -70
  91. stubber/commands/get_core_cmd.py +69 -69
  92. stubber/commands/get_docstubs_cmd.py +87 -87
  93. stubber/commands/get_frozen_cmd.py +112 -112
  94. stubber/commands/get_mcu_cmd.py +56 -56
  95. stubber/commands/merge_cmd.py +66 -66
  96. stubber/commands/publish_cmd.py +119 -119
  97. stubber/commands/stub_cmd.py +30 -30
  98. stubber/commands/switch_cmd.py +54 -54
  99. stubber/commands/variants_cmd.py +48 -48
  100. stubber/cst_transformer.py +178 -178
  101. stubber/data/board_info.csv +193 -193
  102. stubber/data/board_info.json +1729 -1729
  103. stubber/data/micropython_tags.csv +15 -15
  104. stubber/data/requirements-core-micropython.txt +38 -38
  105. stubber/data/requirements-core-pycopy.txt +39 -39
  106. stubber/downloader.py +36 -36
  107. stubber/freeze/common.py +68 -68
  108. stubber/freeze/freeze_folder.py +69 -69
  109. stubber/freeze/freeze_manifest_2.py +113 -113
  110. stubber/freeze/get_frozen.py +127 -127
  111. stubber/get_cpython.py +101 -101
  112. stubber/get_lobo.py +59 -59
  113. stubber/minify.py +418 -418
  114. stubber/publish/bump.py +86 -86
  115. stubber/publish/candidates.py +262 -283
  116. stubber/publish/database.py +18 -18
  117. stubber/publish/defaults.py +45 -45
  118. stubber/publish/enums.py +24 -30
  119. stubber/publish/helpers.py +29 -29
  120. stubber/publish/merge_docstubs.py +130 -130
  121. stubber/publish/missing_class_methods.py +49 -49
  122. stubber/publish/package.py +146 -177
  123. stubber/publish/pathnames.py +51 -51
  124. stubber/publish/publish.py +120 -121
  125. stubber/publish/pypi.py +38 -38
  126. stubber/publish/stubpackage.py +1029 -1029
  127. stubber/rst/__init__.py +9 -9
  128. stubber/rst/classsort.py +77 -77
  129. stubber/rst/lookup.py +530 -530
  130. stubber/rst/output_dict.py +401 -401
  131. stubber/rst/reader.py +822 -823
  132. stubber/rst/report_return.py +69 -69
  133. stubber/rst/rst_utils.py +540 -540
  134. stubber/stubber.py +38 -38
  135. stubber/stubs_from_docs.py +90 -90
  136. stubber/tools/manifestfile.py +610 -610
  137. stubber/tools/readme.md +5 -5
  138. stubber/update_fallback.py +117 -117
  139. stubber/update_module_list.py +123 -125
  140. stubber/utils/__init__.py +5 -5
  141. stubber/utils/config.py +127 -127
  142. stubber/utils/makeversionhdr.py +54 -54
  143. stubber/utils/manifest.py +92 -92
  144. stubber/utils/post.py +79 -79
  145. stubber/utils/repos.py +157 -154
  146. stubber/utils/stubmaker.py +139 -139
  147. stubber/utils/typed_config_toml.py +77 -77
  148. stubber/utils/versions.py +128 -120
  149. stubber/variants.py +106 -106
  150. micropython_stubber-1.20.4.dist-info/RECORD +0 -154
  151. {micropython_stubber-1.20.4.dist-info → micropython_stubber-1.20.6.dist-info}/WHEEL +0 -0
  152. {micropython_stubber-1.20.4.dist-info → micropython_stubber-1.20.6.dist-info}/entry_points.txt +0 -0
@@ -1,123 +1,123 @@
1
- """ Flashing UF2 based MCU on Linux"""
2
-
3
- # sourcery skip: snake-case-functions
4
- from __future__ import annotations
5
-
6
- import subprocess
7
- import sys
8
- import time
9
- from pathlib import Path
10
- from typing import List
11
-
12
- from loguru import logger as log
13
- from rich.progress import track
14
-
15
- from .flash_uf2_boardid import get_board_id
16
- from .uf2disk import UF2Disk
17
-
18
- glb_dismount_me: List[UF2Disk] = []
19
-
20
-
21
- def get_uf2_drives():
22
- """
23
- Get a list of all the (un)mounted UF2 drives
24
- """
25
- # import blkinfo only on linux
26
- from blkinfo import BlkDiskInfo
27
-
28
- myblkd = BlkDiskInfo()
29
- filters = {
30
- "tran": "usb",
31
- }
32
- usb_disks = myblkd.get_disks(filters)
33
- for disk in usb_disks:
34
- if disk["fstype"] == "vfat":
35
- uf2_part = disk
36
- # unpartioned usb disk or partition (e.g. /dev/sdb )
37
- # SEEED WIO Terminal is unpartioned
38
- # print( json.dumps(uf2_part, indent=4))
39
- uf2 = UF2Disk()
40
- uf2.device_path = "/dev/" + uf2_part["name"]
41
- uf2.label = uf2_part["label"]
42
- uf2.mountpoint = uf2_part["mountpoint"]
43
- yield uf2
44
- elif disk["type"] == "disk" and disk.get("children") and len(disk.get("children")) > 0:
45
- if disk.get("children")[0]["type"] == "part" and disk.get("children")[0]["fstype"] == "vfat":
46
- uf2_part = disk.get("children")[0]
47
- # print( json.dumps(uf2_part, indent=4))
48
- uf2 = UF2Disk()
49
- uf2.device_path = "/dev/" + uf2_part["name"]
50
- uf2.label = uf2_part["label"]
51
- uf2.mountpoint = uf2_part["mountpoint"]
52
- yield uf2
53
-
54
-
55
- def pmount(disk: UF2Disk):
56
- """
57
- Mount a UF2 drive if there is no mountpoint yet.
58
- """
59
- global glb_dismount_me
60
- if not disk.mountpoint:
61
- if not disk.label:
62
- disk.label = "UF2BOOT"
63
- disk.mountpoint = f"/media/{disk.label}"
64
- # capture error if pmount is not installed
65
- try:
66
- subprocess.run(["pmount", disk.device_path, disk.mountpoint])
67
- except FileNotFoundError:
68
- log.error("pmount not found, please install it using 'sudo apt install pmount'")
69
- return
70
- log.debug(f"Mounted {disk.label} at {disk.mountpoint}")
71
- glb_dismount_me.append(disk)
72
- else:
73
- log.debug(f"\n{disk.label} already mounted at {disk.mountpoint}")
74
-
75
-
76
- def pumount(disk: UF2Disk):
77
- """
78
- Unmount a UF2 drive
79
- """
80
- if sys.platform != "linux":
81
- log.error("pumount only works on Linux")
82
- return
83
- if disk.mountpoint:
84
- subprocess.run(["pumount", disk.mountpoint]) # ), f"/media/{disk.label}"])
85
- log.info(f"Unmounted {disk.label} from {disk.mountpoint}")
86
- disk.mountpoint = f""
87
- else:
88
- log.warning(f"{disk.label} already dismounted")
89
-
90
-
91
- def dismount_uf2_linux():
92
- global glb_dismount_me
93
- for disk in glb_dismount_me:
94
- pumount(disk)
95
- glb_dismount_me = []
96
-
97
-
98
- def wait_for_UF2_linux(s_max: int = 10):
99
- destination = ""
100
- wait = 10
101
- uf2_drives = []
102
- # while not destination and wait > 0:
103
- for _ in track(
104
- range(s_max), description="Waiting for mcu to mount as a drive", transient=True, refresh_per_second=2
105
- ):
106
- # log.info(f"Waiting for mcu to mount as a drive : {wait} seconds left")
107
- uf2_drives += list(get_uf2_drives())
108
- for drive in get_uf2_drives():
109
- pmount(drive)
110
- time.sleep(1)
111
- try:
112
- if Path(drive.mountpoint, "INFO_UF2.TXT").exists():
113
- board_id = get_board_id(Path(drive.mountpoint)) # type: ignore
114
- destination = Path(drive.mountpoint)
115
- break
116
- except PermissionError:
117
- log.debug(f"Permission error on {drive.mountpoint}")
118
- continue
119
- if destination:
120
- break
121
- time.sleep(1)
122
- wait -= 1
123
- return destination
1
+ """ Flashing UF2 based MCU on Linux"""
2
+
3
+ # sourcery skip: snake-case-functions
4
+ from __future__ import annotations
5
+
6
+ import subprocess
7
+ import sys
8
+ import time
9
+ from pathlib import Path
10
+ from typing import List
11
+
12
+ from loguru import logger as log
13
+ from rich.progress import track
14
+
15
+ from .flash_uf2_boardid import get_board_id
16
+ from .uf2disk import UF2Disk
17
+
18
+ glb_dismount_me: List[UF2Disk] = []
19
+
20
+
21
+ def get_uf2_drives():
22
+ """
23
+ Get a list of all the (un)mounted UF2 drives
24
+ """
25
+ # import blkinfo only on linux
26
+ from blkinfo import BlkDiskInfo
27
+
28
+ myblkd = BlkDiskInfo()
29
+ filters = {
30
+ "tran": "usb",
31
+ }
32
+ usb_disks = myblkd.get_disks(filters)
33
+ for disk in usb_disks:
34
+ if disk["fstype"] == "vfat":
35
+ uf2_part = disk
36
+ # unpartioned usb disk or partition (e.g. /dev/sdb )
37
+ # SEEED WIO Terminal is unpartioned
38
+ # print( json.dumps(uf2_part, indent=4))
39
+ uf2 = UF2Disk()
40
+ uf2.device_path = "/dev/" + uf2_part["name"]
41
+ uf2.label = uf2_part["label"]
42
+ uf2.mountpoint = uf2_part["mountpoint"]
43
+ yield uf2
44
+ elif disk["type"] == "disk" and disk.get("children") and len(disk.get("children")) > 0:
45
+ if disk.get("children")[0]["type"] == "part" and disk.get("children")[0]["fstype"] == "vfat":
46
+ uf2_part = disk.get("children")[0]
47
+ # print( json.dumps(uf2_part, indent=4))
48
+ uf2 = UF2Disk()
49
+ uf2.device_path = "/dev/" + uf2_part["name"]
50
+ uf2.label = uf2_part["label"]
51
+ uf2.mountpoint = uf2_part["mountpoint"]
52
+ yield uf2
53
+
54
+
55
+ def pmount(disk: UF2Disk):
56
+ """
57
+ Mount a UF2 drive if there is no mountpoint yet.
58
+ """
59
+ global glb_dismount_me
60
+ if not disk.mountpoint:
61
+ if not disk.label:
62
+ disk.label = "UF2BOOT"
63
+ disk.mountpoint = f"/media/{disk.label}"
64
+ # capture error if pmount is not installed
65
+ try:
66
+ subprocess.run(["pmount", disk.device_path, disk.mountpoint])
67
+ except FileNotFoundError:
68
+ log.error("pmount not found, please install it using 'sudo apt install pmount'")
69
+ return
70
+ log.debug(f"Mounted {disk.label} at {disk.mountpoint}")
71
+ glb_dismount_me.append(disk)
72
+ else:
73
+ log.debug(f"\n{disk.label} already mounted at {disk.mountpoint}")
74
+
75
+
76
+ def pumount(disk: UF2Disk):
77
+ """
78
+ Unmount a UF2 drive
79
+ """
80
+ if sys.platform != "linux":
81
+ log.error("pumount only works on Linux")
82
+ return
83
+ if disk.mountpoint:
84
+ subprocess.run(["pumount", disk.mountpoint]) # ), f"/media/{disk.label}"])
85
+ log.info(f"Unmounted {disk.label} from {disk.mountpoint}")
86
+ disk.mountpoint = f""
87
+ else:
88
+ log.warning(f"{disk.label} already dismounted")
89
+
90
+
91
+ def dismount_uf2_linux():
92
+ global glb_dismount_me
93
+ for disk in glb_dismount_me:
94
+ pumount(disk)
95
+ glb_dismount_me = []
96
+
97
+
98
+ def wait_for_UF2_linux(s_max: int = 10):
99
+ destination = ""
100
+ wait = 10
101
+ uf2_drives = []
102
+ # while not destination and wait > 0:
103
+ for _ in track(
104
+ range(s_max), description="Waiting for mcu to mount as a drive", transient=True, refresh_per_second=2
105
+ ):
106
+ # log.info(f"Waiting for mcu to mount as a drive : {wait} seconds left")
107
+ uf2_drives += list(get_uf2_drives())
108
+ for drive in get_uf2_drives():
109
+ pmount(drive)
110
+ time.sleep(1)
111
+ try:
112
+ if Path(drive.mountpoint, "INFO_UF2.TXT").exists():
113
+ board_id = get_board_id(Path(drive.mountpoint)) # type: ignore
114
+ destination = Path(drive.mountpoint)
115
+ break
116
+ except PermissionError:
117
+ log.debug(f"Permission error on {drive.mountpoint}")
118
+ continue
119
+ if destination:
120
+ break
121
+ time.sleep(1)
122
+ wait -= 1
123
+ return destination
@@ -1,37 +1,34 @@
1
- """ Flashing UF2 based MCU on macos"""
2
-
3
- # sourcery skip: snake-case-functions
4
- from __future__ import annotations
5
-
6
- import sys
7
- import time
8
- from pathlib import Path
9
- from typing import Optional
10
-
11
- from loguru import logger as log
12
- from rich.progress import track
13
-
14
- from .flash_uf2_boardid import get_board_id
15
-
16
-
17
- def wait_for_UF2_macos(s_max: int = 10) -> Optional[Path]:
18
- """Wait for the MCU to mount as a drive"""
19
- if s_max < 1:
20
- s_max = 10
21
- destination = None
22
- for _ in track(
23
- range(s_max), description="Waiting for mcu to mount as a drive", transient=True, refresh_per_second=2
24
- ):
25
- # log.info(f"Waiting for mcu to mount as a drive : {n} seconds left")
26
- vol_mounts = Path("/Volumes").iterdir()
27
- for vol in vol_mounts:
28
- try:
29
- if Path(vol, "INFO_UF2.TXT").exists():
30
- destination = Path(vol)
31
- break
32
- except OSError:
33
- pass
34
- if destination:
35
- break
36
- time.sleep(1)
37
- return destination
1
+ """ Flashing UF2 based MCU on macos"""
2
+
3
+ # sourcery skip: snake-case-functions
4
+ from __future__ import annotations
5
+
6
+ import time
7
+ from pathlib import Path
8
+ from typing import Optional
9
+
10
+ from rich.progress import track
11
+
12
+
13
+
14
+ def wait_for_UF2_macos(s_max: int = 10) -> Optional[Path]:
15
+ """Wait for the MCU to mount as a drive"""
16
+ if s_max < 1:
17
+ s_max = 10
18
+ destination = None
19
+ for _ in track(
20
+ range(s_max), description="Waiting for mcu to mount as a drive", transient=True, refresh_per_second=2
21
+ ):
22
+ # log.info(f"Waiting for mcu to mount as a drive : {n} seconds left")
23
+ vol_mounts = Path("/Volumes").iterdir()
24
+ for vol in vol_mounts:
25
+ try:
26
+ if Path(vol, "INFO_UF2.TXT").exists():
27
+ destination = Path(vol)
28
+ break
29
+ except OSError:
30
+ pass
31
+ if destination:
32
+ break
33
+ time.sleep(1)
34
+ return destination
@@ -1,34 +1,34 @@
1
- # sourcery skip: snake-case-functions
2
- """Flash a MCU with a UF2 bootloader on Windows"""
3
-
4
- from __future__ import annotations
5
-
6
- import time
7
- from pathlib import Path
8
- from typing import Optional
9
-
10
- import psutil
11
- from rich.progress import track
12
-
13
-
14
-
15
-
16
- def wait_for_UF2_windows(s_max: int = 10) -> Optional[Path]:
17
- """Wait for the MCU to mount as a drive"""
18
- if s_max < 1:
19
- s_max = 10
20
- destination = None
21
- for _ in track(range(s_max), description="Waiting for mcu to mount as a drive", transient=True,refresh_per_second=2):
22
- # log.info(f"Waiting for mcu to mount as a drive : {n} seconds left")
23
- drives = [drive.device for drive in psutil.disk_partitions()]
24
- for drive in drives:
25
- try:
26
- if Path(drive, "INFO_UF2.TXT").exists():
27
- destination = Path(drive)
28
- break
29
- except OSError:
30
- pass
31
- if destination:
32
- break
33
- time.sleep(1)
34
- return destination
1
+ # sourcery skip: snake-case-functions
2
+ """Flash a MCU with a UF2 bootloader on Windows"""
3
+
4
+ from __future__ import annotations
5
+
6
+ import time
7
+ from pathlib import Path
8
+ from typing import Optional
9
+
10
+ import psutil
11
+ from rich.progress import track
12
+
13
+
14
+
15
+
16
+ def wait_for_UF2_windows(s_max: int = 10) -> Optional[Path]:
17
+ """Wait for the MCU to mount as a drive"""
18
+ if s_max < 1:
19
+ s_max = 10
20
+ destination = None
21
+ for _ in track(range(s_max), description="Waiting for mcu to mount as a drive", transient=True,refresh_per_second=2):
22
+ # log.info(f"Waiting for mcu to mount as a drive : {n} seconds left")
23
+ drives = [drive.device for drive in psutil.disk_partitions()]
24
+ for drive in drives:
25
+ try:
26
+ if Path(drive, "INFO_UF2.TXT").exists():
27
+ destination = Path(drive)
28
+ break
29
+ except OSError:
30
+ pass
31
+ if destination:
32
+ break
33
+ time.sleep(1)
34
+ return destination
mpflash/mpflash/list.py CHANGED
@@ -1,89 +1,89 @@
1
- from typing import List
2
-
3
- from rich.progress import track
4
- from rich.table import Table
5
-
6
- from mpflash.mpremoteboard import MPRemoteBoard
7
- from mpflash.vendor.versions import clean_version
8
-
9
- from .logger import console
10
-
11
-
12
- def show_mcus(
13
- conn_mcus: List[MPRemoteBoard],
14
- title: str = "Connected boards",
15
- refresh: bool = True,
16
- ):
17
- console.print(mcu_table(conn_mcus, title, refresh))
18
-
19
-
20
- def abbrv_family(family: str, is_wide: bool) -> str:
21
- if not is_wide:
22
- ABRV = {"micropython": "upy", "circuitpython": "cpy", "unknown": "?"}
23
- return ABRV.get(family, family[:4])
24
- return family
25
-
26
-
27
- def mcu_table(
28
- conn_mcus: List[MPRemoteBoard],
29
- title: str = "Connected boards",
30
- refresh: bool = True,
31
- ):
32
- """
33
- builds a rich table with the connected boards information
34
- The columns of the table are adjusted to the terminal width
35
- the columns are :
36
- Narrow Wide
37
- - Serial Yes Yes
38
- - Family abbrv. Yes
39
- - Port - yes
40
- - Board Yes Yes BOARD_ID and Description
41
- - CPU - Yes
42
- - Version Yes Yes
43
- - Build * * only if any of the mcus have a build
44
- """
45
- table = Table(
46
- title=title,
47
- title_style="magenta",
48
- header_style="bold magenta",
49
- collapse_padding=True,
50
- padding=(0, 0),
51
- )
52
- # check if the terminal is wide enough to show all columns or if we need to collapse some
53
- is_wide = console.width > 99
54
- needs_build = any(mcu.build for mcu in conn_mcus)
55
-
56
- table.add_column("Serial" if is_wide else "Ser.", overflow="fold")
57
- table.add_column("Family" if is_wide else "Fam.", overflow="crop", max_width=None if is_wide else 4)
58
- if is_wide:
59
- table.add_column("Port")
60
- table.add_column("Board", overflow="fold")
61
- # table.add_column("Variant") # TODO: add variant
62
- if is_wide:
63
- table.add_column("CPU")
64
- table.add_column("Version", overflow="fold", min_width=5, max_width=16)
65
- if needs_build:
66
- table.add_column("Build" if is_wide else "Bld", justify="right")
67
-
68
- for mcu in track(conn_mcus, description="Updating board info", transient=True, refresh_per_second=2):
69
- if refresh:
70
- try:
71
- mcu.get_mcu_info()
72
- except ConnectionError:
73
- continue
74
- description = f"[italic bright_cyan]{mcu.description}" if mcu.description else ""
75
- row = [
76
- mcu.serialport.replace("/dev/", ""),
77
- abbrv_family(mcu.family, is_wide),
78
- ]
79
- if is_wide:
80
- row.append(mcu.port)
81
- row.append(f"{mcu.board}\n{description}".strip())
82
- if is_wide:
83
- row.append(mcu.cpu)
84
- row.append(clean_version(mcu.version))
85
- if needs_build:
86
- row.append(mcu.build)
87
-
88
- table.add_row(*row)
89
- return table
1
+ from typing import List
2
+
3
+ from rich.progress import track
4
+ from rich.table import Table
5
+
6
+ from mpflash.mpremoteboard import MPRemoteBoard
7
+ from mpflash.vendor.versions import clean_version
8
+
9
+ from .logger import console
10
+
11
+
12
+ def show_mcus(
13
+ conn_mcus: List[MPRemoteBoard],
14
+ title: str = "Connected boards",
15
+ refresh: bool = True,
16
+ ):
17
+ console.print(mcu_table(conn_mcus, title, refresh))
18
+
19
+
20
+ def abbrv_family(family: str, is_wide: bool) -> str:
21
+ if not is_wide:
22
+ ABRV = {"micropython": "upy", "circuitpython": "cpy", "unknown": "?"}
23
+ return ABRV.get(family, family[:4])
24
+ return family
25
+
26
+
27
+ def mcu_table(
28
+ conn_mcus: List[MPRemoteBoard],
29
+ title: str = "Connected boards",
30
+ refresh: bool = True,
31
+ ):
32
+ """
33
+ builds a rich table with the connected boards information
34
+ The columns of the table are adjusted to the terminal width
35
+ the columns are :
36
+ Narrow Wide
37
+ - Serial Yes Yes
38
+ - Family abbrv. Yes
39
+ - Port - yes
40
+ - Board Yes Yes BOARD_ID and Description
41
+ - CPU - Yes
42
+ - Version Yes Yes
43
+ - Build * * only if any of the mcus have a build
44
+ """
45
+ table = Table(
46
+ title=title,
47
+ title_style="magenta",
48
+ header_style="bold magenta",
49
+ collapse_padding=True,
50
+ padding=(0, 0),
51
+ )
52
+ # check if the terminal is wide enough to show all columns or if we need to collapse some
53
+ is_wide = console.width > 99
54
+ needs_build = any(mcu.build for mcu in conn_mcus)
55
+
56
+ table.add_column("Serial" if is_wide else "Ser.", overflow="fold")
57
+ table.add_column("Family" if is_wide else "Fam.", overflow="crop", max_width=None if is_wide else 4)
58
+ if is_wide:
59
+ table.add_column("Port")
60
+ table.add_column("Board", overflow="fold")
61
+ # table.add_column("Variant") # TODO: add variant
62
+ if is_wide:
63
+ table.add_column("CPU")
64
+ table.add_column("Version", overflow="fold", min_width=5, max_width=16)
65
+ if needs_build:
66
+ table.add_column("Build" if is_wide else "Bld", justify="right")
67
+
68
+ for mcu in track(conn_mcus, description="Updating board info", transient=True, refresh_per_second=2):
69
+ if refresh:
70
+ try:
71
+ mcu.get_mcu_info()
72
+ except ConnectionError:
73
+ continue
74
+ description = f"[italic bright_cyan]{mcu.description}" if mcu.description else ""
75
+ row = [
76
+ mcu.serialport.replace("/dev/", ""),
77
+ abbrv_family(mcu.family, is_wide),
78
+ ]
79
+ if is_wide:
80
+ row.append(mcu.port)
81
+ row.append(f"{mcu.board}\n{description}".strip())
82
+ if is_wide:
83
+ row.append(mcu.cpu)
84
+ row.append(clean_version(mcu.version))
85
+ if needs_build:
86
+ row.append(mcu.build)
87
+
88
+ table.add_row(*row)
89
+ return table
mpflash/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")