circfirm 1.0.1__tar.gz → 2.0.1__tar.gz

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 (69) hide show
  1. {circfirm-1.0.1 → circfirm-2.0.1}/PKG-INFO +1 -1
  2. circfirm-2.0.1/VERSION +1 -0
  3. {circfirm-1.0.1 → circfirm-2.0.1}/circfirm/backend.py +30 -16
  4. {circfirm-1.0.1 → circfirm-2.0.1}/circfirm/cli.py +29 -19
  5. {circfirm-1.0.1 → circfirm-2.0.1}/circfirm.egg-info/PKG-INFO +1 -1
  6. circfirm-2.0.1/tests/assets/boot_out.txt +3 -0
  7. {circfirm-1.0.1 → circfirm-2.0.1}/tests/helpers.py +6 -0
  8. {circfirm-1.0.1 → circfirm-2.0.1}/tests/test_backend.py +30 -11
  9. {circfirm-1.0.1 → circfirm-2.0.1}/tests/test_cli.py +36 -20
  10. circfirm-1.0.1/VERSION +0 -1
  11. circfirm-1.0.1/tests/assets/boot_out.txt +0 -3
  12. {circfirm-1.0.1 → circfirm-2.0.1}/.github/workflows/codeql.yml +0 -0
  13. {circfirm-1.0.1 → circfirm-2.0.1}/.github/workflows/publish.yml +0 -0
  14. {circfirm-1.0.1 → circfirm-2.0.1}/.github/workflows/push.yml +0 -0
  15. {circfirm-1.0.1 → circfirm-2.0.1}/.gitignore +0 -0
  16. {circfirm-1.0.1 → circfirm-2.0.1}/.pre-commit-config.yaml +0 -0
  17. {circfirm-1.0.1 → circfirm-2.0.1}/.reuse/dep5 +0 -0
  18. {circfirm-1.0.1 → circfirm-2.0.1}/LICENSE +0 -0
  19. {circfirm-1.0.1 → circfirm-2.0.1}/LICENSES/MIT.txt +0 -0
  20. {circfirm-1.0.1 → circfirm-2.0.1}/Makefile +0 -0
  21. {circfirm-1.0.1 → circfirm-2.0.1}/README.rst +0 -0
  22. {circfirm-1.0.1 → circfirm-2.0.1}/README.rst.license +0 -0
  23. {circfirm-1.0.1 → circfirm-2.0.1}/VERSION.license +0 -0
  24. {circfirm-1.0.1 → circfirm-2.0.1}/circfirm/__init__.py +0 -0
  25. {circfirm-1.0.1 → circfirm-2.0.1}/circfirm/startup.py +0 -0
  26. {circfirm-1.0.1 → circfirm-2.0.1}/circfirm.egg-info/SOURCES.txt +0 -0
  27. {circfirm-1.0.1 → circfirm-2.0.1}/circfirm.egg-info/dependency_links.txt +0 -0
  28. {circfirm-1.0.1 → circfirm-2.0.1}/circfirm.egg-info/entry_points.txt +0 -0
  29. {circfirm-1.0.1 → circfirm-2.0.1}/circfirm.egg-info/requires.txt +0 -0
  30. {circfirm-1.0.1 → circfirm-2.0.1}/circfirm.egg-info/top_level.txt +0 -0
  31. {circfirm-1.0.1 → circfirm-2.0.1}/pyproject.toml +0 -0
  32. {circfirm-1.0.1 → circfirm-2.0.1}/requirements-dev.txt +0 -0
  33. {circfirm-1.0.1 → circfirm-2.0.1}/requirements.txt +0 -0
  34. {circfirm-1.0.1 → circfirm-2.0.1}/scripts/rmdir.py +0 -0
  35. {circfirm-1.0.1 → circfirm-2.0.1}/setup.cfg +0 -0
  36. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-en_US-7.0.0.uf2 +0 -0
  37. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-en_US-7.1.0.uf2 +0 -0
  38. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-en_US-7.2.0.uf2 +0 -0
  39. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-fr-7.0.0.uf2 +0 -0
  40. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-fr-7.1.0.uf2 +0 -0
  41. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-fr-7.2.0.uf2 +0 -0
  42. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-zh_Latn_pinyin-7.0.0.uf2 +0 -0
  43. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-zh_Latn_pinyin-7.1.0.uf2 +0 -0
  44. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-zh_Latn_pinyin-7.2.0.uf2 +0 -0
  45. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-en_US-7.0.0.uf2 +0 -0
  46. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-en_US-7.1.0.uf2 +0 -0
  47. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-en_US-7.2.0.uf2 +0 -0
  48. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-fr-7.0.0.uf2 +0 -0
  49. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-fr-7.1.0.uf2 +0 -0
  50. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-fr-7.2.0.uf2 +0 -0
  51. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-zh_Latn_pinyin-7.0.0.uf2 +0 -0
  52. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-zh_Latn_pinyin-7.1.0.uf2 +0 -0
  53. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-zh_Latn_pinyin-7.2.0.uf2 +0 -0
  54. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-en_US-7.0.0.uf2 +0 -0
  55. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-en_US-7.1.0.uf2 +0 -0
  56. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-en_US-7.2.0.uf2 +0 -0
  57. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-fr-7.0.0.uf2 +0 -0
  58. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-fr-7.1.0.uf2 +0 -0
  59. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-fr-7.2.0.uf2 +0 -0
  60. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-zh_Latn_pinyin-7.0.0.uf2 +0 -0
  61. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-zh_Latn_pinyin-7.1.0.uf2 +0 -0
  62. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-zh_Latn_pinyin-7.2.0.uf2 +0 -0
  63. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/info_uf2.txt +0 -0
  64. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/responses/full_list.txt +0 -0
  65. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/responses/full_list.txt.license +0 -0
  66. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/responses/specific_board.txt +0 -0
  67. {circfirm-1.0.1 → circfirm-2.0.1}/tests/assets/responses/specific_board.txt.license +0 -0
  68. {circfirm-1.0.1 → circfirm-2.0.1}/tests/conftest.py +0 -0
  69. {circfirm-1.0.1 → circfirm-2.0.1}/tests/test_startup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: circfirm
