circup 2.2.4__py3-none-any.whl → 2.2.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- circup/lazy_metadata.py +113 -0
- circup/shared.py +27 -15
- {circup-2.2.4.dist-info → circup-2.2.5.dist-info}/METADATA +1 -1
- {circup-2.2.4.dist-info → circup-2.2.5.dist-info}/RECORD +8 -7
- {circup-2.2.4.dist-info → circup-2.2.5.dist-info}/WHEEL +0 -0
- {circup-2.2.4.dist-info → circup-2.2.5.dist-info}/entry_points.txt +0 -0
- {circup-2.2.4.dist-info → circup-2.2.5.dist-info}/licenses/LICENSE +0 -0
- {circup-2.2.4.dist-info → circup-2.2.5.dist-info}/top_level.txt +0 -0
circup/lazy_metadata.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 George Waters
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
"""
|
|
5
|
+
Class that acts similar to a dictionary, but defers the loading of expensive
|
|
6
|
+
data until that data is accessed.
|
|
7
|
+
"""
|
|
8
|
+
from typing import Any, Callable
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class LazyMetadata:
|
|
12
|
+
"""
|
|
13
|
+
Dictionary like class that stores module metadata. Expensive to load
|
|
14
|
+
metadata won't be loaded until it is accessed.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
deferred_load: Callable[[], dict[str, Any]],
|
|
20
|
+
initial_data: dict[str, Any] | None = None,
|
|
21
|
+
):
|
|
22
|
+
"""
|
|
23
|
+
Initialize a LazyMetadata object by providing a callable and initial
|
|
24
|
+
data.
|
|
25
|
+
|
|
26
|
+
:param deferred_load: A callable that returns a dictionary of metadata.
|
|
27
|
+
This is not invoked until a key is accessed that is not available in
|
|
28
|
+
:py:attr:`initial_data`.
|
|
29
|
+
:param initial_data: A dictionary containing the initial metadata.
|
|
30
|
+
"""
|
|
31
|
+
self._deferred_load = deferred_load
|
|
32
|
+
self.initial_data = initial_data.copy() if initial_data is not None else {}
|
|
33
|
+
self._deferred_data: dict[str, Any] | None = None
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def deferred_data(self) -> dict[str, Any]:
|
|
37
|
+
"""
|
|
38
|
+
Lazy load the metadata from :py:attr:`_deferred_load`.
|
|
39
|
+
|
|
40
|
+
:return: The "expensive" metadata that was loaded from
|
|
41
|
+
:py:attr:`_deferred_load`.
|
|
42
|
+
"""
|
|
43
|
+
if self._deferred_data is None:
|
|
44
|
+
self._deferred_data = self._deferred_load()
|
|
45
|
+
return self._deferred_data
|
|
46
|
+
|
|
47
|
+
def __getitem__(self, key: str) -> Any:
|
|
48
|
+
"""
|
|
49
|
+
Get items via keyed index lookup, like a dictionary.
|
|
50
|
+
|
|
51
|
+
Keys are first looked for in :py:attr:`initial_data`, if the key isn't
|
|
52
|
+
found it is then looked for in :py:attr:`deferred_data`.
|
|
53
|
+
|
|
54
|
+
:param key: Key to a metadata value.
|
|
55
|
+
:return: Metadata value for the given key.
|
|
56
|
+
:raises KeyError: If the key cannot be found.
|
|
57
|
+
"""
|
|
58
|
+
if key in self.initial_data: # pylint: disable=no-else-return
|
|
59
|
+
return self.initial_data[key]
|
|
60
|
+
elif key in self.deferred_data:
|
|
61
|
+
return self.deferred_data[key]
|
|
62
|
+
raise KeyError(key)
|
|
63
|
+
|
|
64
|
+
def __setitem__(self, key: str, item: Any) -> None:
|
|
65
|
+
"""
|
|
66
|
+
Sets the item under the given key.
|
|
67
|
+
|
|
68
|
+
The item is set in the :py:attr:`initial_data` dictionary.
|
|
69
|
+
|
|
70
|
+
:param key: Key to a metadata value.
|
|
71
|
+
:param item: Metadata value
|
|
72
|
+
"""
|
|
73
|
+
self.initial_data[key] = item
|
|
74
|
+
|
|
75
|
+
def __contains__(self, key: str):
|
|
76
|
+
"""
|
|
77
|
+
Whether or not a key is present.
|
|
78
|
+
|
|
79
|
+
This checks both :py:attr:`initial_data` and :py:attr:`deferred_data`
|
|
80
|
+
for the key. *Note* this will cause :py:attr:`deferred_data` to load
|
|
81
|
+
the deferred data if it is not already.
|
|
82
|
+
"""
|
|
83
|
+
return key in self.initial_data or key in self.deferred_data
|
|
84
|
+
|
|
85
|
+
def get(self, key: str, default: Any = None):
|
|
86
|
+
"""
|
|
87
|
+
Get items via keyed index lookup, like a dictionary.
|
|
88
|
+
|
|
89
|
+
Also like a dictionary, this method doesn't error if the key is not
|
|
90
|
+
found. :param default: is returned if the key is not found.
|
|
91
|
+
|
|
92
|
+
:param key: Key to a metadata value.
|
|
93
|
+
:param default: Default value to return when the key doesn't exist.
|
|
94
|
+
:return: Metadata value for the given key.
|
|
95
|
+
"""
|
|
96
|
+
if key in self:
|
|
97
|
+
return self[key]
|
|
98
|
+
return default
|
|
99
|
+
|
|
100
|
+
def __repr__(self) -> str:
|
|
101
|
+
"""
|
|
102
|
+
Helps with log files.
|
|
103
|
+
|
|
104
|
+
:return: A repr of a dictionary containing the metadata's values.
|
|
105
|
+
"""
|
|
106
|
+
return repr(
|
|
107
|
+
{
|
|
108
|
+
"initial_data": self.initial_data,
|
|
109
|
+
"deferred_data": self._deferred_data
|
|
110
|
+
if self._deferred_data is not None
|
|
111
|
+
else "<Not Loaded>",
|
|
112
|
+
}
|
|
113
|
+
)
|
circup/shared.py
CHANGED
|
@@ -14,6 +14,8 @@ import importlib.resources
|
|
|
14
14
|
import appdirs
|
|
15
15
|
import requests
|
|
16
16
|
|
|
17
|
+
from circup.lazy_metadata import LazyMetadata
|
|
18
|
+
|
|
17
19
|
#: Version identifier for a bad MPY file format
|
|
18
20
|
BAD_FILE_FORMAT = "Invalid"
|
|
19
21
|
|
|
@@ -51,7 +53,7 @@ NOT_MCU_LIBRARIES = [
|
|
|
51
53
|
BOARDLESS_COMMANDS = ["show", "bundle-add", "bundle-remove", "bundle-show"]
|
|
52
54
|
|
|
53
55
|
|
|
54
|
-
def _get_modules_file(path, logger):
|
|
56
|
+
def _get_modules_file(path, logger): # pylint: disable=too-many-locals
|
|
55
57
|
"""
|
|
56
58
|
Get a dictionary containing metadata about all the Python modules found in
|
|
57
59
|
the referenced file system path.
|
|
@@ -71,8 +73,10 @@ def _get_modules_file(path, logger):
|
|
|
71
73
|
]
|
|
72
74
|
single_file_mods = single_file_py_mods + single_file_mpy_mods
|
|
73
75
|
for sfm in [f for f in single_file_mods if not os.path.basename(f).startswith(".")]:
|
|
74
|
-
|
|
75
|
-
metadata
|
|
76
|
+
default_metadata = {"path": sfm, "mpy": sfm.endswith(".mpy")}
|
|
77
|
+
metadata = LazyMetadata(
|
|
78
|
+
lambda sfm=sfm: extract_metadata(sfm, logger), default_metadata
|
|
79
|
+
)
|
|
76
80
|
result[os.path.basename(sfm).replace(".py", "").replace(".mpy", "")] = metadata
|
|
77
81
|
for package_path in package_dir_mods:
|
|
78
82
|
name = os.path.basename(os.path.dirname(package_path))
|
|
@@ -81,19 +85,27 @@ def _get_modules_file(path, logger):
|
|
|
81
85
|
all_files = py_files + mpy_files
|
|
82
86
|
# put __init__ first if any, assumed to have the version number
|
|
83
87
|
all_files.sort()
|
|
88
|
+
|
|
89
|
+
def get_metadata(all_files=all_files): # capture all_files
|
|
90
|
+
selected_metadata = {}
|
|
91
|
+
# explore all the submodules to detect bad ones
|
|
92
|
+
for source in [
|
|
93
|
+
f for f in all_files if not os.path.basename(f).startswith(".")
|
|
94
|
+
]:
|
|
95
|
+
metadata = extract_metadata(source, logger)
|
|
96
|
+
if "__version__" in metadata:
|
|
97
|
+
# don't replace metadata if already found
|
|
98
|
+
if "__version__" not in selected_metadata:
|
|
99
|
+
selected_metadata = metadata
|
|
100
|
+
# break now if any of the submodules has a bad format
|
|
101
|
+
if metadata["__version__"] == BAD_FILE_FORMAT:
|
|
102
|
+
break
|
|
103
|
+
return selected_metadata
|
|
104
|
+
|
|
84
105
|
# default value
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
metadata = extract_metadata(source, logger)
|
|
89
|
-
if "__version__" in metadata:
|
|
90
|
-
# don't replace metadata if already found
|
|
91
|
-
if "__version__" not in result[name]:
|
|
92
|
-
metadata["path"] = package_path
|
|
93
|
-
result[name] = metadata
|
|
94
|
-
# break now if any of the submodules has a bad format
|
|
95
|
-
if metadata["__version__"] == BAD_FILE_FORMAT:
|
|
96
|
-
break
|
|
106
|
+
default_metadata = {"path": package_path, "mpy": bool(mpy_files)}
|
|
107
|
+
metadata = LazyMetadata(get_metadata, default_metadata)
|
|
108
|
+
result[name] = metadata
|
|
97
109
|
return result
|
|
98
110
|
|
|
99
111
|
|
|
@@ -3,18 +3,19 @@ circup/backends.py,sha256=g9Q9xCGZidwsEDL2Ga2cm50YYB54IiqlKUPcxj-pWZA,40008
|
|
|
3
3
|
circup/bundle.py,sha256=FEP4F470aJtwmm8jgTM3DgR3dj5SVwbX1tbyIRKVHn8,5327
|
|
4
4
|
circup/command_utils.py,sha256=FNEhTYbbCT9UzKv4NG5lhbWHlObSEl4DQ7iDd8O0-cs,30581
|
|
5
5
|
circup/commands.py,sha256=jrgJDmqx4U1K--_OnZoOt1d9n1QRNnInK_nBeWrThMw,28542
|
|
6
|
+
circup/lazy_metadata.py,sha256=69VidxGGWE13QwAAtMCPNTXTsQ2q5dJvMtclw4YaqEY,3764
|
|
6
7
|
circup/logging.py,sha256=hu4v8ljkXo8ru-cqs0W3PU-xEVvTO_qqMKDJM18OXbQ,1115
|
|
7
8
|
circup/module.py,sha256=33_kdy5BZn6COyIjAFZMpw00rTtPiryQZWFXQkMF8FY,7435
|
|
8
|
-
circup/shared.py,sha256=
|
|
9
|
+
circup/shared.py,sha256=rribEZdoeyZRHxLiezyrDH0vb8DIP4bGOfMpRJm9M9w,9405
|
|
9
10
|
circup/config/bundle_config.json,sha256=zzpmfy0jD7TxpOOw2P_gqIISuMBG0enb_f3_VneQ5mI,135
|
|
10
11
|
circup/config/bundle_config.json.license,sha256=OOHNqDsViGFhmG9z8J0o98hYmub1CkYKiZB96Php6KE,80
|
|
11
12
|
circup/wwshell/README.rst,sha256=M_jFP0hwOcngF0RdosdeqmVOISNcPzyjTW3duzIu9A8,3617
|
|
12
13
|
circup/wwshell/README.rst.license,sha256=GhA0SoZGP7CReDam-JJk_UtIQIpQaZWQFzR26YSuMm4,107
|
|
13
14
|
circup/wwshell/__init__.py,sha256=CAPZiYrouWboyPx4KiWLBG_vf_n0MmArGqaFyTXGKWk,398
|
|
14
15
|
circup/wwshell/commands.py,sha256=-I5l7XeoDmvWWuZg5wHdt9qe__SBQ1EGmKwCDTBMeus,7454
|
|
15
|
-
circup-2.2.
|
|
16
|
-
circup-2.2.
|
|
17
|
-
circup-2.2.
|
|
18
|
-
circup-2.2.
|
|
19
|
-
circup-2.2.
|
|
20
|
-
circup-2.2.
|
|
16
|
+
circup-2.2.5.dist-info/licenses/LICENSE,sha256=bVlIMmSL_pqLCqae4hzixy9pYXD808IbgsMoQXTNLBk,1076
|
|
17
|
+
circup-2.2.5.dist-info/METADATA,sha256=c-lndR68LWDH1jMrnUFp4Lhscjx5pFAtvyWm-i9Z5aA,13617
|
|
18
|
+
circup-2.2.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
19
|
+
circup-2.2.5.dist-info/entry_points.txt,sha256=FjTmwYD_ApgLRGifUrr_Ui1voW6fEzodQc3DKNzoAPc,69
|
|
20
|
+
circup-2.2.5.dist-info/top_level.txt,sha256=Qx6E0eZgSBE10ciNKsLZx8-TTy_9fEVZh7NLmn24KcU,7
|
|
21
|
+
circup-2.2.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|