circup 1.8.0__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 (80) hide show
  1. {circup-1.8.0 → circup-2.0.1}/.github/workflows/build.yml +2 -2
  2. circup-2.0.1/.github/workflows/release.yml +34 -0
  3. {circup-1.8.0 → circup-2.0.1}/CONTRIBUTING.rst +13 -4
  4. {circup-1.8.0/circup.egg-info → circup-2.0.1}/PKG-INFO +29 -51
  5. {circup-1.8.0 → circup-2.0.1}/circup/backends.py +77 -18
  6. {circup-1.8.0 → circup-2.0.1}/circup/command_utils.py +24 -13
  7. {circup-1.8.0 → circup-2.0.1}/circup/commands.py +19 -4
  8. {circup-1.8.0 → circup-2.0.1/circup.egg-info}/PKG-INFO +29 -51
  9. {circup-1.8.0 → circup-2.0.1}/circup.egg-info/SOURCES.txt +1 -2
  10. circup-2.0.1/pyproject.toml +51 -0
  11. {circup-1.8.0 → circup-2.0.1}/tests/import_styles.py +1 -1
  12. circup-1.8.0/.github/workflows/release.yml +0 -39
  13. circup-1.8.0/circup.egg-info/requires.txt +0 -50
  14. circup-1.8.0/setup.py +0 -104
  15. {circup-1.8.0 → circup-2.0.1}/.github/ISSUE_TEMPLATE.md +0 -0
  16. {circup-1.8.0 → circup-2.0.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  17. {circup-1.8.0 → circup-2.0.1}/.gitignore +0 -0
  18. {circup-1.8.0 → circup-2.0.1}/.isort.cfg +0 -0
  19. {circup-1.8.0 → circup-2.0.1}/.pre-commit-config.yaml +0 -0
  20. {circup-1.8.0 → circup-2.0.1}/.pylintrc +0 -0
  21. {circup-1.8.0 → circup-2.0.1}/CODE_OF_CONDUCT.rst +0 -0
  22. {circup-1.8.0 → circup-2.0.1}/CODE_OF_CONDUCT.rst.license +0 -0
  23. {circup-1.8.0 → circup-2.0.1}/CONTRIBUTING.rst.license +0 -0
  24. {circup-1.8.0 → circup-2.0.1}/LICENSE +0 -0
  25. {circup-1.8.0 → circup-2.0.1}/LICENSES/CC-BY-4.0.txt +0 -0
  26. {circup-1.8.0 → circup-2.0.1}/LICENSES/MIT.txt +0 -0
  27. {circup-1.8.0 → circup-2.0.1}/LICENSES/Unlicense.txt +0 -0
  28. {circup-1.8.0 → circup-2.0.1}/README.rst +0 -0
  29. {circup-1.8.0 → circup-2.0.1}/README.rst.license +0 -0
  30. {circup-1.8.0 → circup-2.0.1}/circup/__init__.py +0 -0
  31. {circup-1.8.0 → circup-2.0.1}/circup/bundle.py +0 -0
  32. {circup-1.8.0 → circup-2.0.1}/circup/config/bundle_config.json +0 -0
  33. {circup-1.8.0 → circup-2.0.1}/circup/config/bundle_config.json.license +0 -0
  34. {circup-1.8.0 → circup-2.0.1}/circup/logging.py +0 -0
  35. {circup-1.8.0 → circup-2.0.1}/circup/module.py +0 -0
  36. {circup-1.8.0 → circup-2.0.1}/circup/shared.py +0 -0
  37. {circup-1.8.0 → circup-2.0.1}/circup.egg-info/dependency_links.txt +0 -0
  38. {circup-1.8.0 → circup-2.0.1}/circup.egg-info/entry_points.txt +0 -0
  39. {circup-1.8.0 → circup-2.0.1}/circup.egg-info/top_level.txt +0 -0
  40. {circup-1.8.0 → circup-2.0.1}/docs/_static/favicon.ico +0 -0
  41. {circup-1.8.0 → circup-2.0.1}/docs/_static/favicon.ico.license +0 -0
  42. {circup-1.8.0 → circup-2.0.1}/docs/conf.py +0 -0
  43. {circup-1.8.0 → circup-2.0.1}/docs/index.rst +0 -0
  44. {circup-1.8.0 → circup-2.0.1}/docs/index.rst.license +0 -0
  45. {circup-1.8.0 → circup-2.0.1}/docs/logo.png +0 -0
  46. {circup-1.8.0 → circup-2.0.1}/docs/logo.png.license +0 -0
  47. {circup-1.8.0 → circup-2.0.1}/optional_requirements.txt +0 -0
  48. {circup-1.8.0 → circup-2.0.1}/optional_requirements.txt.license +0 -0
  49. {circup-1.8.0 → circup-2.0.1}/readthedocs.yml +0 -0
  50. {circup-1.8.0 → circup-2.0.1}/requirements.txt +0 -0
  51. {circup-1.8.0 → circup-2.0.1}/requirements.txt.license +0 -0
  52. {circup-1.8.0 → circup-2.0.1}/setup.cfg +0 -0
  53. {circup-1.8.0 → circup-2.0.1}/tests/__init__.py +0 -0
  54. {circup-1.8.0 → circup-2.0.1}/tests/bad_module/__init__.py +0 -0
  55. {circup-1.8.0 → circup-2.0.1}/tests/bad_module/my_module.py +0 -0
  56. {circup-1.8.0 → circup-2.0.1}/tests/bad_python.py +0 -0
  57. {circup-1.8.0 → circup-2.0.1}/tests/bundle.json +0 -0
  58. {circup-1.8.0 → circup-2.0.1}/tests/bundle.json.license +0 -0
  59. {circup-1.8.0 → circup-2.0.1}/tests/device.json +0 -0
  60. {circup-1.8.0 → circup-2.0.1}/tests/device.json.license +0 -0
  61. {circup-1.8.0 → circup-2.0.1}/tests/dir_module/__init__.py +0 -0
  62. {circup-1.8.0 → circup-2.0.1}/tests/dir_module/my_module.py +0 -0
  63. {circup-1.8.0 → circup-2.0.1}/tests/local_module.py +0 -0
  64. {circup-1.8.0 → circup-2.0.1}/tests/local_module_cp7.mpy +0 -0
  65. {circup-1.8.0 → circup-2.0.1}/tests/local_module_cp7.mpy.license +0 -0
  66. {circup-1.8.0 → circup-2.0.1}/tests/mock_device/boot_out.txt +0 -0
  67. {circup-1.8.0 → circup-2.0.1}/tests/mock_device/boot_out.txt.license +0 -0
  68. {circup-1.8.0 → circup-2.0.1}/tests/mock_device/lib/adafruit_waveform/.gitkeep +0 -0
  69. {circup-1.8.0 → circup-2.0.1}/tests/mount_exists.txt +0 -0
  70. {circup-1.8.0 → circup-2.0.1}/tests/mount_exists.txt.license +0 -0
  71. {circup-1.8.0 → circup-2.0.1}/tests/mount_missing.txt +0 -0
  72. {circup-1.8.0 → circup-2.0.1}/tests/mount_missing.txt.license +0 -0
  73. {circup-1.8.0 → circup-2.0.1}/tests/remote_module.py +0 -0
  74. {circup-1.8.0 → circup-2.0.1}/tests/test_bundle_config.json +0 -0
  75. {circup-1.8.0 → circup-2.0.1}/tests/test_bundle_config.json.license +0 -0
  76. {circup-1.8.0 → circup-2.0.1}/tests/test_bundle_config_local.json +0 -0
  77. {circup-1.8.0 → circup-2.0.1}/tests/test_bundle_config_local.json.license +0 -0
  78. {circup-1.8.0 → circup-2.0.1}/tests/test_circup.py +0 -0
  79. {circup-1.8.0 → circup-2.0.1}/tests/test_module.mpy +0 -0
  80. {circup-1.8.0 → circup-2.0.1}/tests/test_module.mpy.license +0 -0
@@ -17,10 +17,10 @@ jobs:
17
17
  - name: Translate Repo Name For Build Tools filename_prefix
18
18
  id: repo-name
19
19
  run: echo ::set-output name=repo-name::circup
20
- - name: Set up Python 3.7
20
+ - name: Set up Python 3.11
21
21
  uses: actions/setup-python@v1
22
22
  with:
23
- python-version: 3.7
23
+ python-version: 3.11
24
24
  - name: Pip install Sphinx & pre-commit
25
25
  run: |
26
26
  pip install --force-reinstall Sphinx sphinx-rtd-theme pre-commit
@@ -0,0 +1,34 @@
1
+ # SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2
+ # SPDX-FileCopyrightText: 2021 James Carr
3
+ #
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ name: Release Actions
7
+
8
+ on:
9
+ release:
10
+ types: [published]
11
+
12
+ jobs:
13
+ upload-pypi:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ with:
18
+ filter: 'blob:none'
19
+ depth: 0
20
+ - name: Set up Python
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: '3.11'
24
+ - name: Install dependencies
25
+ run: |
26
+ python -m pip install --upgrade pip
27
+ pip install build setuptools wheel twine
28
+ - name: Build and publish
29
+ env:
30
+ TWINE_USERNAME: ${{ secrets.pypi_username }}
31
+ TWINE_PASSWORD: ${{ secrets.pypi_password }}
32
+ run: |
33
+ python -m build
34
+ twine upload dist/*
@@ -25,15 +25,24 @@ Developer Setup
25
25
 
26
26
  .. note::
27
27
 
28
- Please try to use Python 3.6+ while developing CircUp. This is so we can
28
+ Please try to use Python 3.9+ while developing CircUp. This is so we can
29
29
  use the
30
30
  `Black code formatter <https://black.readthedocs.io/en/stable/index.html>`_
31
- (which only works with Python 3.6+).
31
+ and so that we're supporting versions which still receive security updates.
32
+
32
33
 
33
34
  Clone the repository and from the root of the project,
34
- install the requirements::
35
35
 
36
- pip install -e ".[dev]"
36
+
37
+ If you'd like you can setup a virtual environment and activate it.::
38
+
39
+ python3 -m venv .env
40
+ source .env/bin/activate
41
+
42
+ install the development requirements::
43
+
44
+ pip install -r optional_requirements.txt
45
+
37
46
 
38
47
  Run the test suite::
39
48
 
@@ -1,11 +1,31 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: circup
3
- Version: 1.8.0
3
+ Version: 2.0.1
4
4
  Summary: A tool to manage/update libraries on CircuitPython devices.
5
- Home-page: https://github.com/adafruit/circup
6
- Author: Adafruit Industries
7
- Author-email: circuitpython@adafruit.com
8
- License: MIT
5
+ Author-email: Adafruit Industries <circuitpython@adafruit.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2019 Adafruit Industries
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: homepage, https://github.com/adafruit/circup
9
29
  Keywords: adafruit,blinka,circuitpython,micropython,libraries
10
30
  Classifier: Development Status :: 3 - Alpha
11
31
  Classifier: Environment :: Console
@@ -15,58 +35,16 @@ Classifier: License :: OSI Approved :: MIT License
15
35
  Classifier: Operating System :: POSIX
16
36
  Classifier: Operating System :: MacOS :: MacOS X
17
37
  Classifier: Operating System :: Microsoft :: Windows
18
- Classifier: Programming Language :: Python :: 3.6
19
- Classifier: Programming Language :: Python :: 3.7
20
- Classifier: Programming Language :: Python :: 3.8
38
+ Classifier: Programming Language :: Python :: 3
21
39
  Classifier: Programming Language :: Python :: 3.9
40
+ Classifier: Programming Language :: Python :: 3.10
41
+ Classifier: Programming Language :: Python :: 3.11
22
42
  Classifier: Topic :: Education
23
43
  Classifier: Topic :: Software Development :: Embedded Systems
24
44
  Classifier: Topic :: System :: Software Distribution
45
+ Requires-Python: >=3.9
25
46
  Description-Content-Type: text/x-rst
26
47
  License-File: LICENSE
27
- Requires-Dist: semver~=3.0
28
- Requires-Dist: Click>=8.0
29
- Requires-Dist: appdirs>=1.4.3
30
- Requires-Dist: requests>=2.22.0
31
- Requires-Dist: findimports>=2.1.0
32
- Requires-Dist: toml>=0.10.2
33
- Requires-Dist: importlib_metadata; python_version == "3.7"
34
- Requires-Dist: update_checker
35
- Provides-Extra: tests
36
- Requires-Dist: pytest; extra == "tests"
37
- Requires-Dist: pylint; extra == "tests"
38
- Requires-Dist: pytest-cov; extra == "tests"
39
- Requires-Dist: pytest-random-order>=1.0.0; extra == "tests"
40
- Requires-Dist: pytest-faulthandler; extra == "tests"
41
- Requires-Dist: coverage; extra == "tests"
42
- Requires-Dist: black; extra == "tests"
43
- Provides-Extra: docs
44
- Requires-Dist: sphinx; extra == "docs"
45
- Provides-Extra: package
46
- Requires-Dist: wheel; extra == "package"
47
- Requires-Dist: twine; extra == "package"
48
- Provides-Extra: dev
49
- Requires-Dist: pytest; extra == "dev"
50
- Requires-Dist: pylint; extra == "dev"
51
- Requires-Dist: pytest-cov; extra == "dev"
52
- Requires-Dist: pytest-random-order>=1.0.0; extra == "dev"
53
- Requires-Dist: pytest-faulthandler; extra == "dev"
54
- Requires-Dist: coverage; extra == "dev"
55
- Requires-Dist: black; extra == "dev"
56
- Requires-Dist: sphinx; extra == "dev"
57
- Requires-Dist: wheel; extra == "dev"
58
- Requires-Dist: twine; extra == "dev"
59
- Provides-Extra: all
60
- Requires-Dist: wheel; extra == "all"
61
- Requires-Dist: pytest-faulthandler; extra == "all"
62
- Requires-Dist: coverage; extra == "all"
63
- Requires-Dist: pylint; extra == "all"
64
- Requires-Dist: pytest; extra == "all"
65
- Requires-Dist: twine; extra == "all"
66
- Requires-Dist: sphinx; extra == "all"
67
- Requires-Dist: black; extra == "all"
68
- Requires-Dist: pytest-random-order>=1.0.0; extra == "all"
69
- Requires-Dist: pytest-cov; extra == "all"
70
48
 
71
49
 
72
50
  CircUp
@@ -29,9 +29,10 @@ class Backend:
29
29
  implementations
30
30
  """
31
31
 
32
- def __init__(self, logger):
32
+ def __init__(self, logger, version_override=None):
33
33
  self.device_location = None
34
34
  self.LIB_DIR_PATH = None
35
+ self.version_override = version_override
35
36
  self.logger = logger
36
37
 
37
38
  def get_circuitpython_version(self):
@@ -90,7 +91,13 @@ class Backend:
90
91
  """
91
92
  raise NotImplementedError
92
93
 
93
- # pylint: disable=too-many-locals,too-many-branches,too-many-arguments,too-many-nested-blocks
94
+ def copy_file(self, target_file, location_to_paste):
95
+ """Paste a copy of the specified file at the location given
96
+ To be overridden by subclass
97
+ """
98
+ raise NotImplementedError
99
+
100
+ # pylint: disable=too-many-locals,too-many-branches,too-many-arguments,too-many-nested-blocks,too-many-statements
94
101
  def install_module(
95
102
  self, device_path, device_modules, name, pyext, mod_names, upgrade=False
96
103
  ): # pragma: no cover
@@ -109,9 +116,19 @@ class Backend:
109
116
  with get_bundle_versions()
110
117
  :param bool upgrade: Upgrade the specified modules if they're already installed.
111
118
  """
119
+ local_path = None
120
+ if os.path.exists(name):
121
+ # local file exists use that.
122
+ local_path = name
123
+ name = local_path.split(os.path.sep)[-1]
124
+ name = name.replace(".py", "").replace(".mpy", "")
125
+ click.echo(f"Installing from local path: {local_path}")
126
+
112
127
  if not name:
113
128
  click.echo("No module name(s) provided.")
114
- elif name in mod_names:
129
+ return
130
+ if name in mod_names or local_path is not None:
131
+
115
132
  # Grab device modules to check if module already installed
116
133
  if name in device_modules:
117
134
  if not upgrade:
@@ -129,14 +146,19 @@ class Backend:
129
146
  module_path = _metadata["path"]
130
147
  self.uninstall(device_path, module_path)
131
148
 
149
+ new_module_size = 0
132
150
  library_path = (
133
151
  os.path.join(device_path, self.LIB_DIR_PATH)
134
152
  if not isinstance(self, WebBackend)
135
153
  else urljoin(device_path, self.LIB_DIR_PATH)
136
154
  )
137
- metadata = mod_names[name]
138
- bundle = metadata["bundle"]
139
- bundle.size = os.path.getsize(metadata["path"])
155
+ if local_path is None:
156
+ metadata = mod_names[name]
157
+ bundle = metadata["bundle"]
158
+ else:
159
+ metadata = {"path": local_path}
160
+
161
+ new_module_size = os.path.getsize(metadata["path"])
140
162
  if os.path.isdir(metadata["path"]):
141
163
  # pylint: disable=unused-variable
142
164
  for dirpath, dirnames, filenames in os.walk(metadata["path"]):
@@ -144,7 +166,7 @@ class Backend:
144
166
  fp = os.path.join(dirpath, f)
145
167
  try:
146
168
  if not os.path.islink(fp): # Ignore symbolic links
147
- bundle.size += os.path.getsize(fp)
169
+ new_module_size += os.path.getsize(fp)
148
170
  else:
149
171
  self.logger.warning(
150
172
  f"Skipping symbolic link in space calculation: {fp}"
@@ -154,27 +176,29 @@ class Backend:
154
176
  f"Error: {e} - Skipping file in space calculation: {fp}"
155
177
  )
156
178
 
157
- if self.get_free_space() < bundle.size:
179
+ if self.get_free_space() < new_module_size:
158
180
  self.logger.error(
159
181
  f"Aborted installing module {name} - "
160
- f"not enough free space ({bundle.size} < {self.get_free_space()})"
182
+ f"not enough free space ({new_module_size} < {self.get_free_space()})"
161
183
  )
162
184
  click.secho(
163
185
  f"Aborted installing module {name} - "
164
- f"not enough free space ({bundle.size} < {self.get_free_space()})",
186
+ f"not enough free space ({new_module_size} < {self.get_free_space()})",
165
187
  fg="red",
166
188
  )
167
189
  return
168
190
 
169
191
  # Create the library directory first.
170
192
  self._create_library_directory(device_path, library_path)
171
-
172
- if pyext:
173
- # Use Python source for module.
174
- self.install_module_py(metadata)
193
+ if local_path is None:
194
+ if pyext:
195
+ # Use Python source for module.
196
+ self.install_module_py(metadata)
197
+ else:
198
+ # Use pre-compiled mpy modules.
199
+ self.install_module_mpy(bundle, metadata)
175
200
  else:
176
- # Use pre-compiled mpy modules.
177
- self.install_module_mpy(bundle, metadata)
201
+ self.copy_file(metadata["path"], "lib")
178
202
  click.echo("Installed '{}'.".format(name))
179
203
  else:
180
204
  click.echo("Unknown module named, '{}'.".format(name))
@@ -252,7 +276,9 @@ class WebBackend(Backend):
252
276
  Backend for interacting with a device via Web Workflow
253
277
  """
254
278
 
255
- def __init__(self, host, password, logger, timeout=10):
279
+ def __init__( # pylint: disable=too-many-arguments
280
+ self, host, password, logger, timeout=10, version_override=None
281
+ ):
256
282
  super().__init__(logger)
257
283
  if password is None:
258
284
  raise ValueError("--host needs --password")
@@ -278,6 +304,7 @@ class WebBackend(Backend):
278
304
  self.session.mount(self.device_location, HTTPAdapter(max_retries=5))
279
305
  self.library_path = self.device_location + "/" + self.LIB_DIR_PATH
280
306
  self.timeout = timeout
307
+ self.version_override = version_override
281
308
 
282
309
  def install_file_http(self, source, location=None):
283
310
  """
@@ -378,6 +405,9 @@ class WebBackend(Backend):
378
405
 
379
406
  :return: A tuple with the version string for CircuitPython and the board ID string.
380
407
  """
408
+ if self.version_override is not None:
409
+ return self.version_override
410
+
381
411
  # pylint: disable=arguments-renamed
382
412
  with self.session.get(
383
413
  self.device_location + "/cp/version.json", timeout=self.timeout
@@ -520,6 +550,17 @@ class WebBackend(Backend):
520
550
  _writeable_error()
521
551
  r.raise_for_status()
522
552
 
553
+ def copy_file(self, target_file, location_to_paste):
554
+ if os.path.isdir(target_file):
555
+ create_directory_url = urljoin(
556
+ self.device_location,
557
+ "/".join(("fs", location_to_paste, target_file, "")),
558
+ )
559
+ self._create_library_directory(self.device_location, create_directory_url)
560
+ self.install_dir_http(target_file)
561
+ else:
562
+ self.install_file_http(target_file)
563
+
523
564
  def install_module_mpy(self, bundle, metadata):
524
565
  """
525
566
  :param bundle library bundle.
@@ -707,9 +748,10 @@ class DiskBackend(Backend):
707
748
  :param logger: logger to use for outputting messages
708
749
  :param String boot_out: Optional mock contents of a boot_out.txt file
709
750
  to use for version information.
751
+ :param String version_override: Optional mock version to use.
710
752
  """
711
753
 
712
- def __init__(self, device_location, logger, boot_out=None):
754
+ def __init__(self, device_location, logger, boot_out=None, version_override=None):
713
755
  if device_location is None:
714
756
  raise ValueError(
715
757
  "Auto locating USB Disk based device failed. "
@@ -723,6 +765,7 @@ class DiskBackend(Backend):
723
765
  self.version_info = None
724
766
  if boot_out is not None:
725
767
  self.version_info = self.parse_boot_out_file(boot_out)
768
+ self.version_override = version_override
726
769
 
727
770
  def get_circuitpython_version(self):
728
771
  """
@@ -739,6 +782,9 @@ class DiskBackend(Backend):
739
782
 
740
783
  :return: A tuple with the version string for CircuitPython and the board ID string.
741
784
  """
785
+ if self.version_override is not None:
786
+ return self.version_override
787
+
742
788
  if not self.version_info:
743
789
  try:
744
790
  with open(
@@ -775,6 +821,19 @@ class DiskBackend(Backend):
775
821
  if not os.path.exists(library_path): # pragma: no cover
776
822
  os.makedirs(library_path)
777
823
 
824
+ def copy_file(self, target_file, location_to_paste):
825
+ target_filename = target_file.split(os.path.sep)[-1]
826
+ if os.path.isdir(target_file):
827
+ shutil.copytree(
828
+ target_file,
829
+ os.path.join(self.device_location, location_to_paste, target_filename),
830
+ )
831
+ else:
832
+ shutil.copyfile(
833
+ target_file,
834
+ os.path.join(self.device_location, location_to_paste, target_filename),
835
+ )
836
+
778
837
  def install_module_mpy(self, bundle, metadata):
779
838
  """
780
839
  :param bundle library bundle.
@@ -6,6 +6,7 @@ Functions called from commands in order to provide behaviors and return informat
6
6
  """
7
7
 
8
8
  import ctypes
9
+ import glob
9
10
  import os
10
11
 
11
12
  from subprocess import check_output
@@ -90,6 +91,7 @@ def completion_for_install(ctx, param, incomplete):
90
91
  module_names = {m.replace(".py", "") for m in available_modules}
91
92
  if incomplete:
92
93
  module_names = [name for name in module_names if name.startswith(incomplete)]
94
+ module_names.extend(glob.glob(f"{incomplete}*"))
93
95
  return sorted(module_names)
94
96
 
95
97
 
@@ -446,6 +448,7 @@ def get_dependencies(*requested_libraries, mod_names, to_install=()):
446
448
  :param list(str) to_install: Modules already selected for installation.
447
449
  :return: tuple of module names to install which we build
448
450
  """
451
+ # pylint: disable=too-many-branches
449
452
  # Internal variables
450
453
  _to_install = to_install
451
454
  _requested_libraries = []
@@ -471,10 +474,14 @@ def get_dependencies(*requested_libraries, mod_names, to_install=()):
471
474
  _requested_libraries.append(canonical_lib_name)
472
475
  except KeyError:
473
476
  if canonical_lib_name not in WARNING_IGNORE_MODULES:
474
- click.secho(
475
- f"WARNING:\n\t{canonical_lib_name} is not a known CircuitPython library.",
476
- fg="yellow",
477
- )
477
+ if os.path.exists(canonical_lib_name):
478
+ _requested_libraries.append(canonical_lib_name)
479
+ else:
480
+ click.secho(
481
+ f"WARNING:\n\t{canonical_lib_name} "
482
+ f"is not a known CircuitPython library.",
483
+ fg="yellow",
484
+ )
478
485
 
479
486
  if not _requested_libraries:
480
487
  # If nothing is requested, we're done
@@ -484,16 +491,20 @@ def get_dependencies(*requested_libraries, mod_names, to_install=()):
484
491
  if library not in _to_install:
485
492
  _to_install = _to_install + (library,)
486
493
  # get the requirements.txt from bundle
487
- bundle = mod_names[library]["bundle"]
488
- requirements_txt = bundle.requirements_for(library)
489
- if requirements_txt:
490
- _requested_libraries.extend(
491
- libraries_from_requirements(requirements_txt)
492
- )
494
+ try:
495
+ bundle = mod_names[library]["bundle"]
496
+ requirements_txt = bundle.requirements_for(library)
497
+ if requirements_txt:
498
+ _requested_libraries.extend(
499
+ libraries_from_requirements(requirements_txt)
500
+ )
493
501
 
494
- circup_dependencies = get_circup_dependencies(bundle, library)
495
- for circup_dependency in circup_dependencies:
496
- _requested_libraries.append(circup_dependency)
502
+ circup_dependencies = get_circup_dependencies(bundle, library)
503
+ for circup_dependency in circup_dependencies:
504
+ _requested_libraries.append(circup_dependency)
505
+ except KeyError:
506
+ # don't check local file for further dependencies
507
+ pass
497
508
 
498
509
  # we've processed this library, remove it from the list
499
510
  _requested_libraries.remove(library)
@@ -57,7 +57,10 @@ from circup.command_utils import (
57
57
  help="Hostname or IP address of a device. Overrides automatic path detection.",
58
58
  )
59
59
  @click.option(
60
- "--password", help="Password to use for authentication when --host is used."
60
+ "--password",
61
+ help="Password to use for authentication when --host is used."
62
+ " You can optionally set an environment variable CIRCUP_WEBWORKFLOW_PASSWORD"
63
+ " instead of passing this argument. If both exist the CLI arg takes precedent.",
61
64
  )
62
65
  @click.option(
63
66
  "--timeout",
@@ -90,6 +93,10 @@ def main( # pylint: disable=too-many-locals
90
93
  # pylint: disable=too-many-arguments,too-many-branches,too-many-statements,too-many-locals
91
94
  ctx.ensure_object(dict)
92
95
  ctx.obj["TIMEOUT"] = timeout
96
+
97
+ if password is None:
98
+ password = os.getenv("CIRCUP_WEBWORKFLOW_PASSWORD")
99
+
93
100
  device_path = get_device_path(host, password, path)
94
101
 
95
102
  using_webworkflow = "host" in ctx.params.keys() and ctx.params["host"] is not None
@@ -105,7 +112,11 @@ def main( # pylint: disable=too-many-locals
105
112
  device_path = device_path.replace("circuitpython.local", host)
106
113
  try:
107
114
  ctx.obj["backend"] = WebBackend(
108
- host=host, password=password, logger=logger, timeout=timeout
115
+ host=host,
116
+ password=password,
117
+ logger=logger,
118
+ timeout=timeout,
119
+ version_override=cpy_version,
109
120
  )
110
121
  except ValueError as e:
111
122
  click.secho(e, fg="red")
@@ -116,7 +127,11 @@ def main( # pylint: disable=too-many-locals
116
127
  sys.exit(1)
117
128
  else:
118
129
  try:
119
- ctx.obj["backend"] = DiskBackend(device_path, logger)
130
+ ctx.obj["backend"] = DiskBackend(
131
+ device_path,
132
+ logger,
133
+ version_override=cpy_version,
134
+ )
120
135
  except ValueError as e:
121
136
  print(e)
122
137
 
@@ -302,7 +317,7 @@ def install(
302
317
  """
303
318
  Install a named module(s) onto the device. Multiple modules
304
319
  can be installed at once by providing more than one module name, each
305
- separated by a space.
320
+ separated by a space. Modules can be from a Bundle or local filepaths.
306
321
  """
307
322
 
308
323
  # TODO: Ensure there's enough space on the device
@@ -1,11 +1,31 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: circup
3
- Version: 1.8.0
3
+ Version: 2.0.1
4
4
  Summary: A tool to manage/update libraries on CircuitPython devices.
5
- Home-page: https://github.com/adafruit/circup
6
- Author: Adafruit Industries
7
- Author-email: circuitpython@adafruit.com
8
- License: MIT
5
+ Author-email: Adafruit Industries <circuitpython@adafruit.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2019 Adafruit Industries
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: homepage, https://github.com/adafruit/circup
9
29
  Keywords: adafruit,blinka,circuitpython,micropython,libraries
10
30
  Classifier: Development Status :: 3 - Alpha
11
31
  Classifier: Environment :: Console
@@ -15,58 +35,16 @@ Classifier: License :: OSI Approved :: MIT License
15
35
  Classifier: Operating System :: POSIX
16
36
  Classifier: Operating System :: MacOS :: MacOS X
17
37
  Classifier: Operating System :: Microsoft :: Windows
18
- Classifier: Programming Language :: Python :: 3.6
19
- Classifier: Programming Language :: Python :: 3.7
20
- Classifier: Programming Language :: Python :: 3.8
38
+ Classifier: Programming Language :: Python :: 3
21
39
  Classifier: Programming Language :: Python :: 3.9
40
+ Classifier: Programming Language :: Python :: 3.10
41
+ Classifier: Programming Language :: Python :: 3.11
22
42
  Classifier: Topic :: Education
23
43
  Classifier: Topic :: Software Development :: Embedded Systems
24
44
  Classifier: Topic :: System :: Software Distribution
45
+ Requires-Python: >=3.9
25
46
  Description-Content-Type: text/x-rst
26
47
  License-File: LICENSE
27
- Requires-Dist: semver~=3.0
28
- Requires-Dist: Click>=8.0
29
- Requires-Dist: appdirs>=1.4.3
30
- Requires-Dist: requests>=2.22.0
31
- Requires-Dist: findimports>=2.1.0
32
- Requires-Dist: toml>=0.10.2
33
- Requires-Dist: importlib_metadata; python_version == "3.7"
34
- Requires-Dist: update_checker
35
- Provides-Extra: tests
36
- Requires-Dist: pytest; extra == "tests"
37
- Requires-Dist: pylint; extra == "tests"
38
- Requires-Dist: pytest-cov; extra == "tests"
39
- Requires-Dist: pytest-random-order>=1.0.0; extra == "tests"
40
- Requires-Dist: pytest-faulthandler; extra == "tests"
41
- Requires-Dist: coverage; extra == "tests"
42
- Requires-Dist: black; extra == "tests"
43
- Provides-Extra: docs
44
- Requires-Dist: sphinx; extra == "docs"
45
- Provides-Extra: package
46
- Requires-Dist: wheel; extra == "package"
47
- Requires-Dist: twine; extra == "package"
48
- Provides-Extra: dev
49
- Requires-Dist: pytest; extra == "dev"
50
- Requires-Dist: pylint; extra == "dev"
51
- Requires-Dist: pytest-cov; extra == "dev"
52
- Requires-Dist: pytest-random-order>=1.0.0; extra == "dev"
53
- Requires-Dist: pytest-faulthandler; extra == "dev"
54
- Requires-Dist: coverage; extra == "dev"
55
- Requires-Dist: black; extra == "dev"
56
- Requires-Dist: sphinx; extra == "dev"
57
- Requires-Dist: wheel; extra == "dev"
58
- Requires-Dist: twine; extra == "dev"
59
- Provides-Extra: all
60
- Requires-Dist: wheel; extra == "all"
61
- Requires-Dist: pytest-faulthandler; extra == "all"
62
- Requires-Dist: coverage; extra == "all"
63
- Requires-Dist: pylint; extra == "all"
64
- Requires-Dist: pytest; extra == "all"
65
- Requires-Dist: twine; extra == "all"
66
- Requires-Dist: sphinx; extra == "all"
67
- Requires-Dist: black; extra == "all"
68
- Requires-Dist: pytest-random-order>=1.0.0; extra == "all"
69
- Requires-Dist: pytest-cov; extra == "all"
70
48
 
71
49
 
72
50
  CircUp
@@ -11,10 +11,10 @@ README.rst
11
11
  README.rst.license
12
12
  optional_requirements.txt
13
13
  optional_requirements.txt.license
14
+ pyproject.toml
14
15
  readthedocs.yml
15
16
  requirements.txt
16
17
  requirements.txt.license
17
- setup.py
18
18
  .github/ISSUE_TEMPLATE.md
19
19
  .github/PULL_REQUEST_TEMPLATE.md
20
20
  .github/workflows/build.yml
@@ -34,7 +34,6 @@ circup.egg-info/PKG-INFO
34
34
  circup.egg-info/SOURCES.txt
35
35
  circup.egg-info/dependency_links.txt
36
36
  circup.egg-info/entry_points.txt
37
- circup.egg-info/requires.txt
38
37
  circup.egg-info/top_level.txt
39
38
  circup/config/bundle_config.json
40
39
  circup/config/bundle_config.json.license
@@ -0,0 +1,51 @@
1
+ # SPDX-FileCopyrightText: 2024 Jev Kuznetsov, ROX Automation
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+
5
+ [build-system]
6
+ requires = ["setuptools>=61.0", "setuptools-scm"]
7
+ build-backend = "setuptools.build_meta"
8
+
9
+ [project]
10
+ name = "circup"
11
+ dynamic = ["version"]
12
+ description = "A tool to manage/update libraries on CircuitPython devices."
13
+ readme = "README.rst"
14
+ authors = [{ name = "Adafruit Industries", email = "circuitpython@adafruit.com" }]
15
+ license = { file = "LICENSE" }
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "Intended Audience :: Education",
21
+ "License :: OSI Approved :: MIT License",
22
+ "Operating System :: POSIX",
23
+ "Operating System :: MacOS :: MacOS X",
24
+ "Operating System :: Microsoft :: Windows",
25
+ "Programming Language :: Python :: 3",
26
+ "Programming Language :: Python :: 3.9",
27
+ "Programming Language :: Python :: 3.10",
28
+ "Programming Language :: Python :: 3.11",
29
+ "Topic :: Education",
30
+ "Topic :: Software Development :: Embedded Systems",
31
+ "Topic :: System :: Software Distribution"
32
+ ]
33
+ keywords = ["adafruit", "blinka", "circuitpython", "micropython", "libraries"]
34
+
35
+ requires-python = ">=3.9"
36
+
37
+ [tool.setuptools.dynamic]
38
+ dependencies = {file = ["requirements.txt"]}
39
+ optional-dependencies = {optional = {file = ["optional_requirements.txt"]}}
40
+
41
+ [tool.setuptools_scm]
42
+
43
+ [project.scripts]
44
+ circup = "circup:main"
45
+
46
+ [project.urls]
47
+ homepage = "https://github.com/adafruit/circup"
48
+
49
+ [tool.setuptools.packages.find]
50
+ where = ["."] # This tells setuptools to look in the project root directory
51
+ include = ["circup"] # This pattern includes your main package and any sub-packages within it
@@ -4,5 +4,5 @@
4
4
  # pylint: disable=all
5
5
  import adafruit_bus_device
6
6
  from adafruit_button import Button
7
- import adafruit_esp32spi.adafruit_esp32spi_socket as socket
7
+ from adafruit_esp32spi import adafruit_esp32spi_socketpool
8
8
  import adafruit_hid.consumer_control
@@ -1,39 +0,0 @@
1
- # SPDX-FileCopyrightText: 2019 Nicholas Tollervey, written for Adafruit Industries
2
-
3
- # SPDX-License-Identifier: MIT
4
-
5
- name: Release Actions
6
-
7
- on:
8
- release:
9
- types: [published]
10
-
11
- jobs:
12
- upload-pypi:
13
- runs-on: ubuntu-latest
14
- steps:
15
- - uses: actions/checkout@v4
16
- with:
17
- show-progress: false
18
- - name: Check For setup.py
19
- id: need-pypi
20
- run: |
21
- echo ::set-output name=setup-py::$( find . -wholename './setup.py' )
22
- - name: Set up Python
23
- if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
24
- uses: actions/setup-python@v1
25
- with:
26
- python-version: '3.x'
27
- - name: Install dependencies
28
- if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
29
- run: |
30
- python -m pip install --upgrade pip
31
- pip install setuptools wheel twine
32
- - name: Build and publish
33
- if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
34
- env:
35
- TWINE_USERNAME: ${{ secrets.pypi_username }}
36
- TWINE_PASSWORD: ${{ secrets.pypi_password }}
37
- run: |
38
- python setup.py sdist
39
- twine upload dist/*
@@ -1,50 +0,0 @@
1
- semver~=3.0
2
- Click>=8.0
3
- appdirs>=1.4.3
4
- requests>=2.22.0
5
- findimports>=2.1.0
6
- toml>=0.10.2
7
- update_checker
8
-
9
- [:python_version == "3.7"]
10
- importlib_metadata
11
-
12
- [all]
13
- wheel
14
- pytest-faulthandler
15
- coverage
16
- pylint
17
- pytest
18
- twine
19
- sphinx
20
- black
21
- pytest-random-order>=1.0.0
22
- pytest-cov
23
-
24
- [dev]
25
- pytest
26
- pylint
27
- pytest-cov
28
- pytest-random-order>=1.0.0
29
- pytest-faulthandler
30
- coverage
31
- black
32
- sphinx
33
- wheel
34
- twine
35
-
36
- [docs]
37
- sphinx
38
-
39
- [package]
40
- wheel
41
- twine
42
-
43
- [tests]
44
- pytest
45
- pylint
46
- pytest-cov
47
- pytest-random-order>=1.0.0
48
- pytest-faulthandler
49
- coverage
50
- black
circup-1.8.0/setup.py DELETED
@@ -1,104 +0,0 @@
1
- # SPDX-FileCopyrightText: 2019 Nicholas Tollervey, written for Adafruit Industries
2
- #
3
- # SPDX-License-Identifier: MIT
4
-
5
-
6
- """A setuptools based setup module.
7
- See:
8
- https://packaging.python.org/guides/distributing-packages-using-setuptools/
9
- https://github.com/pypa/sampleproject
10
- """
11
-
12
- # Always prefer setuptools over distutils
13
- from setuptools import setup, find_packages
14
-
15
- # To use a consistent encoding
16
- from codecs import open
17
- from os import path
18
-
19
- here = path.abspath(path.dirname(__file__))
20
-
21
- # Get the long description from the README file
22
- with open(path.join(here, "README.rst"), encoding="utf-8") as f:
23
- long_description = f.read()
24
-
25
- install_requires = [
26
- "semver~=3.0",
27
- "Click>=8.0",
28
- "appdirs>=1.4.3",
29
- "requests>=2.22.0",
30
- "findimports>=2.1.0",
31
- "toml>=0.10.2",
32
- # importlib_metadata is only available for 3.7, and is not needed for 3.8 and up.
33
- "importlib_metadata; python_version == '3.7'",
34
- "update_checker",
35
- ]
36
-
37
- extras_require = {
38
- "tests": [
39
- "pytest",
40
- "pylint",
41
- "pytest-cov",
42
- "pytest-random-order>=1.0.0",
43
- "pytest-faulthandler",
44
- "coverage",
45
- "black",
46
- ],
47
- "docs": ["sphinx"],
48
- "package": [
49
- # Wheel building and PyPI uploading
50
- "wheel",
51
- "twine",
52
- ],
53
- }
54
-
55
- extras_require["dev"] = (
56
- extras_require["tests"] + extras_require["docs"] + extras_require["package"]
57
- )
58
-
59
- extras_require["all"] = list(
60
- {req for extra, reqs in extras_require.items() for req in reqs}
61
- )
62
-
63
- setup(
64
- name="circup",
65
- use_scm_version=True,
66
- setup_requires=["setuptools_scm"],
67
- description="A tool to manage/update libraries on CircuitPython devices.",
68
- long_description=long_description,
69
- long_description_content_type="text/x-rst",
70
- # The project's main homepage.
71
- url="https://github.com/adafruit/circup",
72
- # Author details
73
- author="Adafruit Industries",
74
- author_email="circuitpython@adafruit.com",
75
- install_requires=install_requires,
76
- extras_require=extras_require,
77
- # Choose your license
78
- license="MIT",
79
- # See https://pypi.python.org/pypi?%3Aaction=list_classifiers
80
- classifiers=[
81
- "Development Status :: 3 - Alpha",
82
- "Environment :: Console",
83
- "Intended Audience :: Developers",
84
- "Intended Audience :: Education",
85
- "License :: OSI Approved :: MIT License",
86
- "Operating System :: POSIX",
87
- "Operating System :: MacOS :: MacOS X",
88
- "Operating System :: Microsoft :: Windows",
89
- "Programming Language :: Python :: 3.6",
90
- "Programming Language :: Python :: 3.7",
91
- "Programming Language :: Python :: 3.8",
92
- "Programming Language :: Python :: 3.9",
93
- "Topic :: Education",
94
- "Topic :: Software Development :: Embedded Systems",
95
- "Topic :: System :: Software Distribution",
96
- ],
97
- entry_points={"console_scripts": ["circup=circup:main"]},
98
- # What does your project relate to?
99
- keywords="adafruit, blinka, circuitpython, micropython, libraries",
100
- # You can just specify the packages manually here if your project is
101
- # simple. Or you can use find_packages().
102
- packages=["circup"],
103
- package_data={"circup": ["config/bundle_config.json"]},
104
- )
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
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes