circfirm 4.0.0__tar.gz → 4.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 (121) hide show
  1. {circfirm-4.0.0 → circfirm-4.0.1}/PKG-INFO +3 -2
  2. circfirm-4.0.1/VERSION +1 -0
  3. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/backend/cache.py +0 -1
  4. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/backend/s3.py +0 -1
  5. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/cli/cache.py +5 -0
  6. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/cli/query.py +24 -5
  7. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/cli/update.py +5 -2
  8. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm.egg-info/PKG-INFO +3 -2
  9. {circfirm-4.0.0 → circfirm-4.0.1}/tests/backend/test_backend.py +1 -0
  10. {circfirm-4.0.0 → circfirm-4.0.1}/tests/backend/test_backend_device.py +5 -10
  11. {circfirm-4.0.0 → circfirm-4.0.1}/tests/cli/test_cli_cache.py +33 -19
  12. {circfirm-4.0.0 → circfirm-4.0.1}/tests/cli/test_cli_current.py +2 -5
  13. {circfirm-4.0.0 → circfirm-4.0.1}/tests/cli/test_cli_detect.py +4 -8
  14. {circfirm-4.0.0 → circfirm-4.0.1}/tests/cli/test_cli_install.py +14 -15
  15. {circfirm-4.0.0 → circfirm-4.0.1}/tests/cli/test_cli_query.py +77 -20
  16. {circfirm-4.0.0 → circfirm-4.0.1}/tests/cli/test_cli_update.py +40 -22
  17. circfirm-4.0.1/tests/conftest.py +169 -0
  18. circfirm-4.0.1/tests/helpers.py +96 -0
  19. {circfirm-4.0.0 → circfirm-4.0.1}/tests/test_startup.py +0 -1
  20. circfirm-4.0.0/VERSION +0 -1
  21. circfirm-4.0.0/tests/conftest.py +0 -53
  22. circfirm-4.0.0/tests/helpers.py +0 -191
  23. {circfirm-4.0.0 → circfirm-4.0.1}/.github/workflows/codeql.yml +0 -0
  24. {circfirm-4.0.0 → circfirm-4.0.1}/.github/workflows/publish.yml +0 -0
  25. {circfirm-4.0.0 → circfirm-4.0.1}/.github/workflows/push.yml +0 -0
  26. {circfirm-4.0.0 → circfirm-4.0.1}/.gitignore +0 -0
  27. {circfirm-4.0.0 → circfirm-4.0.1}/.pre-commit-config.yaml +0 -0
  28. {circfirm-4.0.0 → circfirm-4.0.1}/.readthedocs.yaml +0 -0
  29. {circfirm-4.0.0 → circfirm-4.0.1}/.reuse/dep5 +0 -0
  30. {circfirm-4.0.0 → circfirm-4.0.1}/LICENSE +0 -0
  31. {circfirm-4.0.0 → circfirm-4.0.1}/LICENSES/MIT.txt +0 -0
  32. {circfirm-4.0.0 → circfirm-4.0.1}/LICENSES/Unlicense.txt +0 -0
  33. {circfirm-4.0.0 → circfirm-4.0.1}/Makefile +0 -0
  34. {circfirm-4.0.0 → circfirm-4.0.1}/NOTICE +0 -0
  35. {circfirm-4.0.0 → circfirm-4.0.1}/NOTICE.license +0 -0
  36. {circfirm-4.0.0 → circfirm-4.0.1}/README.rst +0 -0
  37. {circfirm-4.0.0 → circfirm-4.0.1}/VERSION.license +0 -0
  38. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/__init__.py +0 -0
  39. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/backend/__init__.py +0 -0
  40. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/backend/device.py +0 -0
  41. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/backend/github.py +0 -0
  42. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/cli/__init__.py +0 -0
  43. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/cli/about.py +0 -0
  44. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/cli/config.py +0 -0
  45. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/cli/current.py +0 -0
  46. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/cli/detect.py +0 -0
  47. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/cli/install.py +0 -0
  48. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/py.typed +0 -0
  49. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/startup.py +0 -0
  50. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/templates/settings.yaml +0 -0
  51. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm/templates/settings.yaml.license +0 -0
  52. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm.egg-info/SOURCES.txt +0 -0
  53. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm.egg-info/dependency_links.txt +0 -0
  54. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm.egg-info/entry_points.txt +0 -0
  55. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm.egg-info/requires.txt +0 -0
  56. {circfirm-4.0.0 → circfirm-4.0.1}/circfirm.egg-info/top_level.txt +0 -0
  57. {circfirm-4.0.0 → circfirm-4.0.1}/docs/commands/cache.rst +0 -0
  58. {circfirm-4.0.0 → circfirm-4.0.1}/docs/commands/config.rst +0 -0
  59. {circfirm-4.0.0 → circfirm-4.0.1}/docs/commands/current.rst +0 -0
  60. {circfirm-4.0.0 → circfirm-4.0.1}/docs/commands/detect.rst +0 -0
  61. {circfirm-4.0.0 → circfirm-4.0.1}/docs/commands/install.rst +0 -0
  62. {circfirm-4.0.0 → circfirm-4.0.1}/docs/commands/query.rst +0 -0
  63. {circfirm-4.0.0 → circfirm-4.0.1}/docs/commands/update.rst +0 -0
  64. {circfirm-4.0.0 → circfirm-4.0.1}/docs/conf.py +0 -0
  65. {circfirm-4.0.0 → circfirm-4.0.1}/docs/examples/update_many.rst +0 -0
  66. {circfirm-4.0.0 → circfirm-4.0.1}/docs/examples/weekly_cache.rst +0 -0
  67. {circfirm-4.0.0 → circfirm-4.0.1}/docs/index.rst +0 -0
  68. {circfirm-4.0.0 → circfirm-4.0.1}/docs/index.rst.license +0 -0
  69. {circfirm-4.0.0 → circfirm-4.0.1}/docs/infrastructure/ci.rst +0 -0
  70. {circfirm-4.0.0 → circfirm-4.0.1}/docs/infrastructure/codecheck.rst +0 -0
  71. {circfirm-4.0.0 → circfirm-4.0.1}/docs/infrastructure/docs.rst +0 -0
  72. {circfirm-4.0.0 → circfirm-4.0.1}/docs/infrastructure/license.rst +0 -0
  73. {circfirm-4.0.0 → circfirm-4.0.1}/docs/infrastructure/notice.rst +0 -0
  74. {circfirm-4.0.0 → circfirm-4.0.1}/docs/infrastructure/tests.rst +0 -0
  75. {circfirm-4.0.0 → circfirm-4.0.1}/examples/bash/update_many.sh +0 -0
  76. {circfirm-4.0.0 → circfirm-4.0.1}/examples/bash/weekly_cache.sh +0 -0
  77. {circfirm-4.0.0 → circfirm-4.0.1}/examples/powershell/update_many.ps1 +0 -0
  78. {circfirm-4.0.0 → circfirm-4.0.1}/examples/powershell/weekly_cache.ps1 +0 -0
  79. {circfirm-4.0.0 → circfirm-4.0.1}/pyproject.toml +0 -0
  80. {circfirm-4.0.0 → circfirm-4.0.1}/requirements-dev.txt +0 -0
  81. {circfirm-4.0.0 → circfirm-4.0.1}/requirements.txt +0 -0
  82. {circfirm-4.0.0 → circfirm-4.0.1}/scripts/rmdir.py +0 -0
  83. {circfirm-4.0.0 → circfirm-4.0.1}/setup.cfg +0 -0
  84. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/boot_out.txt +0 -0
  85. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-en_US-7.0.0.uf2 +0 -0
  86. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-en_US-7.1.0.uf2 +0 -0
  87. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-en_US-7.2.0.uf2 +0 -0
  88. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-fr-7.0.0.uf2 +0 -0
  89. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-fr-7.1.0.uf2 +0 -0
  90. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-fr-7.2.0.uf2 +0 -0
  91. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-zh_Latn_pinyin-7.0.0.uf2 +0 -0
  92. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-zh_Latn_pinyin-7.1.0.uf2 +0 -0
  93. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m0_express/adafruit-circuitpython-feather_m0_express-zh_Latn_pinyin-7.2.0.uf2 +0 -0
  94. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-en_US-7.0.0.uf2 +0 -0
  95. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-en_US-7.1.0.uf2 +0 -0
  96. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-en_US-7.2.0.uf2 +0 -0
  97. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-fr-7.0.0.uf2 +0 -0
  98. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-fr-7.1.0.uf2 +0 -0
  99. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-fr-7.2.0.uf2 +0 -0
  100. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-zh_Latn_pinyin-7.0.0.uf2 +0 -0
  101. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-zh_Latn_pinyin-7.1.0.uf2 +0 -0
  102. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/feather_m4_express/adafruit-circuitpython-feather_m4_express-zh_Latn_pinyin-7.2.0.uf2 +0 -0
  103. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-en_US-7.0.0.uf2 +0 -0
  104. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-en_US-7.1.0.uf2 +0 -0
  105. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-en_US-7.2.0.uf2 +0 -0
  106. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-fr-7.0.0.uf2 +0 -0
  107. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-fr-7.1.0.uf2 +0 -0
  108. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-fr-7.2.0.uf2 +0 -0
  109. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-zh_Latn_pinyin-7.0.0.uf2 +0 -0
  110. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-zh_Latn_pinyin-7.1.0.uf2 +0 -0
  111. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/firmwares/pygamer/adafruit-circuitpython-pygamer-zh_Latn_pinyin-7.2.0.uf2 +0 -0
  112. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/info_uf2.txt +0 -0
  113. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/responses/full_list.txt +0 -0
  114. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/responses/full_list.txt.license +0 -0
  115. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/responses/specific_board.txt +0 -0
  116. {circfirm-4.0.0 → circfirm-4.0.1}/tests/assets/responses/specific_board.txt.license +0 -0
  117. {circfirm-4.0.0 → circfirm-4.0.1}/tests/backend/test_backend_cache.py +0 -0
  118. {circfirm-4.0.0 → circfirm-4.0.1}/tests/backend/test_backend_github.py +0 -0
  119. {circfirm-4.0.0 → circfirm-4.0.1}/tests/backend/test_backend_s3.py +0 -0
  120. {circfirm-4.0.0 → circfirm-4.0.1}/tests/cli/test_cli_about.py +0 -0
  121. {circfirm-4.0.0 → circfirm-4.0.1}/tests/cli/test_cli_config.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: circfirm