3
- Version: 1.0.1
3
+ Version: 2.0.1
4
4
  Summary: CLI tool for install firmware for CircuitPython boards
5
5
  Author-email: Alec Delaney <tekktrik@gmail.com>
6
6
  License: MIT
circfirm-2.0.1/VERSION ADDED
@@ -0,0 +1 @@
1
+ 2.0.1
@@ -10,6 +10,7 @@ Author(s): Alec Delaney
10
10
  import enum
11
11
  import os
12
12
  import pathlib
13
+ import re
13
14
  from typing import Dict, List, Optional, Set, Tuple
14
15
 
15
16
  import packaging.version
@@ -45,6 +46,18 @@ class Language(enum.Enum):
45
46
  MANDARIN_LATIN_PINYIN = "zh_Latn_pinyin"
46
47
 
47
48
 
49
+ _ALL_LANGAGES = [language.value for language in Language]
50
+ _ALL_LANGUAGES_REGEX = "|".join(_ALL_LANGAGES)
51
+ FIRMWARE_REGEX = "-".join(
52
+ [
53
+ r"adafruit-circuitpython-(.*)",
54
+ f"({_ALL_LANGUAGES_REGEX})",
55
+ r"(\d+\.\d+\.\d+(?:-(?:\balpha\b|\bbeta\b)\.\d+)*)\.uf2",
56
+ ]
57
+ )
58
+ BOARD_ID_REGEX = r"Board ID:\s*(.*)"
59
+
60
+
48
61
  def _find_device(filename: str) -> Optional[str]:
49
62
  """Find a specific connected device."""
50
63
  for partition in psutil.disk_partitions():
@@ -69,19 +82,20 @@ def find_bootloader() -> Optional[str]:
69
82
 
70
83
  def get_board_name(device_path: str) -> str:
71
84
  """Get the attached CircuitPython board's name."""
72
- uf2info_file = pathlib.Path(device_path) / circfirm.UF2INFO_FILE
73
- with open(uf2info_file, encoding="utf-8") as infofile:
85
+ bootout_file = pathlib.Path(device_path) / circfirm.BOOTOUT_FILE
86
+ with open(bootout_file, encoding="utf-8") as infofile:
74
87
  contents = infofile.read()
75
- model_line = [line.strip() for line in contents.split("\n")][1]
76
- return [comp.strip() for comp in model_line.split(":")][1]
88
+ board_match = re.search(BOARD_ID_REGEX, contents)
89
+ if not board_match:
90
+ raise ValueError("Could not parse the board name from the boot out file")
91
+ return board_match[1]
77
92
 
78
93
 
79
94
  def download_uf2(board: str, version: str, language: str = "en_US") -> None:
80
95
  """Download a version of CircuitPython for a specific board."""
81
96
  file = get_uf2_filename(board, version, language=language)
82
- board_name = board.replace(" ", "_").lower()
83
97
  uf2_file = get_uf2_filepath(board, version, language=language, ensure=True)
84
- url = f"https://downloads.circuitpython.org/bin/{board_name}/{language}/{file}"
98
+ url = f"https://downloads.circuitpython.org/bin/{board}/{language}/{file}"
85
99
  response = requests.get(url)
86
100
 
87
101
  SUCCESS = 200
@@ -105,8 +119,7 @@ def get_uf2_filepath(
105
119
  ) -> pathlib.Path:
106
120
  """Get the path to a downloaded UF2 file."""
107
121
  file = get_uf2_filename(board, version, language)
108
- board_name = board.replace(" ", "_").lower()
109
- uf2_folder = pathlib.Path(circfirm.UF2_ARCHIVE) / board_name
122
+ uf2_folder = pathlib.Path(circfirm.UF2_ARCHIVE) / board
110
123
  if ensure:
111
124
  circfirm.startup.ensure_dir(uf2_folder)
112
125
  return pathlib.Path(uf2_folder) / file
@@ -114,22 +127,23 @@ def get_uf2_filepath(
114
127
 
115
128
  def get_uf2_filename(board: str, version: str, language: str = "en_US") -> str:
116
129
  """Get the structured name for a specific board/version CircuitPython."""
117
- board_name = board.replace(" ", "_").lower()
118
- return f"adafruit-circuitpython-{board_name}-{language}-{version}.uf2"
130
+ return f"adafruit-circuitpython-{board}-{language}-{version}.uf2"
119
131
 
120
132
 
121
133
  def get_board_folder(board: str) -> pathlib.Path:
122
134
  """Get the board folder path."""
123
- board_name = board.replace(" ", "_").lower()
124
- return pathlib.Path(circfirm.UF2_ARCHIVE) / board_name
135
+ return pathlib.Path(circfirm.UF2_ARCHIVE) / board
125
136
 
126
137
 
127
138
  def get_firmware_info(uf2_filename: str) -> Tuple[str, str]:
128
139
  """Get firmware info."""
129
- filename_parts = uf2_filename.split("-")
130
- language = filename_parts[3]
131
- version_extension = "-".join(filename_parts[4:])
132
- version = version_extension[:-4]
140
+ regex_match = re.match(FIRMWARE_REGEX, uf2_filename)
141
+ if regex_match is None:
142
+ raise ValueError(
143
+ "Firmware information could not be determined from the filename"
144
+ )
145
+ version = regex_match[3]
146
+ language = regex_match[2]
133
147
  return version, language
134
148
 
135
149
 
@@ -11,6 +11,7 @@ import os
11
11
  import pathlib
12
12
  import shutil
13
13
  import sys
14
+ import time
14
15
  from typing import Optional
15
16
 
16
17
  import click
@@ -30,21 +31,34 @@ def cli() -> None:
30
31
  @cli.command()
31
32
  @click.argument("version")
32
33
  @click.option("-l", "--language", default="en_US", help="CircuitPython language/locale")
33
- def install(version: str, language: str) -> None:
34
+ @click.option("-b", "--board", default=None, help="Assume the given board name")
35
+ def install(version: str, language: str, board: Optional[str]) -> None:
34
36
  """Install the specified version of CircuitPython."""
35
- mount_path = circfirm.backend.find_bootloader()
36
- if not mount_path:
37
- circuitpy = circfirm.backend.find_circuitpy()
38
- if circuitpy:
37
+ circuitpy = circfirm.backend.find_circuitpy()
38
+ bootloader = circfirm.backend.find_bootloader()
39
+ if not circuitpy and not bootloader:
40
+ click.echo("CircuitPython device not found!")
41
+ click.echo("Check that the device is connected and mounted.")
42
+ sys.exit(1)
43
+
44
+ if not board:
45
+ if not circuitpy and bootloader:
46
+ click.echo("CircuitPython device found, but it is in bootloader mode!")
47
+ click.echo(
48
+ "Please put the device out of bootloader mode, or use the --board option."
49
+ )
50
+ sys.exit(3)
51
+ board = circfirm.backend.get_board_name(circuitpy)
52
+
53
+ click.echo("Board name detected, please switch the device to bootloader mode.")
54
+ while not (bootloader := circfirm.backend.find_bootloader()):
55
+ time.sleep(1)
56
+
57
+ if not bootloader:
58
+ if circfirm.backend.find_circuitpy():
39
59
  click.echo("CircuitPython device found, but is not in bootloader mode!")
40
60
  click.echo("Please put the device in bootloader mode.")
41
61
  sys.exit(2)
42
- else:
43
- click.echo("CircuitPython device not found!")
44
- click.echo("Check that the device is connected and mounted.")
45
- sys.exit(1)
46
-
47
- board = circfirm.backend.get_board_name(mount_path)
48
62
 
49
63
  if not circfirm.backend.is_downloaded(board, version, language):
50
64
  click.echo("Downloading UF2...")
@@ -52,7 +66,7 @@ def install(version: str, language: str) -> None:
52
66
 
53
67
  uf2file = circfirm.backend.get_uf2_filepath(board, version, language)
54
68
  uf2filename = os.path.basename(uf2file)
55
- shutil.copyfile(uf2file, os.path.join(mount_path, uf2filename))
69
+ shutil.copyfile(uf2file, os.path.join(bootloader, uf2filename))
56
70
  click.echo("UF2 file copied to device!")
57
71
  click.echo("Device should reboot momentarily.")
58
72
 
@@ -76,8 +90,6 @@ def clear(
76
90
  click.echo("Cache cleared!")
77
91
  return
78
92
 
79
- board = board.replace(" ", "_").lower()
80
-
81
93
  glob_pattern = "*-*" if board is None else f"*-{board}"
82
94
  language_pattern = "-*" if language is None else f"-{language}"
83
95
  glob_pattern += language_pattern
@@ -99,19 +111,17 @@ def clear(
99
111
  @click.option("-b", "--board", default=None, help="CircuitPython board name")
100
112
  def cache_list(board: Optional[str]) -> None:
101
113
  """List all the boards/versions cached."""
102
- if board is not None:
103
- board_name = board.replace(" ", "_").lower()
104
114
  board_list = os.listdir(circfirm.UF2_ARCHIVE)
105
115
 
106
116
  if not board_list:
107
117
  click.echo("Versions have not been cached yet for any boards.")
108
118
  sys.exit(0)
109
119
 
110
- if board is not None and board_name not in board_list:
111
- click.echo(f"No versions for board '{board_name}' are not cached.")
120
+ if board is not None and board not in board_list:
121
+ click.echo(f"No versions for board '{board}' are not cached.")
112
122
  sys.exit(0)
113
123
 
114
- specified_board = board_name if board is not None else None
124
+ specified_board = board if board is not None else None
115
125
  boards = circfirm.backend.get_sorted_boards(specified_board)
116
126
 
117
127
  for rec_boardname, rec_boardvers in boards.items():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: circfirm
3
- Version: 1.0.1
3
+ Version: 2.0.1
4
4
  Summary: CLI tool for install firmware for CircuitPython boards
5
5
  Author-email: Alec Delaney <tekktrik@gmail.com>
6
6
  License: MIT
@@ -0,0 +1,3 @@
1
+ Adafruit CircuitPython 8.0.0-beta.6 on 2022-12-21; Adafruit Feather M4 Express with samd51j19
2
+ Board ID:feather_m4_express
3
+ UID:C4391B2B0D942955
@@ -42,6 +42,12 @@ def get_mount_node(path: str, must_exist: bool = False) -> str:
42
42
  return node_location
43
43
 
44
44
 
45
+ def delete_mount_node(path: str, missing_okay: bool = False) -> None:
46
+ """Delete a file on the mounted druve."""
47
+ node_file = get_mount_node(path)
48
+ pathlib.Path(node_file).unlink(missing_ok=missing_okay)
49
+
50
+
45
51
  def touch_mount_node(path: str, exist_ok: bool = False) -> str:
46
52
  """Touch a file on the mounted drive."""
47
53
  node_location = get_mount_node(path)
@@ -50,17 +50,33 @@ def test_find_bootloader() -> None:
50
50
 
51
51
  def test_get_board_name() -> None:
52
52
  """Tests getting the board name from the UF2 info file."""
53
+ # Setup
54
+ tests.helpers.delete_mount_node(circfirm.UF2INFO_FILE)
55
+ tests.helpers.copy_boot_out()
56
+
57
+ # Test successful parsing
53
58
  mount_location = tests.helpers.get_mount()
54
59
  board_name = circfirm.backend.get_board_name(mount_location)
55
- assert board_name == "PyGamer"
60
+ assert board_name == "feather_m4_express"
61
+
62
+ # Test unsuccessful parsing
63
+ with open(
64
+ tests.helpers.get_mount_node(circfirm.BOOTOUT_FILE), mode="w", encoding="utf-8"
65
+ ) as bootfile:
66
+ bootfile.write("junktext")
67
+ with pytest.raises(ValueError):
68
+ circfirm.backend.get_board_name(mount_location)
69
+
70
+ # Clean up
71
+ tests.helpers.delete_mount_node(circfirm.BOOTOUT_FILE)
72
+ tests.helpers.copy_uf2_info()
56
73
 
57
74
 
58
75
  def test_get_board_folder() -> None:
59
76
  """Tests getting UF2 information."""
60
- board_name = "Feather M4 Express"
61
- formatted_board_name = board_name.replace(" ", "_").lower()
77
+ board_name = "feather_m4_express"
62
78
  board_path = circfirm.backend.get_board_folder(board_name)
63
- expected_path = pathlib.Path(circfirm.UF2_ARCHIVE) / formatted_board_name
79
+ expected_path = pathlib.Path(circfirm.UF2_ARCHIVE) / board_name
64
80
  assert board_path.resolve() == expected_path.resolve()
65
81
 
66
82
 
@@ -71,7 +87,7 @@ def test_get_uf2_filepath() -> None:
71
87
  version = "7.0.0"
72
88
 
73
89
  created_path = circfirm.backend.get_uf2_filepath(
74
- "Feather M4 Express", "7.0.0", "en_US", ensure=True
90
+ "feather_m4_express", "7.0.0", "en_US", ensure=True
75
91
  )
76
92
  expected_path = (
77
93
  pathlib.Path(circfirm.UF2_ARCHIVE)
@@ -83,16 +99,14 @@ def test_get_uf2_filepath() -> None:
83
99
 
84
100
  def test_download_uf2() -> None:
85
101
  """Tests the UF2 download functionality."""
86
- board_name = "Feather M4 Express"
102
+ board_name = "feather_m4_express"
87
103
  language = "en_US"
88
104
  version = "junktext"
89
105
 
90
- formatted_board_name = board_name.replace(" ", "_").lower()
91
-
92
106
  # Test bad download candidate
93
107
  expected_path = (
94
108
  circfirm.backend.get_board_folder(board_name)
95
- / f"adafruit-circuitpython-{formatted_board_name}-{language}-{version}.uf2"
109
+ / f"adafruit-circuitpython-{board_name}-{language}-{version}.uf2"
96
110
  )
97
111
  with pytest.raises(ConnectionError):
98
112
  circfirm.backend.download_uf2(board_name, version, language)
@@ -105,7 +119,7 @@ def test_download_uf2() -> None:
105
119
  circfirm.backend.download_uf2(board_name, version, language)
106
120
  expected_path = (
107
121
  circfirm.backend.get_board_folder(board_name)
108
- / f"adafruit-circuitpython-{formatted_board_name}-{language}-{version}.uf2"
122
+ / f"adafruit-circuitpython-{board_name}-{language}-{version}.uf2"
109
123
  )
110
124
  assert expected_path.exists()
111
125
  assert circfirm.backend.is_downloaded(board_name, version)
@@ -116,9 +130,10 @@ def test_download_uf2() -> None:
116
130
 
117
131
  def test_get_firmware_info() -> None:
118
132
  """Tests the ability to get firmware information."""
119
- board_name = "Feather M4 Express"
133
+ board_name = "feather_m4_express"
120
134
  language = "en_US"
121
135
 
136
+ # Test successful parsing
122
137
  for version in ("8.0.0", "9.0.0-beta.2"):
123
138
  try:
124
139
  board_folder = circfirm.backend.get_board_folder(board_name)
@@ -133,3 +148,7 @@ def test_get_firmware_info() -> None:
133
148
  finally:
134
149
  # Clean up post tests
135
150
  shutil.rmtree(board_folder)
151
+
152
+ # Test failed parsing
153
+ with pytest.raises(ValueError):
154
+ circfirm.backend.get_firmware_info("cannotparse")
@@ -10,6 +10,8 @@ Author(s): Alec Delaney
10
10
  import os
11
11
  import pathlib
12
12
  import shutil
13
+ import threading
14
+ import time
13
15
 
14
16
  from click.testing import CliRunner
15
17
 
@@ -20,36 +22,55 @@ from circfirm.cli import cli
20
22
 
21
23
  def test_install() -> None:
22
24
  """Tests the install command."""
23
- version = "7.0.0"
25
+
26
+ def wait_and_add() -> None:
27
+ """Wait then add the boot_out.txt file."""
28
+ time.sleep(2)
29
+ tests.helpers.delete_mount_node(circfirm.BOOTOUT_FILE)
30
+ tests.helpers.copy_uf2_info()
31
+
32
+ version = "8.0.0-beta.6"
24
33
  runner = CliRunner()
25
34
 
26
35
  # Test successfully installing the firmware
36
+ tests.helpers.delete_mount_node(circfirm.UF2INFO_FILE)
37
+ tests.helpers.copy_boot_out()
38
+ threading.Thread(target=wait_and_add).start()
27
39
  result = runner.invoke(cli, ["install", version])
28
40
  assert result.exit_code == 0
29
- expected_uf2_filename = circfirm.backend.get_uf2_filename("PyGamer", version)
41
+ expected_uf2_filename = circfirm.backend.get_uf2_filename(
42
+ "feather_m4_express", version
43
+ )
30
44
  expected_uf2_filepath = tests.helpers.get_mount_node(expected_uf2_filename)
31
45
  assert os.path.exists(expected_uf2_filepath)
32
46
  os.remove(expected_uf2_filepath)
33
47
 
34
48
  ERR_NOT_FOUND = 1
35
49
  ERR_FOUND_CIRCUITPY = 2
50
+ ERR_IN_BOOTLOADER = 3
36
51
  try:
37
52
  # Test not finding the mounted drive
38
- uf2_info = tests.helpers.get_mount_node(circfirm.UF2INFO_FILE)
39
- os.remove(uf2_info)
40
- result = runner.invoke(cli, ["install", version])
53
+ tests.helpers.delete_mount_node(circfirm.UF2INFO_FILE)
54
+ result = runner.invoke(
55
+ cli, ["install", version, "--board", "feather_m4_express"]
56
+ )
41
57
  assert result.exit_code == ERR_NOT_FOUND
42
58
 
43
59
  # Test finding the mounted drive as CIRCUITPY
44
60
  tests.helpers.copy_boot_out()
45
- result = runner.invoke(cli, ["install", version])
61
+ result = runner.invoke(
62
+ cli, ["install", version, "--board", "feather_m4_express"]
63
+ )
46
64
  assert result.exit_code == ERR_FOUND_CIRCUITPY
47
- bootout = tests.helpers.get_mount_node(circfirm.BOOTOUT_FILE)
48
- os.remove(bootout)
65
+ tests.helpers.delete_mount_node(circfirm.BOOTOUT_FILE)
49
66
  finally:
50
67
  tests.helpers.copy_uf2_info()
51
68
 
52
- board_folder = circfirm.backend.get_board_folder("pygamer")
69
+ # Test using install when in bootloader mode
70
+ result = runner.invoke(cli, ["install", version])
71
+ assert result.exit_code == ERR_IN_BOOTLOADER
72
+
73
+ board_folder = circfirm.backend.get_board_folder("feather_m4_express")
53
74
  shutil.rmtree(board_folder)
54
75
 
55
76
 
@@ -77,24 +98,19 @@ def test_cache_list() -> None:
77
98
  "tests/assets/responses/specific_board.txt", encoding="utf-8"
78
99
  ) as respfile:
79
100
  expected_response = respfile.read()
80
- result = runner.invoke(cli, ["cache", "list", "--board", "Feather M4 Express"])
81
- print(result.output)
101
+ result = runner.invoke(cli, ["cache", "list", "--board", "feather_m4_express"])
82
102
  assert result.exit_code == 0
83
103
  assert result.output == expected_response
84
104
 
85
105
  # Test specific board, version, and language response
86
- fake_board = "Does Not Exist"
87
- fake_board_name = fake_board.replace(" ", "_").lower()
106
+ fake_board = "does_not_exist"
88
107
  with open(
89
108
  "tests/assets/responses/specific_board.txt", encoding="utf-8"
90
109
  ) as respfile:
91
110
  expected_response = respfile.read()
92
111
  result = runner.invoke(cli, ["cache", "list", "--board", fake_board])
93
- print(result.output)
94
112
  assert result.exit_code == 0
95
- assert (
96
- result.output == f"No versions for board '{fake_board_name}' are not cached.\n"
97
- )
113
+ assert result.output == f"No versions for board '{fake_board}' are not cached.\n"
98
114
 
99
115
  # Clean Up after test
100
116
  shutil.rmtree(circfirm.UF2_ARCHIVE)
@@ -103,7 +119,7 @@ def test_cache_list() -> None:
103
119
 
104
120
  def test_cache_save() -> None:
105
121
  """Tests the cache save command."""
106
- board = "Feather M4 Express"
122
+ board = "feather_m4_express"
107
123
  version = "7.3.0"
108
124
  langauge = "fr"
109
125
  runner = CliRunner()
@@ -132,7 +148,7 @@ def test_cache_save() -> None:
132
148
 
133
149
  def test_cache_clear() -> None:
134
150
  """Tests the cache clear command."""
135
- board = "Feather M4 Express"
151
+ board = "feather_m4_express"
136
152
  version = "7.1.0"
137
153
  langauge = "zh_Latn_pinyin"
138
154
  runner = CliRunner()
@@ -154,7 +170,7 @@ def test_cache_clear() -> None:
154
170
  langauge,
155
171
  ],
156
172
  )
157
- board_folder = pathlib.Path(circfirm.UF2_ARCHIVE) / board.replace(" ", "_").lower()
173
+ board_folder = pathlib.Path(circfirm.UF2_ARCHIVE) / board
158
174
  uf2_file = (
159
175
  board_folder
160
176
  / "adafruit-circuitpython-feather_m4_express-zh_Latn_pinyin-7.1.0.uf2"
circfirm-1.0.1/VERSION DELETED
@@ -1 +0,0 @@
1
- 1.0.1
@@ -1,3 +0,0 @@
1
- Adafruit CircuitPython 8.2.9 on 2023-12-06; Adafruit Feather STM32F405 Express with STM32F405RG
2
- Board ID:feather_stm32f405_express
3
- UID:250026001050304235343220
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes