mpflash 1.24.6__py3-none-any.whl → 1.24.8__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 (48) hide show
  1. mpflash/ask_input.py +7 -7
  2. mpflash/basicgit.py +23 -57
  3. mpflash/bootloader/__init__.py +0 -2
  4. mpflash/bootloader/activate.py +1 -1
  5. mpflash/bootloader/detect.py +1 -2
  6. mpflash/bootloader/manual.py +0 -1
  7. mpflash/bootloader/touch1200.py +2 -2
  8. mpflash/cli_flash.py +28 -5
  9. mpflash/cli_group.py +1 -0
  10. mpflash/cli_list.py +2 -2
  11. mpflash/cli_main.py +1 -1
  12. mpflash/common.py +6 -14
  13. mpflash/config.py +26 -7
  14. mpflash/connected.py +6 -14
  15. mpflash/download.py +56 -23
  16. mpflash/downloaded.py +1 -5
  17. mpflash/flash/__init__.py +33 -18
  18. mpflash/flash/esp.py +40 -9
  19. mpflash/flash/uf2/__init__.py +18 -2
  20. mpflash/flash/uf2/linux.py +4 -9
  21. mpflash/flash/uf2/macos.py +1 -1
  22. mpflash/flash/uf2/windows.py +1 -1
  23. mpflash/flash/worklist.py +7 -2
  24. mpflash/list.py +17 -6
  25. mpflash/logger.py +1 -3
  26. mpflash/mpboard_id/__init__.py +6 -87
  27. mpflash/mpboard_id/add_boards.py +6 -8
  28. mpflash/mpboard_id/board_id.py +7 -6
  29. mpflash/mpboard_id/board_info.json +30974 -0
  30. mpflash/mpboard_id/board_info.zip +0 -0
  31. mpflash/mpboard_id/known.py +94 -0
  32. mpflash/mpboard_id/store.py +0 -2
  33. mpflash/mpremoteboard/__init__.py +13 -9
  34. mpflash/mpremoteboard/mpy_fw_info.py +14 -17
  35. mpflash/py.typed +0 -0
  36. mpflash/vendor/click_aliases.py +64 -0
  37. mpflash/vendor/dfu.py +2 -8
  38. mpflash/vendor/pico-universal-flash-nuke/LICENSE.txt +21 -0
  39. mpflash/vendor/pico-universal-flash-nuke/universal_flash_nuke.uf2 +0 -0
  40. mpflash/vendor/pydfu.py +3 -14
  41. mpflash/vendor/readme.md +2 -0
  42. mpflash/versions.py +9 -6
  43. {mpflash-1.24.6.dist-info → mpflash-1.24.8.dist-info}/METADATA +71 -13
  44. mpflash-1.24.8.dist-info/RECORD +59 -0
  45. {mpflash-1.24.6.dist-info → mpflash-1.24.8.dist-info}/WHEEL +1 -1
  46. mpflash-1.24.6.dist-info/RECORD +0 -54
  47. {mpflash-1.24.6.dist-info → mpflash-1.24.8.dist-info}/LICENSE +0 -0
  48. {mpflash-1.24.6.dist-info → mpflash-1.24.8.dist-info}/entry_points.txt +0 -0
mpflash/ask_input.py CHANGED
@@ -11,8 +11,7 @@ from loguru import logger as log
11
11
 
12
12
  from .common import DownloadParams, FlashParams, ParamType
13
13
  from .config import config
14
- from .mpboard_id import (get_known_boards_for_port, get_known_ports,
15
- known_stored_boards)
14
+ from .mpboard_id import get_known_boards_for_port, get_known_ports, known_stored_boards
16
15
  from .mpremoteboard import MPRemoteBoard
17
16
  from .versions import micropython_versions
18
17
 
@@ -73,11 +72,11 @@ def ask_missing_params(
73
72
  # params.ports = [p for p in params.ports if p != "?"] # remove the "?" if present
74
73
  if isinstance(answers["port"], str):
75
74
  params.ports.append(answers["port"])
76
- elif isinstance(answers["port"], list): # type: ignore
75
+ elif isinstance(answers["port"], list): # type: ignore
77
76
  params.ports.extend(answers["port"])
78
77
  else:
79
78
  raise ValueError(f"Unexpected type for answers['port']: {type(answers['port'])}")
80
-
79
+
81
80
  if "boards" in answers:
82
81
  params.boards = [b for b in params.boards if b != "?"] # remove the "?" if present
83
82
  params.boards.extend(answers["boards"] if isinstance(answers["boards"], list) else [answers["boards"]])
@@ -157,23 +156,24 @@ def ask_port_board(*, multi_select: bool, action: str):
157
156
  ),
158
157
  inquirer_ux(
159
158
  "boards",
160
- message=(
161
- "Which {port} board firmware do you want to {action} " + "to {serial} ?" if action == "flash" else "?"
162
- ),
159
+ message=("Which {port} board firmware do you want to {action} " + "to {serial} ?" if action == "flash" else "?"),
163
160
  choices=filter_matching_boards,
164
161
  validate=at_least_one_validation, # type: ignore
165
162
  # validate=lambda _, x: True if x else "Please select at least one board", # type: ignore
166
163
  ),
167
164
  ]
168
165
 
166
+
169
167
  def at_least_one_validation(answers, current) -> bool:
170
168
  import inquirer.errors
169
+
171
170
  if not current:
172
171
  raise inquirer.errors.ValidationError("", reason="Please select at least one item.")
173
172
  if isinstance(current, list) and not any(current):
174
173
  raise inquirer.errors.ValidationError("", reason="Please select at least one item.")
175
174
  return True
176
175
 
176
+
177
177
  def ask_mp_version(multi_select: bool, action: str):
178
178
  """
179
179
  Asks the user for the version selection.
mpflash/basicgit.py CHANGED
@@ -4,28 +4,25 @@ Simple Git module, where needed via powershell
4
4
  Some of the functions are based on the PyGithub module
5
5
  """
6
6
 
7
- import os
8
7
  import subprocess
9
8
  from pathlib import Path
10
9
  from typing import List, Optional, Union
11
10
 
12
11
  import cachetools.func
13
- from github import Auth, BadCredentialsException, Github
14
12
  from loguru import logger as log
15
- from packaging.version import parse
16
13
 
17
- # from mpflash.versions import SET_PREVIEW
14
+ from mpflash.config import config
18
15
 
19
- # Token with no permissions to avoid throttling
20
- # https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28#getting-a-higher-rate-limit
21
- PAT_NO_ACCESS = (
22
- "github_pat_"
23
- + "11AAHPVFQ0G4NTaQ73Bw5J"
24
- + "_fAp7K9sZ1qL8VFnI9g78eUlCdmOXHB3WzSdj2jtEYb4XF3N7PDJBl32qIxq"
25
- )
26
- PAT = os.environ.get("GITHUB_TOKEN") or PAT_NO_ACCESS
27
- GH_CLIENT = Github(auth=Auth.Token(PAT))
16
+ # from github import Auth, BadCredentialsException, Github
28
17
 
18
+ # # Token with no permissions to avoid throttling
19
+ # # https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28#getting-a-higher-rate-limit
20
+ # PAT_NO_ACCESS = "github_pat_" + "11AAHPVFQ0G4NTaQ73Bw5J" + "_fAp7K9sZ1qL8VFnI9g78eUlCdmOXHB3WzSdj2jtEYb4XF3N7PDJBl32qIxq"
21
+ # PAT = os.environ.get("GITHUB_TOKEN") or PAT_NO_ACCESS
22
+
23
+ # # GH_CLIENT = Github(auth=Auth.Token(PAT))
24
+
25
+ # GH_CLIENT = None
29
26
 
30
27
  def _run_local_git(
31
28
  cmd: List[str],
@@ -47,10 +44,9 @@ def _run_local_git(
47
44
  encoding="utf-8",
48
45
  )
49
46
  else:
50
- result = subprocess.run(
51
- cmd, capture_output=capture_output, check=True, encoding="utf-8"
52
- )
47
+ result = subprocess.run(cmd, capture_output=capture_output, check=True, encoding="utf-8")
53
48
  except (NotADirectoryError, FileNotFoundError) as e: # pragma: no cover
49
+ log.error(f"Not a directory: {e}")
54
50
  return None
55
51
  except subprocess.CalledProcessError as e: # pragma: no cover
56
52
  # add some logging for github actions
@@ -88,9 +84,7 @@ def clone(remote_repo: str, path: Path, shallow: bool = False, tag: Optional[str
88
84
  return False
89
85
 
90
86
 
91
- def get_local_tag(
92
- repo: Optional[Union[str, Path]] = None, abbreviate: bool = True
93
- ) -> Union[str, None]:
87
+ def get_local_tag(repo: Optional[Union[str, Path]] = None, abbreviate: bool = True) -> Union[str, None]:
94
88
  """
95
89
  get the most recent git version tag of a local repo
96
90
  repo Path should be in the form of : repo = "./repo/micropython"
@@ -123,6 +117,9 @@ def get_local_tags(repo: Optional[Path] = None, minver: Optional[str] = None) ->
123
117
  """
124
118
  get list of all tags of a local repo
125
119
  """
120
+ # Just in time import
121
+ from packaging.version import parse
122
+
126
123
  if not repo:
127
124
  repo = Path(".")
128
125
 
@@ -136,19 +133,22 @@ def get_local_tags(repo: Optional[Path] = None, minver: Optional[str] = None) ->
136
133
  return sorted(tags)
137
134
 
138
135
 
139
- from github.GithubException import BadCredentialsException
140
-
141
-
142
136
  @cachetools.func.ttl_cache(maxsize=16, ttl=60) # 60 seconds
143
137
  def get_tags(repo: str, minver: Optional[str] = None) -> List[str]:
144
138
  """
145
139
  Get list of tag of a repote github repo.
146
140
  only the last -preview tag is kept
147
141
  """
142
+ # Just in time import
143
+ from github import BadCredentialsException
144
+ from packaging.version import parse
145
+
148
146
  if not repo or not isinstance(repo, str) or "/" not in repo: # type: ignore
149
147
  return []
148
+
149
+ gh_client = config.gh_client
150
150
  try:
151
- gh_repo = GH_CLIENT.get_repo(repo)
151
+ gh_repo = gh_client.get_repo(repo)
152
152
  except BadCredentialsException as e:
153
153
  log.error(f"Github authentication error - {e}")
154
154
  return []
@@ -179,40 +179,6 @@ def checkout_tag(tag: str, repo: Optional[Union[str, Path]] = None) -> bool:
179
179
  return True
180
180
 
181
181
 
182
- def sync_submodules(repo: Union[Path, str]) -> bool:
183
- """
184
- make sure any submodules are in sync
185
- """
186
- cmds = [
187
- ["git", "submodule", "sync", "--quiet"],
188
- # ["git", "submodule", "update", "--quiet"],
189
- ["git", "submodule", "update", "--init", "lib/micropython-lib"],
190
- ]
191
- for cmd in cmds:
192
- if result := _run_local_git(cmd, repo=repo, expect_stderr=True):
193
- # actually a good result
194
- log.debug(result.stderr)
195
- else:
196
- return False
197
- checkout_arduino_lib(Path(repo))
198
- return True
199
-
200
-
201
- def checkout_arduino_lib(mpy_path: Path):
202
- """
203
- Checkout the arduino-lib submodule repo if it exists
204
-
205
- This is needed as some of the arduino boards freeze modules originationg from the arduino-lib
206
- """
207
- # arduino_lib_path = mpy_path / "lib/arduino-lib"
208
- if (mpy_path / "lib/arduino-lib").exists():
209
- cmd = ["git", "submodule", "update", "--init", "lib/arduino-lib"]
210
- try:
211
- result = subprocess.run(cmd, cwd=mpy_path, check=True)
212
- log.info(f"checkout arduino-lib: {result.returncode}")
213
- except subprocess.CalledProcessError as e:
214
- log.warning("Could not check out arduino-lib, error: ", e)
215
-
216
182
 
217
183
  def checkout_commit(commit_hash: str, repo: Optional[Union[Path, str]] = None) -> bool:
218
184
  """
@@ -1,2 +0,0 @@
1
- from .activate import enter_bootloader # type: ignore
2
- from .detect import in_bootloader # type: ignore
@@ -12,7 +12,7 @@ from .touch1200 import enter_bootloader_touch_1200bps
12
12
 
13
13
  BL_OPTIONS = {
14
14
  "stm32": [BootloaderMethod.TOUCH_1200, BootloaderMethod.MPY, BootloaderMethod.MANUAL],
15
- "rp2": [BootloaderMethod.TOUCH_1200, BootloaderMethod.MPY, BootloaderMethod.MANUAL],
15
+ "rp2": [BootloaderMethod.MPY, BootloaderMethod.TOUCH_1200, BootloaderMethod.MANUAL],
16
16
  "samd": [BootloaderMethod.TOUCH_1200, BootloaderMethod.MPY, BootloaderMethod.MANUAL],
17
17
  "esp32": [BootloaderMethod.NONE],
18
18
  "esp8266": [BootloaderMethod.NONE],
@@ -1,5 +1,4 @@
1
- """ Detect if a board is in bootloader mode
2
- """
1
+ """Detect if a board is in bootloader mode"""
3
2
 
4
3
  import os
5
4
 
@@ -52,7 +52,6 @@ mcu_theme = Theme(
52
52
 
53
53
 
54
54
  def enter_bootloader_manual(mcu: MPRemoteBoard, timeout: int = 10):
55
-
56
55
  message: str
57
56
  if mcu.port == "rp2":
58
57
  message = f"""\
@@ -27,10 +27,10 @@ def enter_bootloader_touch_1200bps(mcu: MPRemoteBoard, timeout: int = 10):
27
27
 
28
28
  except serial.SerialException as e:
29
29
  log.exception(e)
30
- raise MPFlashError("pySerial error: " + str(e) + "\n") from e
30
+ raise MPFlashError(f"pySerial error: {str(e)}") from e
31
31
  except Exception as e:
32
32
  log.exception(e)
33
- raise MPFlashError("Error: " + str(e) + "\n") from e
33
+ raise MPFlashError(f"Error: {str(e)}") from e
34
34
 
35
35
  # be optimistic
36
36
  return True
mpflash/cli_flash.py CHANGED
@@ -92,6 +92,14 @@ from mpflash.versions import clean_version
92
92
  help="The MicroPython board ID to flash. If not specified will try to read the BOARD_ID from the connected MCU.",
93
93
  metavar="BOARD_ID or ?",
94
94
  )
95
+ @click.option(
96
+ "--variant",
97
+ "-var",
98
+ "variant", # single board
99
+ multiple=False,
100
+ help="The board VARIANT to flash or '-'. If not specified will try to read the variant from the connected MCU.",
101
+ metavar="VARIANT",
102
+ )
95
103
  @click.option(
96
104
  "--cpu",
97
105
  "--chip",
@@ -102,9 +110,9 @@ from mpflash.versions import clean_version
102
110
  )
103
111
  @click.option(
104
112
  "--erase/--no-erase",
105
- default=True,
113
+ default=False,
106
114
  show_default=True,
107
- help="""Erase flash before writing new firmware. (Not supported on UF2 boards)""",
115
+ help="""Erase flash before writing new firmware.""",
108
116
  )
109
117
  @click.option(
110
118
  "--bootloader",
@@ -115,14 +123,21 @@ from mpflash.versions import clean_version
115
123
  show_default=True,
116
124
  help="""How to enter the (MicroPython) bootloader before flashing.""",
117
125
  )
126
+ @click.option(
127
+ "--flash_mode", "-fm",
128
+ type=click.Choice(["keep", "qio", "qout", "dio", "dout"]),
129
+ default="keep",
130
+ show_default=True,
131
+ help="""Flash mode for ESP boards. (default: keep)""",
132
+ )
118
133
  def cli_flash_board(**kwargs) -> int:
119
134
  # version to versions, board to boards
120
- kwargs["versions"] = [kwargs.pop("version")] if kwargs["version"] != None else []
135
+ kwargs["versions"] = [kwargs.pop("version")] if kwargs["version"] is not None else []
121
136
  if kwargs["board"] is None:
122
137
  kwargs["boards"] = []
123
138
  kwargs.pop("board")
124
139
  else:
125
- kwargs["boards"] = [kwargs.pop("board")]
140
+ kwargs["boards"] = [kwargs.pop("board")]
126
141
 
127
142
  params = FlashParams(**kwargs)
128
143
  params.versions = list(params.versions)
@@ -141,7 +156,9 @@ def cli_flash_board(**kwargs) -> int:
141
156
  all_boards: List[MPRemoteBoard] = []
142
157
  if not params.boards:
143
158
  # nothing specified - detect connected boards
144
- params.ports, params.boards, all_boards = connected_ports_boards(include=params.ports, ignore=params.ignore, bluetooth=params.bluetooth)
159
+ params.ports, params.boards, all_boards = connected_ports_boards(
160
+ include=params.ports, ignore=params.ignore, bluetooth=params.bluetooth
161
+ )
145
162
  if params.boards == []:
146
163
  # No MicroPython boards detected, but it could be unflashed or in bootloader mode
147
164
  # Ask for serial port and board_id to flash
@@ -171,6 +188,11 @@ def cli_flash_board(**kwargs) -> int:
171
188
  if not all_boards:
172
189
  log.trace("No boards detected yet, scanning for connected boards")
173
190
  _, _, all_boards = connected_ports_boards(include=params.ports, ignore=params.ignore)
191
+ # if variant id provided on the cmdline, treat is as an override
192
+ if params.variant:
193
+ for b in all_boards:
194
+ b.variant = params.variant if (params.variant != "-") else ""
195
+
174
196
  worklist = full_auto_worklist(
175
197
  all_boards=all_boards,
176
198
  version=params.versions[0],
@@ -199,6 +221,7 @@ def cli_flash_board(**kwargs) -> int:
199
221
  params.fw_folder,
200
222
  params.erase,
201
223
  params.bootloader,
224
+ flash_mode = params.flash_mode,
202
225
  ):
203
226
  log.info(f"Flashed {len(flashed)} boards")
204
227
  show_mcus(flashed, title="Updated boards after flashing")
mpflash/cli_group.py CHANGED
@@ -39,6 +39,7 @@ def cb_test(ctx, param, value):
39
39
  config.tests = value
40
40
  return value
41
41
 
42
+
42
43
  def cb_usb(ctx, param, value: bool):
43
44
  config.usb = bool(value)
44
45
  return value
mpflash/cli_list.py CHANGED
@@ -73,8 +73,8 @@ def cli_list_mcus(serial: List[str], ignore: List[str], bluetooth: bool, as_json
73
73
  # TODO? Ask user to select a serialport if [?] is given ?
74
74
 
75
75
  conn_mcus = list_mcus(ignore=ignore, include=serial, bluetooth=bluetooth)
76
- # ignore boards that have the [micropython-stubber] ignore flag set
77
- conn_mcus = [item for item in conn_mcus if not (item.toml.get("mpflash", {}).get("ignore", False))]
76
+ # ignore boards that have the [mpflash] ignore flag set
77
+ conn_mcus = [item for item in conn_mcus if not (item.toml.get("mpflash", {}).get("ignore", False))]
78
78
  if as_json:
79
79
  # remove the path and firmware attibutes from the json output as they are always empty
80
80
  for mcu in conn_mcus:
mpflash/cli_main.py CHANGED
@@ -30,7 +30,7 @@ def mpflash():
30
30
  except click_exceptions.ClickException as e:
31
31
  log.error(f"Error: {e}")
32
32
  exit(-2)
33
- except click_exceptions.Abort as e:
33
+ except click_exceptions.Abort:
34
34
  # Aborted - Ctrl-C
35
35
  exit(-3)
36
36
 
mpflash/common.py CHANGED
@@ -10,12 +10,10 @@ from typing import List, Optional, Union
10
10
  from serial.tools import list_ports
11
11
  from serial.tools.list_ports_common import ListPortInfo
12
12
 
13
- from mpflash.basicgit import GH_CLIENT as GH_CLIENT
14
13
 
14
+ # from mpflash.flash.esp import FlashMode
15
15
  from .logger import log
16
16
 
17
- # from mpflash.mpremoteboard import MPRemoteBoard
18
-
19
17
  PORT_FWTYPES = {
20
18
  "stm32": [".dfu"], # need .dfu for pydfu.py - .hex for cube cli/GUI
21
19
  "esp32": [".bin"],
@@ -28,6 +26,7 @@ PORT_FWTYPES = {
28
26
  "renesas-ra": [".hex"],
29
27
  }
30
28
 
29
+ UF2_PORTS = [port for port, exts in PORT_FWTYPES.items() if ".uf2" in exts]
31
30
 
32
31
  @dataclass
33
32
  class FWInfo:
@@ -71,6 +70,7 @@ class Params:
71
70
 
72
71
  ports: List[str] = field(default_factory=list)
73
72
  boards: List[str] = field(default_factory=list)
73
+ variant: str = ""
74
74
  versions: List[str] = field(default_factory=list)
75
75
  fw_folder: Path = Path()
76
76
  serial: List[str] = field(default_factory=list)
@@ -101,6 +101,7 @@ class FlashParams(Params):
101
101
  erase: bool = True
102
102
  bootloader: BootloaderMethod = BootloaderMethod.NONE
103
103
  cpu: str = ""
104
+ flash_mode: str = "keep" # keep, qio, qout, dio, dout
104
105
 
105
106
  def __post_init__(self):
106
107
  if isinstance(self.bootloader, str):
@@ -137,14 +138,7 @@ def filtered_comports(
137
138
  # remove ports that are to be ignored
138
139
  log.trace(f"{include=}, {ignore=}, {bluetooth=}")
139
140
 
140
- comports = [
141
- p for p in list_ports.comports() if not any(fnmatch.fnmatch(p.device, i) for i in ignore)
142
- ]
143
-
144
- if False:
145
- import jsons
146
-
147
- print(jsons.dumps(comports).replace('{"description":', '\n{"description":'))
141
+ comports = [p for p in list_ports.comports() if not any(fnmatch.fnmatch(p.device, i) for i in ignore)]
148
142
 
149
143
  if platform.system() == "Linux":
150
144
  # use p.location to filter out the bogus ports on newer Linux kernels
@@ -156,9 +150,7 @@ def filtered_comports(
156
150
 
157
151
  if include != ["*"]:
158
152
  # if there are explicit ports to include, add them to the list
159
- explicit = [
160
- p for p in list_ports.comports() if any(fnmatch.fnmatch(p.device, i) for i in include)
161
- ]
153
+ explicit = [p for p in list_ports.comports() if any(fnmatch.fnmatch(p.device, i) for i in include)]
162
154
  log.trace(f"explicit: {[p.device for p in explicit]}")
163
155
  if ignore == []:
164
156
  # if nothing to ignore, just use the explicit list as a sinple sane default
mpflash/config.py CHANGED
@@ -3,34 +3,34 @@
3
3
  import os
4
4
  from importlib.metadata import version
5
5
  from pathlib import Path
6
- from typing import List
6
+ from typing import List, Optional
7
7
 
8
8
  import platformdirs
9
9
 
10
- from mpflash.logger import log
11
-
12
10
 
13
11
  def get_version():
14
12
  name = __package__ or "mpflash"
15
13
  return version(name)
16
14
 
17
15
 
18
- class MPtoolConfig:
16
+ class MPFlashConfig:
19
17
  """Centralized configuration for mpflash"""
20
18
 
21
19
  quiet: bool = False
22
20
  verbose: bool = False
23
21
  usb: bool = False
24
22
  ignore_ports: List[str] = []
25
- firmware_folder: Path = platformdirs.user_downloads_path() / "firmware"
23
+ _firmware_folder: Optional[Path] = None
26
24
  # test options specified on the commandline
27
25
  tests: List[str] = []
28
26
  _interactive: bool = True
27
+ _gh_client = None
29
28
 
30
29
  @property
31
30
  def interactive(self):
32
31
  # No interactions in CI
33
32
  if os.getenv("GITHUB_ACTIONS") == "true":
33
+ from mpflash.logger import log
34
34
  log.warning("Disabling interactive mode in CI")
35
35
  return False
36
36
  return self._interactive
@@ -39,6 +39,25 @@ class MPtoolConfig:
39
39
  def interactive(self, value: bool):
40
40
  self._interactive = value
41
41
 
42
-
43
- config = MPtoolConfig()
42
+ @property
43
+ def firmware_folder(self) -> Path:
44
+ """The folder where firmware files are stored"""
45
+ if not self._firmware_folder:
46
+ self._firmware_folder = platformdirs.user_downloads_path() / "firmware"
47
+ return self._firmware_folder
48
+
49
+ @property
50
+ def gh_client(self):
51
+ """The gh client to use"""
52
+ if not self._gh_client:
53
+ from github import Auth, Github
54
+ # Token with no permissions to avoid throttling
55
+ # https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28#getting-a-higher-rate-limit
56
+ PAT_NO_ACCESS = "github_pat_" + "11AAHPVFQ0G4NTaQ73Bw5J" + "_fAp7K9sZ1qL8VFnI9g78eUlCdmOXHB3WzSdj2jtEYb4XF3N7PDJBl32qIxq"
57
+ PAT = os.environ.get("GITHUB_TOKEN") or PAT_NO_ACCESS
58
+ self._gh_client = Github(auth=Auth.Token(PAT))
59
+ return self._gh_client
60
+
61
+
62
+ config = MPFlashConfig()
44
63
  __version__ = get_version()
mpflash/connected.py CHANGED
@@ -4,11 +4,9 @@ from rich import print
4
4
  from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
5
5
  from rich.table import Column
6
6
 
7
- from mpflash.common import filtered_comports
7
+ from mpflash.common import filtered_comports, find_serial_by_path
8
8
  from mpflash.mpremoteboard import MPRemoteBoard
9
9
 
10
- from mpflash.common import find_serial_by_path
11
-
12
10
 
13
11
  def connected_ports_boards(
14
12
  *, include: List[str], ignore: List[str], bluetooth: bool = False
@@ -23,13 +21,9 @@ def connected_ports_boards(
23
21
  - A list of unique board names of the connected MCUs.
24
22
  - A list of MPRemoteBoard instances of the connected MCUs.
25
23
  """
26
- conn_mcus = [
27
- b for b in list_mcus(include=include, ignore=ignore, bluetooth=bluetooth) if b.connected
28
- ]
29
- # ignore boards that have the [micropython-stubber] ignore flag set
30
- conn_mcus = [
31
- item for item in conn_mcus if not (item.toml.get("mpflash", {}).get("ignore", False))
32
- ]
24
+ conn_mcus = [b for b in list_mcus(include=include, ignore=ignore, bluetooth=bluetooth) if b.connected]
25
+ # ignore boards that have the [mpflash] ignore flag set
26
+ conn_mcus = [item for item in conn_mcus if not (item.toml.get("mpflash", {}).get("ignore", False))]
33
27
 
34
28
  ports = list({b.port for b in conn_mcus})
35
29
  boards = list({b.board for b in conn_mcus})
@@ -42,9 +36,7 @@ rp_text = TextColumn("{task.description} {task.fields[device]}", table_column=Co
42
36
  rp_bar = BarColumn(bar_width=None, table_column=Column())
43
37
 
44
38
 
45
- def list_mcus(
46
- *, ignore: List[str], include: List[str], bluetooth: bool = False
47
- ) -> List[MPRemoteBoard]:
39
+ def list_mcus(*, ignore: List[str], include: List[str], bluetooth: bool = False) -> List[MPRemoteBoard]:
48
40
  """
49
41
  Retrieves information about connected microcontroller boards.
50
42
 
@@ -63,7 +55,7 @@ def list_mcus(
63
55
  connected_mcus = [
64
56
  MPRemoteBoard(
65
57
  c.device,
66
- location=find_serial_by_path(c.device) or c.location or c.hwid or "?",
58
+ location=find_serial_by_path(c.device) or c.location or c.hwid or "?",
67
59
  )
68
60
  for c in comports
69
61
  ]