3
- Version: 4.0.0
3
+ Version: 4.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
@@ -46,6 +46,7 @@ Requires-Dist: pytest~=8.3; extra == "dev"
46
46
  Requires-Dist: sphinx~=7.4; extra == "dev"
47
47
  Requires-Dist: sphinx-tabs~=3.4; extra == "dev"
48
48
  Requires-Dist: sphinx-rtd-theme~=3.0; extra == "dev"
49
+ Dynamic: license-file
49
50
 
50
51
  ..
51
52
  SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries
circfirm-4.0.1/VERSION ADDED
@@ -0,0 +1 @@
1
+ 4.0.1
@@ -15,7 +15,6 @@ import packaging.version
15
15
  import requests
16
16
 
17
17
  import circfirm.backend
18
- import circfirm.startup
19
18
 
20
19
 
21
20
  def get_uf2_filepath(
@@ -17,7 +17,6 @@ import packaging.version
17
17
  from mypy_boto3_s3 import S3ServiceResource
18
18
 
19
19
  import circfirm.backend
20
- import circfirm.backend.cache
21
20
 
22
21
  S3_CONFIG = botocore.client.Config(signature_version=botocore.UNSIGNED)
23
22
  S3_RESOURCE: S3ServiceResource = boto3.resource("s3", config=S3_CONFIG)
@@ -13,6 +13,7 @@ import re
13
13
  import shutil
14
14
  from typing import Optional
15
15
 
16
+ import botocore.exceptions
16
17
  import click
17
18
 
18
19
  import circfirm
@@ -153,3 +154,7 @@ def cache_latest(board_id: str, language: str, pre_release: bool) -> None:
153
154
  )
154
155
  except ConnectionError as err:
155
156
  raise click.exceptions.ClickException(err.args[0])
157
+ except botocore.exceptions.ConnectionError:
158
+ raise click.exceptions.ClickException(
159
+ "Could not connect to the S3 bucket - check network connection"
160
+ )
@@ -9,6 +9,7 @@ Author(s): Alec Delaney
9
9
 
10
10
  import re
11
11
 
12
+ import botocore.exceptions
12
13
  import click
13
14
  import requests
14
15
 
@@ -51,12 +52,18 @@ def query_board_ids(regex: str) -> None:
51
52
  except ValueError as err:
52
53
  raise click.ClickException(err.args[0])
53
54
  except requests.ConnectionError as err:
55
+ print("Triggered!")
54
56
  raise click.ClickException(
55
57
  "Issue with requesting information from git repository, check network connection"
56
58
  )
57
59
  for board in boards:
58
60
  board_id = board.strip()
59
- result = re.search(regex, board_id)
61
+ try:
62
+ result = re.search(regex, board_id)
63
+ except re.PatternError:
64
+ raise click.exceptions.ClickException(
65
+ "Regex pattern error - please check the regex syntax"
66
+ )
60
67
  if result:
61
68
  click.echo(board_id)
62
69
 
@@ -69,7 +76,16 @@ def query_board_ids(regex: str) -> None:
69
76
  )
70
77
  def query_versions(board_id: str, language: str, regex: str) -> None:
71
78
  """Query the CircuitPython versions available for a board."""
72
- versions = circfirm.backend.s3.get_board_versions(board_id, language, regex=regex)
79
+ try:
80
+ versions = circfirm.backend.s3.get_board_versions(
81
+ board_id, language, regex=regex
82
+ )
83
+ except botocore.exceptions.ConnectionError as err:
84
+ raise click.exceptions.ClickException(err.args[0])
85
+ except re.PatternError:
86
+ raise click.exceptions.ClickException(
87
+ "Regex pattern error - please check the regex syntax"
88
+ )
73
89
  for version in reversed(versions):
74
90
  click.echo(version)
75
91
 
@@ -86,8 +102,11 @@ def query_versions(board_id: str, language: str, regex: str) -> None:
86
102
  )
87
103
  def query_latest(board_id: str, language: str, pre_release: bool) -> None:
88
104
  """Query the latest CircuitPython versions available."""
89
- version = circfirm.backend.s3.get_latest_board_version(
90
- board_id, language, pre_release
91
- )
105
+ try:
106
+ version = circfirm.backend.s3.get_latest_board_version(
107
+ board_id, language, pre_release
108
+ )
109
+ except botocore.exceptions.ConnectionError as err:
110
+ raise click.exceptions.ClickException(err.args[0])
92
111
  if version:
93
112
  click.echo(version)
@@ -9,12 +9,12 @@ Author(s): Alec Delaney
9
9
 
10
10
  from typing import Optional
11
11
 
12
+ import botocore.exceptions
12
13
  import click
13
14
  import packaging.version
14
15
 
15
16
  import circfirm.backend.device
16
17
  import circfirm.backend.s3
17
- import circfirm.cli.install
18
18
 
19
19
 
20
20
  @click.command()
@@ -79,7 +79,10 @@ def cli( # noqa: PLR0913
79
79
  except OSError as err:
80
80
  raise click.ClickException(err.args[0])
81
81
 
82
- new_versions = circfirm.backend.s3.get_board_versions(board_id, language)
82
+ try:
83
+ new_versions = circfirm.backend.s3.get_board_versions(board_id, language)
84
+ except botocore.exceptions.ConnectionError as err:
85
+ raise click.exceptions.ClickException(err.args[0])
83
86
 
84
87
  if not pre_release:
85
88
  new_versions = [
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: circfirm
3
- Version: 4.0.0
3
+ Version: 4.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
@@ -46,6 +46,7 @@ Requires-Dist: pytest~=8.3; extra == "dev"
46
46
  Requires-Dist: sphinx~=7.4; extra == "dev"
47
47
  Requires-Dist: sphinx-tabs~=3.4; extra == "dev"
48
48
  Requires-Dist: sphinx-rtd-theme~=3.0; extra == "dev"
49
+ Dynamic: license-file
49
50
 
50
51
  ..
51
52
  SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries
@@ -14,6 +14,7 @@ import pytest
14
14
  import circfirm.backend.cache
15
15
 
16
16
 
17
+ # TODO: Parameterize?
17
18
  def test_parse_firmware_info() -> None:
18
19
  """Tests the ability to get firmware information."""
19
20
  board_id = "feather_m4_express"
@@ -13,39 +13,34 @@ import circfirm.backend.device
13
13
  import tests.helpers
14
14
 
15
15
 
16
- @tests.helpers.as_circuitpy
17
- def test_find_circuitpy() -> None:
16
+ def test_find_circuitpy(mock_with_circuitpy: None) -> None:
18
17
  """Tests finding a CircuitPython device when boot_out.txt is present."""
19
18
  mount_location = tests.helpers.get_mount()
20
19
  circuitpy = circfirm.backend.device.find_circuitpy()
21
20
  assert circuitpy == mount_location
22
21
 
23
22
 
24
- @tests.helpers.as_not_present
25
- def test_find_circuitpy_absent() -> None:
23
+ def test_find_circuitpy_absent(mock_with_no_device: None) -> None:
26
24
  """Tests finding a CircuitPython device when boot_out.txt is absent."""
27
25
  circuitpy = circfirm.backend.device.find_circuitpy()
28
26
  assert circuitpy is None
29
27
 
30
28
 
31
- @tests.helpers.as_bootloader
32
- def test_find_bootloader() -> None:
29
+ def test_find_bootloader(mock_with_bootloader: None) -> None:
33
30
  """Tests finding a CircuitPython device in bootloader mode when info_uf2.txt is present."""
34
31
  mount_location = tests.helpers.get_mount()
35
32
  bootloader = circfirm.backend.device.find_bootloader()
36
33
  assert bootloader == mount_location
37
34
 
38
35
 
39
- @tests.helpers.as_not_present
40
- def test_find_bootloader_absent() -> None:
36
+ def test_find_bootloader_absent(mock_with_no_device: None) -> None:
41
37
  """Tests finding a CircuitPython device in bootloader mode when info_uf2.txt is absent."""
42
38
  bootloader = circfirm.backend.device.find_bootloader()
43
39
  assert bootloader is None
44
40
  tests.helpers.copy_uf2_info()
45
41
 
46
42
 
47
- @tests.helpers.as_circuitpy
48
- def test_get_board_info() -> None:
43
+ def test_get_board_info(mock_with_circuitpy: None) -> None:
49
44
  """Tests getting the board ID and firmware version from the UF2 info file."""
50
45
  # Test successful parsing
51
46
  mount_location = tests.helpers.get_mount()
@@ -10,12 +10,12 @@ Author(s): Alec Delaney
10
10
  import os
11
11
  import pathlib
12
12
  import shutil
13
+ from typing import NoReturn
13
14
 
14
15
  from click.testing import CliRunner
15
16
 
16
17
  import circfirm
17
18
  import circfirm.backend.cache
18
- import tests.helpers
19
19
  from circfirm.cli import cli
20
20
 
21
21
  RUNNER = CliRunner()
@@ -28,8 +28,7 @@ def test_cache_list_empty() -> None:
28
28
  assert result.output == "Versions have not been cached yet for any boards.\n"
29
29
 
30
30
 
31
- @tests.helpers.with_firmwares
32
- def test_cache_list_all() -> None:
31
+ def test_cache_list_all(mock_with_firmwares_archived: None) -> None:
33
32
  """Tests the cache list command with an non-empty cache."""
34
33
  with open("tests/assets/responses/full_list.txt", encoding="utf-8") as respfile:
35
34
  expected_response = respfile.read()
@@ -38,8 +37,7 @@ def test_cache_list_all() -> None:
38
37
  assert result.output == expected_response
39
38
 
40
39
 
41
- @tests.helpers.with_firmwares
42
- def test_cache_list_specific_board_found() -> None:
40
+ def test_cache_list_specific_board_found(mock_with_firmwares_archived: None) -> None:
43
41
  """Tests the cache list command with an non-empty cache for a specific board."""
44
42
  with open(
45
43
  "tests/assets/responses/specific_board.txt", encoding="utf-8"
@@ -50,8 +48,7 @@ def test_cache_list_specific_board_found() -> None:
50
48
  assert result.output == expected_response
51
49
 
52
50
 
53
- @tests.helpers.with_firmwares
54
- def test_cache_list_none_found() -> None:
51
+ def test_cache_list_none_found(mock_with_firmwares_archived: None) -> None:
55
52
  """Tests the cache list command with an non-empty cache and no matches."""
56
53
  fake_board = "does_not_exist"
57
54
 
@@ -92,8 +89,7 @@ def test_cache_save() -> None:
92
89
  )
93
90
 
94
91
 
95
- @tests.helpers.with_firmwares
96
- def test_cache_clear() -> None:
92
+ def test_cache_clear(mock_with_firmwares_archived: None) -> None:
97
93
  """Tests the cache clear command."""
98
94
  board = "feather_m4_express"
99
95
  version = "7.1.0"
@@ -136,8 +132,7 @@ def test_cache_clear() -> None:
136
132
  assert len(list(board_folder.parent.glob("*"))) == 0
137
133
 
138
134
 
139
- @tests.helpers.with_firmwares
140
- def test_cache_clear_regex_board_id() -> None:
135
+ def test_cache_clear_regex_board_id(mock_with_firmwares_archived: None) -> None:
141
136
  """Tests the cache clear command when using a regex flag for board ID."""
142
137
  board = "feather_m4_express"
143
138
  board_regex = "m4"
@@ -160,8 +155,7 @@ def test_cache_clear_regex_board_id() -> None:
160
155
  assert not board_folder.exists()
161
156
 
162
157
 
163
- @tests.helpers.with_firmwares
164
- def test_cache_clear_regex_version() -> None:
158
+ def test_cache_clear_regex_version(mock_with_firmwares_archived: None) -> None:
165
159
  """Tests the cache clear command when using a regex flag for version."""
166
160
  version = "7.1.0"
167
161
  version_regex = r".\.1"
@@ -184,8 +178,7 @@ def test_cache_clear_regex_version() -> None:
184
178
  assert not list(board_folder.glob(f"*{version}*"))
185
179
 
186
180
 
187
- @tests.helpers.with_firmwares
188
- def test_cache_clear_regex_language() -> None:
181
+ def test_cache_clear_regex_language(mock_with_firmwares_archived: None) -> None:
189
182
  """Tests the cache clear command when using a regex flag for language."""
190
183
  language = "zh_Latn_pinyin"
191
184
  language_regex = ".*Latn"
@@ -208,8 +201,7 @@ def test_cache_clear_regex_language() -> None:
208
201
  assert not list(board_folder.glob(f"*{language}*"))
209
202
 
210
203
 
211
- @tests.helpers.with_firmwares
212
- def test_cache_clear_regex_combination() -> None:
204
+ def test_cache_clear_regex_combination(mock_with_firmwares_archived: None) -> None:
213
205
  """Tests the cache clear command when using a regex flag for language."""
214
206
  board_regex = "feather"
215
207
  version = "7.2.0"
@@ -270,13 +262,35 @@ def test_cache_latest() -> None:
270
262
  assert result.exit_code == 0
271
263
  assert os.path.exists(uf2_filepath)
272
264
 
273
- # Save the latest version (unsuccessful)
265
+ # Save the latest version (unsuccessful, does not exist)
274
266
  result = RUNNER.invoke(
275
267
  cli, ["cache", "latest", board, "--language", "doesnotexist"]
276
268
  )
277
- assert result.exit_code == 1
269
+ assert result.exit_code != 0
278
270
 
279
271
  finally:
280
272
  board_folder = circfirm.backend.cache.get_board_folder(board)
281
273
  if board_folder.exists():
282
274
  shutil.rmtree(board_folder)
275
+
276
+
277
+ def test_cache_latest_no_internet(mock_s3_no_internet: NoReturn) -> None:
278
+ """Test the update command when in CIRCUITPY mode when there is no internet connection."""
279
+ board = "feather_m0_express"
280
+ language = "cs"
281
+ expected_version = "6.1.0"
282
+
283
+ uf2_filepath = circfirm.backend.cache.get_uf2_filepath(
284
+ board, expected_version, language
285
+ )
286
+ assert not os.path.exists(uf2_filepath)
287
+
288
+ try:
289
+ # Save the latest version (unsuccessful, no internet connection)
290
+ result = RUNNER.invoke(cli, ["cache", "latest", board, "--language", language])
291
+ assert result.exit_code != 0
292
+
293
+ finally:
294
+ board_folder = circfirm.backend.cache.get_board_folder(board)
295
+ if board_folder.exists(): # pragma: no cover
296
+ shutil.rmtree(board_folder)
@@ -9,14 +9,12 @@ Author(s): Alec Delaney
9
9
 
10
10
  from click.testing import CliRunner
11
11
 
12
- import tests.helpers
13
12
  from circfirm.cli import cli
14
13
 
15
14
  RUNNER = CliRunner()
16
15
 
17
16
 
18
- @tests.helpers.as_circuitpy
19
- def test_current() -> None:
17
+ def test_current(mock_with_circuitpy: None) -> None:
20
18
  """Tests the current name and version commands."""
21
19
  # Test when connected in CIRCUITPY mode
22
20
  result = RUNNER.invoke(cli, ["current", "board-id"])
@@ -28,8 +26,7 @@ def test_current() -> None:
28
26
  assert result.output == "8.0.0-beta.6\n"
29
27
 
30
28
 
31
- @tests.helpers.as_bootloader
32
- def test_current_in_bootloader() -> None:
29
+ def test_current_in_bootloader(mock_with_bootloader: None) -> None:
33
30
  """Tests the current command whenn connected in bootloader mode."""
34
31
  result = RUNNER.invoke(cli, ["current", "board-id"])
35
32
  assert result.exit_code != 0
@@ -17,8 +17,7 @@ from circfirm.cli import cli
17
17
  RUNNER = CliRunner()
18
18
 
19
19
 
20
- @tests.helpers.as_circuitpy
21
- def test_detect_circuitpy_found() -> None:
20
+ def test_detect_circuitpy_found(mock_with_circuitpy: None) -> None:
22
21
  """Tests the ability of the detect circuitpy command to find a connected board."""
23
22
  result = RUNNER.invoke(cli, ["detect", "circuitpy"])
24
23
  assert result.exit_code == 0
@@ -28,15 +27,13 @@ def test_detect_circuitpy_found() -> None:
28
27
  assert circuitpy == mount
29
28
 
30
29
 
31
- @tests.helpers.as_not_present
32
- def test_detect_circuitpy_not_found() -> None:
30
+ def test_detect_circuitpy_not_found(mock_with_no_device: None) -> None:
33
31
  """Tests the detect circuitpy command without a connected board."""
34
32
  result = RUNNER.invoke(cli, ["detect", "circuitpy"])
35
33
  assert result.output == "No board connected in CIRCUITPY or equivalent mode\n"
36
34
 
37
35
 
38
- @tests.helpers.as_bootloader
39
- def test_detect_bootloader_found() -> None:
36
+ def test_detect_bootloader_found(mock_with_bootloader: None) -> None:
40
37
  """Tests the ability of the detect bootloader command to find a connected board."""
41
38
  import time
42
39
 
@@ -49,8 +46,7 @@ def test_detect_bootloader_found() -> None:
49
46
  assert bootloader == mount
50
47
 
51
48
 
52
- @tests.helpers.as_not_present
53
- def test_detect_bootloader_not_found() -> None:
49
+ def test_detect_bootloader_not_found(mock_with_no_device: None) -> None:
54
50
  """Tests the detect bootloader command without a connected board."""
55
51
  result = RUNNER.invoke(cli, ["detect", "bootloader"])
56
52
  assert result.output == "No board connected in bootloader mode\n"
@@ -9,7 +9,6 @@ Author(s): Alec Delaney
9
9
 
10
10
  import os
11
11
  import shutil
12
- import threading
13
12
  import time
14
13
 
15
14
  from click.testing import CliRunner
@@ -28,17 +27,19 @@ ERR_UF2_DOWNLOAD = 4
28
27
  VERSION = "8.0.0-beta.6"
29
28
 
30
29
 
31
- @tests.helpers.as_circuitpy
32
- def test_install_successful() -> None:
30
+ def test_install_successful(mock_with_circuitpy: None) -> None:
33
31
  """Tests the successful use of the install command."""
34
32
  try:
35
33
  # Test successfully installing the firmware
36
- threading.Thread(target=tests.helpers.wait_and_set_bootloader).start()
34
+ tests.helpers.start_bootloader_copy_thread()
35
+
37
36
  result = RUNNER.invoke(cli, ["install", VERSION])
37
+
38
38
  assert result.exit_code == 0
39
39
  expected_uf2_filename = circfirm.backend.get_uf2_filename(
40
40
  "feather_m4_express", VERSION
41
41
  )
42
+
42
43
  expected_uf2_filepath = tests.helpers.get_mount_node(expected_uf2_filename)
43
44
  assert os.path.exists(expected_uf2_filepath)
44
45
  os.remove(expected_uf2_filepath)
@@ -57,8 +58,7 @@ def test_install_successful() -> None:
57
58
  shutil.rmtree(board_folder)
58
59
 
59
60
 
60
- @tests.helpers.as_not_present
61
- def test_install_no_mount() -> None:
61
+ def test_install_no_mount(mock_with_no_device: None) -> None:
62
62
  """Tests the install command when a mounted drive is not found."""
63
63
  result = RUNNER.invoke(
64
64
  cli, ["install", VERSION, "--board-id", "feather_m4_express"]
@@ -66,8 +66,7 @@ def test_install_no_mount() -> None:
66
66
  assert result.exit_code == ERR_NOT_FOUND
67
67
 
68
68
 
69
- @tests.helpers.as_circuitpy
70
- def test_install_as_circuitpy() -> None:
69
+ def test_install_as_circuitpy(mock_with_circuitpy: None) -> None:
71
70
  """Tests the install command when a mounted CIRCUITPY drive is found."""
72
71
  result = RUNNER.invoke(
73
72
  cli, ["install", VERSION, "--board-id", "feather_m4_express"]
@@ -75,8 +74,7 @@ def test_install_as_circuitpy() -> None:
75
74
  assert result.exit_code == ERR_FOUND_CIRCUITPY
76
75
 
77
76
 
78
- @tests.helpers.as_bootloader
79
- def test_install_bad_version() -> None:
77
+ def test_install_bad_version(mock_with_bootloader: None) -> None:
80
78
  """Tests the install command using a bad board version."""
81
79
  result = RUNNER.invoke(
82
80
  cli, ["install", "doesnotexist", "--board-id", "feather_m4_express"]
@@ -88,16 +86,18 @@ def test_install_bad_version() -> None:
88
86
  assert result.exit_code == ERR_IN_BOOTLOADER
89
87
 
90
88
 
91
- @tests.helpers.as_circuitpy
92
- def test_install_with_timeout() -> None:
89
+ def test_install_with_timeout(mock_with_circuitpy: None) -> None:
93
90
  """Tests the install command using the timeout option."""
94
91
  try:
95
- threading.Thread(target=tests.helpers.wait_and_set_bootloader).start()
92
+ tests.helpers.start_bootloader_copy_thread()
93
+
96
94
  result = RUNNER.invoke(cli, ["install", VERSION, "--timeout", "60"])
95
+
97
96
  assert result.exit_code == 0
98
97
  expected_uf2_filename = circfirm.backend.get_uf2_filename(
99
98
  "feather_m4_express", VERSION
100
99
  )
100
+
101
101
  expected_uf2_filepath = tests.helpers.get_mount_node(expected_uf2_filename)
102
102
  assert os.path.exists(expected_uf2_filepath)
103
103
  os.remove(expected_uf2_filepath)
@@ -108,8 +108,7 @@ def test_install_with_timeout() -> None:
108
108
  shutil.rmtree(board_folder)
109
109
 
110
110
 
111
- @tests.helpers.as_circuitpy
112
- def test_install_with_timeout_failure() -> None:
111
+ def test_install_with_timeout_failure(mock_with_circuitpy: None) -> None:
113
112
  """Tests the install command using the timeout option that causes a failure."""
114
113
  timeout = 3
115
114
  start_time = time.time()
@@ -11,23 +11,15 @@ import os
11
11
  from typing import NoReturn
12
12
 
13
13
  import pytest
14
- import requests
15
14
  from click.testing import CliRunner
16
15
 
17
- import circfirm.backend.github
18
16
  import tests.helpers
19
17
  from circfirm.cli import cli
20
18
 
21
19
  RUNNER = CliRunner()
22
20
 
23
21
 
24
- def simulate_no_connection(arg: str) -> NoReturn:
25
- """Simulate a network error by raising requests.ConnectionError."""
26
- raise requests.ConnectionError
27
-
28
-
29
- @tests.helpers.with_token(os.environ["GH_TOKEN"])
30
- def test_query_board_ids() -> None:
22
+ def test_query_board_ids(token: None) -> None:
31
23
  """Tests the ability to query the boards using the CLI."""
32
24
  # Test an authenticated request with supporting text
33
25
  board_ids = tests.helpers.get_board_ids_from_git()
@@ -45,33 +37,52 @@ def test_query_board_ids() -> None:
45
37
  assert result.output == expected_output
46
38
 
47
39
  # Test an authenticated request without supporting text
40
+ preexisting = RUNNER.invoke(cli, ["config", "view", "output.supporting.silence"])
48
41
  assert result.exit_code == 0
42
+ preexisting = preexisting.output.strip()
43
+ assert preexisting in ("true", "false")
44
+
45
+ # Suppress supporting text
49
46
  result = RUNNER.invoke(cli, ["config", "edit", "output.supporting.silence", "true"])
50
47
  assert result.exit_code == 0
48
+
49
+ # Test command
51
50
  result = RUNNER.invoke(cli, ["query", "board-ids"])
52
51
  assert result.exit_code == 0
53
52
  assert result.output == pre_expected_output
54
53
 
54
+ # Reset the supporting text setting
55
+ result = RUNNER.invoke(
56
+ cli, ["config", "edit", "output.supporting.silence", preexisting]
57
+ )
58
+ assert result.exit_code == 0
59
+
60
+ # Check results of reset
61
+ final = RUNNER.invoke(cli, ["config", "view", "output.supporting.silence"])
62
+ assert result.exit_code == 0
63
+ final = final.output.strip()
64
+ assert final == preexisting
65
+
55
66
 
56
- @tests.helpers.with_token("badtoken")
57
- def test_query_board_ids_bad_token() -> None:
67
+ @pytest.mark.parametrize("token", ["badtoken"], indirect=True)
68
+ def test_query_board_ids_bad_token(token: None) -> None:
58
69
  """Test a request with a faulty token."""
59
70
  result = RUNNER.invoke(cli, ["query", "board-ids"])
60
71
  assert result.exit_code != 0
61
72
 
62
73
 
63
- @tests.helpers.with_token(os.environ["GH_TOKEN"], True)
64
- def test_query_board_ids_no_network(monkeypatch: pytest.MonkeyPatch) -> None:
74
+ def test_query_board_ids_no_internet(
75
+ token: None, mock_requests_no_internet: NoReturn
76
+ ) -> None:
65
77
  """Tests failure when cannot fetch results due to no network connection."""
66
- monkeypatch.setattr(
67
- circfirm.backend.github, "get_board_id_list", simulate_no_connection
68
- )
69
78
  result = RUNNER.invoke(cli, ["query", "board-ids"])
70
79
  assert result.exit_code != 0
71
- assert (
72
- result.output.split("\n")[-2]
73
- == "Error: Issue with requesting information from git repository, check network connection"
74
- )
80
+
81
+
82
+ def test_query_board_ids_bad_regex(token: None) -> None:
83
+ """Tests failure when a bad regex pattern is provided."""
84
+ result = RUNNER.invoke(cli, ["query", "board-ids", "--regex", "*badregex"])
85
+ assert result.exit_code != 0
75
86
 
76
87
 
77
88
  def test_query_versions() -> None:
@@ -115,6 +126,33 @@ def test_query_versions() -> None:
115
126
  assert result.output == "6.2.0-beta.1\n"
116
127
 
117
128
 
129
+ def test_query_versions_no_internet(mock_s3_no_internet: NoReturn) -> None:
130
+ """Tests the ability to query firmware versions using the CLI."""
131
+ board = "adafruit_feather_rp2040"
132
+ language = "cs"
133
+
134
+ result = RUNNER.invoke(
135
+ cli,
136
+ [
137
+ "query",
138
+ "versions",
139
+ board,
140
+ "--language",
141
+ language,
142
+ ],
143
+ )
144
+
145
+ assert result.exit_code != 0
146
+
147
+
148
+ def test_query_versions_bad_regex(token: None) -> None:
149
+ """Tests failure when a bad regex pattern is provided."""
150
+ result = RUNNER.invoke(
151
+ cli, ["query", "versions", "adafruit_feather_rp2040", "--regex", "*badregex"]
152
+ )
153
+ assert result.exit_code != 0
154
+
155
+
118
156
  def test_query_latest() -> None:
119
157
  """Tests the ability to query the latest version of the firmware using the CLI."""
120
158
  board = "adafruit_feather_rp2040"
@@ -142,3 +180,22 @@ def test_query_latest() -> None:
142
180
  )
143
181
  assert result.exit_code == 0
144
182
  assert result.output == expected_output
183
+
184
+
185
+ def test_query_latest_no_internet(mock_s3_no_internet: NoReturn) -> None:
186
+ """Tests the ability to query the latest version of the firmware using the CLI."""
187
+ board = "adafruit_feather_rp2040"
188
+ language = "cs"
189
+
190
+ # Test without pre-releases included
191
+ result = RUNNER.invoke(
192
+ cli,
193
+ [
194
+ "query",
195
+ "latest",
196
+ board,
197
+ "--language",
198
+ language,
199
+ ],
200
+ )
201
+ assert result.exit_code != 0