circup 1.6.1__tar.gz → 1.7.0__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 (80) hide show
  1. {circup-1.6.1 → circup-1.7.0}/.gitignore +2 -0
  2. {circup-1.6.1/circup.egg-info → circup-1.7.0}/PKG-INFO +6 -6
  3. circup-1.7.0/circup/__init__.py +26 -0
  4. {circup-1.6.1 → circup-1.7.0}/circup/backends.py +20 -3
  5. circup-1.7.0/circup/bundle.py +156 -0
  6. circup-1.7.0/circup/command_utils.py +562 -0
  7. circup-1.7.0/circup/commands.py +657 -0
  8. circup-1.7.0/circup/logging.py +33 -0
  9. circup-1.7.0/circup/module.py +209 -0
  10. {circup-1.6.1 → circup-1.7.0}/circup/shared.py +75 -1
  11. {circup-1.6.1 → circup-1.7.0/circup.egg-info}/PKG-INFO +6 -6
  12. {circup-1.6.1 → circup-1.7.0}/circup.egg-info/SOURCES.txt +9 -1
  13. {circup-1.6.1 → circup-1.7.0}/docs/conf.py +1 -1
  14. circup-1.7.0/optional_requirements.txt +4 -0
  15. circup-1.7.0/optional_requirements.txt.license +3 -0
  16. circup-1.7.0/requirements.txt +7 -0
  17. {circup-1.6.1 → circup-1.7.0}/tests/mock_device/boot_out.txt +1 -1
  18. circup-1.7.0/tests/mock_device/lib/adafruit_waveform/.gitkeep +0 -0
  19. {circup-1.6.1 → circup-1.7.0}/tests/test_circup.py +198 -197
  20. circup-1.6.1/circup/__init__.py +0 -1584
  21. circup-1.6.1/requirements.txt +0 -58
  22. {circup-1.6.1 → circup-1.7.0}/.github/ISSUE_TEMPLATE.md +0 -0
  23. {circup-1.6.1 → circup-1.7.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  24. {circup-1.6.1 → circup-1.7.0}/.github/workflows/build.yml +0 -0
  25. {circup-1.6.1 → circup-1.7.0}/.github/workflows/release.yml +0 -0
  26. {circup-1.6.1 → circup-1.7.0}/.isort.cfg +0 -0
  27. {circup-1.6.1 → circup-1.7.0}/.pre-commit-config.yaml +0 -0
  28. {circup-1.6.1 → circup-1.7.0}/.pylintrc +0 -0
  29. {circup-1.6.1 → circup-1.7.0}/CODE_OF_CONDUCT.rst +0 -0
  30. {circup-1.6.1 → circup-1.7.0}/CODE_OF_CONDUCT.rst.license +0 -0
  31. {circup-1.6.1 → circup-1.7.0}/CONTRIBUTING.rst +0 -0
  32. {circup-1.6.1 → circup-1.7.0}/CONTRIBUTING.rst.license +0 -0
  33. {circup-1.6.1 → circup-1.7.0}/LICENSE +0 -0
  34. {circup-1.6.1 → circup-1.7.0}/LICENSES/CC-BY-4.0.txt +0 -0
  35. {circup-1.6.1 → circup-1.7.0}/LICENSES/MIT.txt +0 -0
  36. {circup-1.6.1 → circup-1.7.0}/LICENSES/Unlicense.txt +0 -0
  37. {circup-1.6.1 → circup-1.7.0}/README.rst +0 -0
  38. {circup-1.6.1 → circup-1.7.0}/README.rst.license +0 -0
  39. {circup-1.6.1 → circup-1.7.0}/circup/config/bundle_config.json +0 -0
  40. {circup-1.6.1 → circup-1.7.0}/circup/config/bundle_config.json.license +0 -0
  41. {circup-1.6.1 → circup-1.7.0}/circup.egg-info/dependency_links.txt +0 -0
  42. {circup-1.6.1 → circup-1.7.0}/circup.egg-info/entry_points.txt +0 -0
  43. {circup-1.6.1 → circup-1.7.0}/circup.egg-info/requires.txt +5 -5
  44. {circup-1.6.1 → circup-1.7.0}/circup.egg-info/top_level.txt +0 -0
  45. {circup-1.6.1 → circup-1.7.0}/docs/_static/favicon.ico +0 -0
  46. {circup-1.6.1 → circup-1.7.0}/docs/_static/favicon.ico.license +0 -0
  47. {circup-1.6.1 → circup-1.7.0}/docs/index.rst +0 -0
  48. {circup-1.6.1 → circup-1.7.0}/docs/index.rst.license +0 -0
  49. {circup-1.6.1 → circup-1.7.0}/docs/logo.png +0 -0
  50. {circup-1.6.1 → circup-1.7.0}/docs/logo.png.license +0 -0
  51. {circup-1.6.1 → circup-1.7.0}/readthedocs.yml +0 -0
  52. {circup-1.6.1 → circup-1.7.0}/requirements.txt.license +0 -0
  53. {circup-1.6.1 → circup-1.7.0}/setup.cfg +0 -0
  54. {circup-1.6.1 → circup-1.7.0}/setup.py +0 -0
  55. {circup-1.6.1 → circup-1.7.0}/tests/__init__.py +0 -0
  56. {circup-1.6.1 → circup-1.7.0}/tests/bad_module/__init__.py +0 -0
  57. {circup-1.6.1 → circup-1.7.0}/tests/bad_module/my_module.py +0 -0
  58. {circup-1.6.1 → circup-1.7.0}/tests/bad_python.py +0 -0
  59. {circup-1.6.1 → circup-1.7.0}/tests/bundle.json +0 -0
  60. {circup-1.6.1 → circup-1.7.0}/tests/bundle.json.license +0 -0
  61. {circup-1.6.1 → circup-1.7.0}/tests/device.json +0 -0
  62. {circup-1.6.1 → circup-1.7.0}/tests/device.json.license +0 -0
  63. {circup-1.6.1 → circup-1.7.0}/tests/dir_module/__init__.py +0 -0
  64. {circup-1.6.1 → circup-1.7.0}/tests/dir_module/my_module.py +0 -0
  65. {circup-1.6.1 → circup-1.7.0}/tests/import_styles.py +0 -0
  66. {circup-1.6.1 → circup-1.7.0}/tests/local_module.py +0 -0
  67. {circup-1.6.1 → circup-1.7.0}/tests/local_module_cp7.mpy +0 -0
  68. {circup-1.6.1 → circup-1.7.0}/tests/local_module_cp7.mpy.license +0 -0
  69. {circup-1.6.1 → circup-1.7.0}/tests/mock_device/boot_out.txt.license +0 -0
  70. {circup-1.6.1 → circup-1.7.0}/tests/mount_exists.txt +0 -0
  71. {circup-1.6.1 → circup-1.7.0}/tests/mount_exists.txt.license +0 -0
  72. {circup-1.6.1 → circup-1.7.0}/tests/mount_missing.txt +0 -0
  73. {circup-1.6.1 → circup-1.7.0}/tests/mount_missing.txt.license +0 -0
  74. {circup-1.6.1 → circup-1.7.0}/tests/remote_module.py +0 -0
  75. {circup-1.6.1 → circup-1.7.0}/tests/test_bundle_config.json +0 -0
  76. {circup-1.6.1 → circup-1.7.0}/tests/test_bundle_config.json.license +0 -0
  77. {circup-1.6.1 → circup-1.7.0}/tests/test_bundle_config_local.json +0 -0
  78. {circup-1.6.1 → circup-1.7.0}/tests/test_bundle_config_local.json.license +0 -0
  79. {circup-1.6.1 → circup-1.7.0}/tests/test_module.mpy +0 -0
  80. {circup-1.6.1 → circup-1.7.0}/tests/test_module.mpy.license +0 -0
@@ -19,6 +19,7 @@ downloads/
19
19
  eggs/
20
20
  .eggs/
21
21
  lib/
22
+ !tests/mock_device/lib/
22
23
  lib64/
23
24
  parts/
24
25
  sdist/
@@ -93,6 +94,7 @@ venv/
93
94
  ENV/
94
95
  env.bak/
95
96
  venv.bak/
97
+ *_venv/
96
98
 
97
99
  # Spyder project settings
98
100
  .spyderproject
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: circup
3
- Version: 1.6.1
3
+ Version: 1.7.0
4
4
  Summary: A tool to manage/update libraries on CircuitPython devices.
5
5
  Home-page: https://github.com/adafruit/circup
6
6
  Author: Adafruit Industries
@@ -57,16 +57,16 @@ Requires-Dist: sphinx; extra == "dev"
57
57
  Requires-Dist: wheel; extra == "dev"
58
58
  Requires-Dist: twine; extra == "dev"
59
59
  Provides-Extra: all
60
- Requires-Dist: pytest-faulthandler; extra == "all"
61
- Requires-Dist: pylint; extra == "all"
62
60
  Requires-Dist: wheel; extra == "all"
61
+ Requires-Dist: pytest-faulthandler; extra == "all"
63
62
  Requires-Dist: pytest-random-order>=1.0.0; extra == "all"
63
+ Requires-Dist: pylint; extra == "all"
64
+ Requires-Dist: pytest; extra == "all"
64
65
  Requires-Dist: coverage; extra == "all"
65
66
  Requires-Dist: black; extra == "all"
66
- Requires-Dist: sphinx; extra == "all"
67
- Requires-Dist: twine; extra == "all"
68
67
  Requires-Dist: pytest-cov; extra == "all"
69
- Requires-Dist: pytest; extra == "all"
68
+ Requires-Dist: twine; extra == "all"
69
+ Requires-Dist: sphinx; extra == "all"
70
70
 
71
71
 
72
72
  CircUp
@@ -0,0 +1,26 @@
1
+ # SPDX-FileCopyrightText: 2019 Nicholas Tollervey, written for Adafruit Industries
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ """
5
+ CircUp -- a utility to manage and update libraries on a CircuitPython device.
6
+ """
7
+
8
+
9
+ from circup.shared import DATA_DIR, BAD_FILE_FORMAT, extract_metadata, _get_modules_file
10
+ from circup.backends import WebBackend, DiskBackend
11
+ from circup.logging import logger
12
+
13
+
14
+ # Useful constants.
15
+
16
+
17
+ __version__ = "0.0.0-auto.0"
18
+ __repo__ = "https://github.com/adafruit/circup.git"
19
+
20
+
21
+ from circup.commands import *
22
+
23
+ # Allows execution via `python -m circup ...`
24
+ # pylint: disable=no-value-for-parameter
25
+ if __name__ == "__main__": # pragma: no cover
26
+ main()
@@ -589,14 +589,31 @@ class WebBackend(Backend):
589
589
 
590
590
  def is_device_present(self):
591
591
  """
592
- returns True if the device is currently connected
592
+ returns True if the device is currently connected and running supported version
593
593
  """
594
594
  try:
595
- _ = self.session.get(f"{self.device_location}/cp/version.json")
596
- return True
595
+ with self.session.get(f"{self.device_location}/cp/version.json") as r:
596
+ r.raise_for_status()
597
+ web_api_version = r.json().get("web_api_version")
598
+ if web_api_version is None:
599
+ self.logger.error("Unable to get web API version from device.")
600
+ click.secho("Unable to get web API version from device.", fg="red")
601
+ return False
602
+
603
+ if web_api_version < 4:
604
+ self.logger.error(
605
+ f"Device running unsupported web API version {web_api_version} < 4."
606
+ )
607
+ click.secho(
608
+ f"Device running unsupported web API version {web_api_version} < 4.",
609
+ fg="red",
610
+ )
611
+ return False
597
612
  except requests.exceptions.ConnectionError:
598
613
  return False
599
614
 
615
+ return True
616
+
600
617
  def get_device_versions(self):
601
618
  """
602
619
  Returns a dictionary of metadata from modules on the connected device.
@@ -0,0 +1,156 @@
1
+ # SPDX-FileCopyrightText: 2019 Nicholas Tollervey, 2024 Tim Cocks, written for Adafruit Industries
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ """
5
+ Class that represents a specific release of a Bundle.
6
+ """
7
+ import os
8
+ import sys
9
+
10
+ import click
11
+ import requests
12
+
13
+ from circup.shared import (
14
+ DATA_DIR,
15
+ PLATFORMS,
16
+ REQUESTS_TIMEOUT,
17
+ tags_data_load,
18
+ get_latest_release_from_url,
19
+ )
20
+
21
+ from circup.logging import logger
22
+
23
+
24
+ class Bundle:
25
+ """
26
+ All the links and file names for a bundle
27
+ """
28
+
29
+ def __init__(self, repo):
30
+ """
31
+ Initialise a Bundle created from its github info.
32
+ Construct all the strings in one place.
33
+
34
+ :param str repo: Repository string for github: "user/repository"
35
+ """
36
+ vendor, bundle_id = repo.split("/")
37
+ bundle_id = bundle_id.lower().replace("_", "-")
38
+ self.key = repo
39
+ #
40
+ self.url = "https://github.com/" + repo
41
+ self.basename = bundle_id + "-{platform}-{tag}"
42
+ self.urlzip = self.basename + ".zip"
43
+ self.dir = os.path.join(DATA_DIR, vendor, bundle_id + "-{platform}")
44
+ self.zip = os.path.join(DATA_DIR, bundle_id + "-{platform}.zip")
45
+ self.url_format = self.url + "/releases/download/{tag}/" + self.urlzip
46
+ # tag
47
+ self._current = None
48
+ self._latest = None
49
+
50
+ def lib_dir(self, platform):
51
+ """
52
+ This bundle's lib directory for the platform.
53
+
54
+ :param str platform: The platform identifier (py/6mpy/...).
55
+ :return: The path to the lib directory for the platform.
56
+ """
57
+ tag = self.current_tag
58
+ return os.path.join(
59
+ self.dir.format(platform=platform),
60
+ self.basename.format(platform=PLATFORMS[platform], tag=tag),
61
+ "lib",
62
+ )
63
+
64
+ def requirements_for(self, library_name, toml_file=False):
65
+ """
66
+ The requirements file for this library.
67
+
68
+ :param str library_name: The name of the library.
69
+ :return: The path to the requirements.txt file.
70
+ """
71
+ platform = "py"
72
+ tag = self.current_tag
73
+ found_file = os.path.join(
74
+ self.dir.format(platform=platform),
75
+ self.basename.format(platform=PLATFORMS[platform], tag=tag),
76
+ "requirements",
77
+ library_name,
78
+ "requirements.txt" if not toml_file else "pyproject.toml",
79
+ )
80
+ if os.path.isfile(found_file):
81
+ with open(found_file, "r", encoding="utf-8") as read_this:
82
+ return read_this.read()
83
+ return None
84
+
85
+ @property
86
+ def current_tag(self):
87
+ """
88
+ Lazy load current cached tag from the BUNDLE_DATA json file.
89
+
90
+ :return: The current cached tag value for the project.
91
+ """
92
+ if self._current is None:
93
+ self._current = tags_data_load(logger).get(self.key, "0")
94
+ return self._current
95
+
96
+ @current_tag.setter
97
+ def current_tag(self, tag):
98
+ """
99
+ Set the current cached tag (after updating).
100
+
101
+ :param str tag: The new value for the current tag.
102
+ :return: The current cached tag value for the project.
103
+ """
104
+ self._current = tag
105
+
106
+ @property
107
+ def latest_tag(self):
108
+ """
109
+ Lazy find the value of the latest tag for the bundle.
110
+
111
+ :return: The most recent tag value for the project.
112
+ """
113
+ if self._latest is None:
114
+ self._latest = get_latest_release_from_url(
115
+ self.url + "/releases/latest", logger
116
+ )
117
+ return self._latest
118
+
119
+ def validate(self):
120
+ """
121
+ Test the existence of the expected URLs (not their content)
122
+ """
123
+ tag = self.latest_tag
124
+ if not tag or tag == "releases":
125
+ if "--verbose" in sys.argv:
126
+ click.secho(f' Invalid tag "{tag}"', fg="red")
127
+ return False
128
+ for platform in PLATFORMS.values():
129
+ url = self.url_format.format(platform=platform, tag=tag)
130
+ r = requests.get(url, stream=True, timeout=REQUESTS_TIMEOUT)
131
+ # pylint: disable=no-member
132
+ if r.status_code != requests.codes.ok:
133
+ if "--verbose" in sys.argv:
134
+ click.secho(f" Unable to find {os.path.split(url)[1]}", fg="red")
135
+ return False
136
+ # pylint: enable=no-member
137
+ return True
138
+
139
+ def __repr__(self):
140
+ """
141
+ Helps with log files.
142
+
143
+ :return: A repr of a dictionary containing the Bundles's metadata.
144
+ """
145
+ return repr(
146
+ {
147
+ "key": self.key,
148
+ "url": self.url,
149
+ "urlzip": self.urlzip,
150
+ "dir": self.dir,
151
+ "zip": self.zip,
152
+ "url_format": self.url_format,
153
+ "current": self._current,
154
+ "latest": self._latest,
155
+ }
156
+ )