hwcomponents 1.0.81__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.
- hwcomponents/__init__.py +10 -0
- hwcomponents/_logging.py +99 -0
- hwcomponents/_model_wrapper.py +461 -0
- hwcomponents/_util.py +14 -0
- hwcomponents/_version.py +34 -0
- hwcomponents/_version_scheme.py +23 -0
- hwcomponents/find_models.py +250 -0
- hwcomponents/hwcomponents.py +77 -0
- hwcomponents/model.py +547 -0
- hwcomponents/scaling/__init__.py +7 -0
- hwcomponents/scaling/scalefuncs.py +119 -0
- hwcomponents/scaling/techscaling.py +185 -0
- hwcomponents/select_models.py +466 -0
- hwcomponents-1.0.81.dist-info/METADATA +34 -0
- hwcomponents-1.0.81.dist-info/RECORD +19 -0
- hwcomponents-1.0.81.dist-info/WHEEL +5 -0
- hwcomponents-1.0.81.dist-info/entry_points.txt +3 -0
- hwcomponents-1.0.81.dist-info/top_level.txt +1 -0
- hwcomponents-1.0.81.dist-info/zip-safe +1 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import glob
|
|
2
|
+
import importlib
|
|
3
|
+
from importlib.machinery import SourceFileLoader
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from types import ModuleType
|
|
6
|
+
from typing import List, Set, Union
|
|
7
|
+
from hwcomponents._model_wrapper import ComponentModelWrapper, ComponentModel
|
|
8
|
+
import inspect
|
|
9
|
+
import logging
|
|
10
|
+
import copy
|
|
11
|
+
import sys
|
|
12
|
+
import os
|
|
13
|
+
from pkgutil import iter_modules
|
|
14
|
+
|
|
15
|
+
_ALL_ESTIMATORS = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def installed_models(
|
|
19
|
+
_return_wrappers: bool = False,
|
|
20
|
+
) -> List[ComponentModelWrapper] | List[ComponentModel]:
|
|
21
|
+
"""
|
|
22
|
+
Lists all Python packages installed that are prefixed with "hwcomponents_". Finds
|
|
23
|
+
ComponentModel subclasses in these packages and returns them as
|
|
24
|
+
ComponentModel or ComponentModelWrapper objects.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
_return_wrappers : bool
|
|
29
|
+
Whether to return ComponentModelWrapper objects or
|
|
30
|
+
ComponentModel objects.
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
A list of ComponentModel or ComponentModelWrapper objects.
|
|
35
|
+
"""
|
|
36
|
+
# List all Python packages installed that are prefixed with "hwcomponents_"
|
|
37
|
+
global _ALL_ESTIMATORS
|
|
38
|
+
if _ALL_ESTIMATORS is not None:
|
|
39
|
+
return _ALL_ESTIMATORS
|
|
40
|
+
|
|
41
|
+
modules = [p.name for p in iter_modules() if p.name.startswith("hwcomponents_")]
|
|
42
|
+
for m in modules:
|
|
43
|
+
logging.info(f"Importing from module: {m}")
|
|
44
|
+
|
|
45
|
+
models = []
|
|
46
|
+
model_ids = set()
|
|
47
|
+
|
|
48
|
+
# Handle the packages
|
|
49
|
+
for module in modules:
|
|
50
|
+
models.extend(
|
|
51
|
+
get_models_in_module(
|
|
52
|
+
importlib.import_module(module),
|
|
53
|
+
model_ids,
|
|
54
|
+
_return_wrappers,
|
|
55
|
+
)
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
_ALL_ESTIMATORS = models
|
|
59
|
+
|
|
60
|
+
return models
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_models_in_module(
|
|
64
|
+
module: ModuleType,
|
|
65
|
+
model_ids: Set,
|
|
66
|
+
_return_wrappers: bool = False,
|
|
67
|
+
) -> List[ComponentModelWrapper] | List[ComponentModel]:
|
|
68
|
+
"""
|
|
69
|
+
Finds all ComponentModel subclasses in a module and returns them as
|
|
70
|
+
ComponentModelWrapper objects. Ignores underscore-prefixed classes.
|
|
71
|
+
|
|
72
|
+
Parameters
|
|
73
|
+
----------
|
|
74
|
+
model_ids : set
|
|
75
|
+
A set of model IDs to avoid duplicates.
|
|
76
|
+
_return_wrappers : bool
|
|
77
|
+
Whether to return ComponentModelWrapper objects or ComponentModel objects.
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
A list of ComponentModelWrapper objects.
|
|
82
|
+
|
|
83
|
+
"""
|
|
84
|
+
logging.info(f"Getting models in module: {module.__name__}")
|
|
85
|
+
classes = [
|
|
86
|
+
(x, name) for name in dir(module) if inspect.isclass(x := getattr(module, name))
|
|
87
|
+
]
|
|
88
|
+
classes = [(x, name) for x, name in classes if not name.startswith("_")]
|
|
89
|
+
found = []
|
|
90
|
+
for x, name in classes:
|
|
91
|
+
superclasses = [c.__name__ for c in inspect.getmro(x)]
|
|
92
|
+
|
|
93
|
+
if (
|
|
94
|
+
any(base in superclasses for base in ["ComponentModel", "Model"])
|
|
95
|
+
and not inspect.isabstract(x)
|
|
96
|
+
and id(x) not in model_ids
|
|
97
|
+
):
|
|
98
|
+
model_ids.add(id(x))
|
|
99
|
+
if _return_wrappers:
|
|
100
|
+
found.append(ComponentModelWrapper(x, name))
|
|
101
|
+
else:
|
|
102
|
+
found.append(x)
|
|
103
|
+
return found
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def get_models(
|
|
107
|
+
*paths_or_packages_or_models: Union[
|
|
108
|
+
str, List[str], List[List[str]], ComponentModel
|
|
109
|
+
],
|
|
110
|
+
include_installed: bool = True,
|
|
111
|
+
name_must_include: str = "",
|
|
112
|
+
_return_wrappers: bool = False,
|
|
113
|
+
) -> List[ComponentModelWrapper] | List[ComponentModel]:
|
|
114
|
+
"""
|
|
115
|
+
Instantiate a list of model objects for later queries. Searches for models in the
|
|
116
|
+
given paths and packages.
|
|
117
|
+
|
|
118
|
+
Parameters
|
|
119
|
+
----------
|
|
120
|
+
paths_or_packages_or_models : list
|
|
121
|
+
A list of paths or packages to search for models.
|
|
122
|
+
include_installed : bool
|
|
123
|
+
Whether to include models from installed packages.
|
|
124
|
+
name_must_include : str
|
|
125
|
+
If provided, a model will only be returned if its name includes this string.
|
|
126
|
+
Non-case-sensitive.
|
|
127
|
+
_return_wrappers : bool
|
|
128
|
+
Whether to return ComponentModelWrapper objects or
|
|
129
|
+
ComponentModel objects.
|
|
130
|
+
|
|
131
|
+
Returns
|
|
132
|
+
-------
|
|
133
|
+
A list of ComponentModelWrapper objects or ComponentModel objects.
|
|
134
|
+
"""
|
|
135
|
+
model_ids = set()
|
|
136
|
+
n_models = 0
|
|
137
|
+
|
|
138
|
+
packages = []
|
|
139
|
+
paths = []
|
|
140
|
+
models = []
|
|
141
|
+
|
|
142
|
+
flattened = []
|
|
143
|
+
|
|
144
|
+
to_check = list(paths_or_packages_or_models)
|
|
145
|
+
|
|
146
|
+
i = 0
|
|
147
|
+
while i < len(to_check):
|
|
148
|
+
path_or_package = to_check[i]
|
|
149
|
+
i += 1
|
|
150
|
+
if isinstance(path_or_package, (list, tuple)):
|
|
151
|
+
to_check.extend(path_or_package)
|
|
152
|
+
elif isinstance(path_or_package, type) and issubclass(
|
|
153
|
+
path_or_package, ComponentModel
|
|
154
|
+
):
|
|
155
|
+
models.append(path_or_package)
|
|
156
|
+
elif isinstance(path_or_package, (str, Path)):
|
|
157
|
+
globbed = glob.glob(path_or_package, recursive=True)
|
|
158
|
+
flattened.extend(globbed)
|
|
159
|
+
else:
|
|
160
|
+
raise ValueError(f"Invalid type: {type(path_or_package)}")
|
|
161
|
+
|
|
162
|
+
if _return_wrappers:
|
|
163
|
+
models = [ComponentModelWrapper(m, m.__name__) for m in models]
|
|
164
|
+
|
|
165
|
+
models.extend(installed_models(_return_wrappers) if include_installed else [])
|
|
166
|
+
|
|
167
|
+
for path_or_package in flattened:
|
|
168
|
+
# Check if it's a package first
|
|
169
|
+
try:
|
|
170
|
+
importlib.import_module(path_or_package)
|
|
171
|
+
packages.append(path_or_package)
|
|
172
|
+
except (ImportError, TypeError):
|
|
173
|
+
# If not, check if it's a file
|
|
174
|
+
if os.path.isfile(path_or_package):
|
|
175
|
+
assert path_or_package.endswith(
|
|
176
|
+
".py"
|
|
177
|
+
), f"Path {path_or_package} is not a Python file"
|
|
178
|
+
paths.append(path_or_package)
|
|
179
|
+
else:
|
|
180
|
+
raise ValueError(
|
|
181
|
+
f"Path {path_or_package} is not a valid file or package"
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
for package in packages:
|
|
185
|
+
models.extend(
|
|
186
|
+
get_models_in_module(
|
|
187
|
+
importlib.import_module(package),
|
|
188
|
+
model_ids,
|
|
189
|
+
_return_wrappers,
|
|
190
|
+
)
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# Handle the paths
|
|
194
|
+
paths_globbed = []
|
|
195
|
+
allpaths = []
|
|
196
|
+
for p in paths:
|
|
197
|
+
if isinstance(p, list):
|
|
198
|
+
allpaths.extend(p)
|
|
199
|
+
else:
|
|
200
|
+
allpaths.append(p)
|
|
201
|
+
|
|
202
|
+
for p in allpaths:
|
|
203
|
+
logging.info(f"Checking path: {p}")
|
|
204
|
+
newpaths = []
|
|
205
|
+
if os.path.isfile(p):
|
|
206
|
+
assert p.endswith(".py"), f"Path {p} is not a Python file"
|
|
207
|
+
newpaths.append(p)
|
|
208
|
+
else:
|
|
209
|
+
newpaths += list(glob.glob(p, recursive=True))
|
|
210
|
+
newpaths += list(glob.glob(os.path.join(p, "**"), recursive=True))
|
|
211
|
+
paths_globbed.extend(newpaths)
|
|
212
|
+
if not newpaths:
|
|
213
|
+
raise ValueError(
|
|
214
|
+
f"Path {p} does not have any Python files. Please check the path and "
|
|
215
|
+
f"try again."
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
newpaths = [p.rstrip("/") for p in newpaths]
|
|
219
|
+
newpaths = [p.replace("\\", "/") for p in newpaths]
|
|
220
|
+
newpaths = [p.replace("//", "/") for p in newpaths]
|
|
221
|
+
newpaths = [p for p in newpaths if p.endswith(".py")]
|
|
222
|
+
newpaths = [p for p in newpaths if not p.endswith("setup.py")]
|
|
223
|
+
newpaths = [p for p in newpaths if not p.endswith("__init__.py")]
|
|
224
|
+
|
|
225
|
+
new_models = []
|
|
226
|
+
for path in newpaths:
|
|
227
|
+
logging.info(
|
|
228
|
+
f"Loading models from {path}. Errors below are likely due to the model."
|
|
229
|
+
)
|
|
230
|
+
prev_sys_path = copy.deepcopy(sys.path)
|
|
231
|
+
sys.path.append(os.path.dirname(os.path.abspath(path)))
|
|
232
|
+
python_module = SourceFileLoader(f"model{n_models}", path).load_module()
|
|
233
|
+
new_models += get_models_in_module(
|
|
234
|
+
python_module, model_ids, _return_wrappers
|
|
235
|
+
)
|
|
236
|
+
sys.path = prev_sys_path
|
|
237
|
+
n_models += 1
|
|
238
|
+
|
|
239
|
+
if not new_models:
|
|
240
|
+
raise ValueError(f"No models found in {p}")
|
|
241
|
+
|
|
242
|
+
models.extend(new_models)
|
|
243
|
+
|
|
244
|
+
if _return_wrappers:
|
|
245
|
+
models = [
|
|
246
|
+
m for m in models if name_must_include.lower() in m.model_name.lower()
|
|
247
|
+
]
|
|
248
|
+
return sorted(models, key=lambda x: x.model_name)
|
|
249
|
+
models = [m for m in models if name_must_include.lower() in m.__name__.lower()]
|
|
250
|
+
return sorted(models, key=lambda x: x.__name__)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
from hwcomponents.find_models import get_models
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def list_components(printfunc=print):
|
|
6
|
+
"""
|
|
7
|
+
Lists all available components.
|
|
8
|
+
|
|
9
|
+
Parameters
|
|
10
|
+
----------
|
|
11
|
+
printfunc : Callable[[str], None]
|
|
12
|
+
The function to use to print the components.
|
|
13
|
+
|
|
14
|
+
Returns
|
|
15
|
+
-------
|
|
16
|
+
None
|
|
17
|
+
"""
|
|
18
|
+
printfunc("\n")
|
|
19
|
+
printfunc("Supported Components:")
|
|
20
|
+
|
|
21
|
+
class Entry:
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
name: str,
|
|
25
|
+
class_name: str,
|
|
26
|
+
init_function: str,
|
|
27
|
+
actions: list[str],
|
|
28
|
+
):
|
|
29
|
+
self.name = name
|
|
30
|
+
self.class_name = class_name
|
|
31
|
+
self.init_function = init_function
|
|
32
|
+
self.actions = actions
|
|
33
|
+
|
|
34
|
+
def __str__(self):
|
|
35
|
+
return (
|
|
36
|
+
f"{self.class_name}{self.init_function} from class {self.name} \n"
|
|
37
|
+
+ "\n".join(f"\t{a}" for a in self.actions)
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
entries = []
|
|
41
|
+
for model in get_models(_return_wrappers=True):
|
|
42
|
+
|
|
43
|
+
def add_entry(name, class_names, init_func, actions):
|
|
44
|
+
class_names = [class_names] if isinstance(class_names, str) else class_names
|
|
45
|
+
entries.append(
|
|
46
|
+
(class_names[0], Entry(name, class_names[0], str(init_func), actions))
|
|
47
|
+
)
|
|
48
|
+
for c in class_names[1:]:
|
|
49
|
+
entries.append(
|
|
50
|
+
(c, f"{c}: alias for {name} from class {class_names[0]}")
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
add_entry(
|
|
54
|
+
model.get_name(),
|
|
55
|
+
model.get_component_names(),
|
|
56
|
+
str(model.init_function),
|
|
57
|
+
model.actions,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
entries = sorted(entries, key=lambda x: x[0].lower())
|
|
61
|
+
for entry in entries:
|
|
62
|
+
printfunc(entry[1])
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _main():
|
|
66
|
+
parser = argparse.ArgumentParser()
|
|
67
|
+
parser.add_argument(
|
|
68
|
+
"--list", action="store_true", help="List all available components"
|
|
69
|
+
)
|
|
70
|
+
args = parser.parse_args()
|
|
71
|
+
|
|
72
|
+
if args.list:
|
|
73
|
+
list_components()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
if __name__ == "__main__":
|
|
77
|
+
_main()
|