simstack 0.2.0__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.
- simstack/__init__.py +0 -0
- simstack/_version.py +34 -0
- simstack/core/__init__.py +0 -0
- simstack/core/artifacts.py +447 -0
- simstack/core/asnyc_helper.py +14 -0
- simstack/core/config_file.py +60 -0
- simstack/core/context.py +167 -0
- simstack/core/data.py +139 -0
- simstack/core/definitions.py +21 -0
- simstack/core/engine.py +116 -0
- simstack/core/find_simstack_modules.py +43 -0
- simstack/core/hash.py +177 -0
- simstack/core/model_table.py +199 -0
- simstack/core/node.py +911 -0
- simstack/core/node_runner.py +254 -0
- simstack/core/node_table.py +380 -0
- simstack/core/recompute_artifacts.py +120 -0
- simstack/core/reset_db.py +12 -0
- simstack/core/resources.py +101 -0
- simstack/core/run_node.py +69 -0
- simstack/core/runner.py +435 -0
- simstack/core/simstack_result.py +41 -0
- simstack/core/submit_node.py +143 -0
- simstack/core/task_id.py +22 -0
- simstack/data/__init__.py +0 -0
- simstack/methods/__init__.py +0 -0
- simstack/methods/get_file.py +10 -0
- simstack/methods/multiple_executor.py +307 -0
- simstack/models/__init__.py +37 -0
- simstack/models/array_list.py +48 -0
- simstack/models/array_storage.py +54 -0
- simstack/models/artifact_models.py +127 -0
- simstack/models/base_types.py +208 -0
- simstack/models/charts_artifact.py +411 -0
- simstack/models/dataset.py +432 -0
- simstack/models/dataset_metadata.py +303 -0
- simstack/models/file_instance.py +77 -0
- simstack/models/file_list.py +321 -0
- simstack/models/files.py +229 -0
- simstack/models/log_entry_model.py +37 -0
- simstack/models/models.py +40 -0
- simstack/models/node_registry.py +105 -0
- simstack/models/pandas_model.py +210 -0
- simstack/models/parameters.py +388 -0
- simstack/models/pickle_models.py +311 -0
- simstack/models/runner_model.py +39 -0
- simstack/models/simple_table.py +32 -0
- simstack/models/simstack_model.py +97 -0
- simstack/models/slurm_info.py +17 -0
- simstack/models/table_artifact.py +87 -0
- simstack/util/__init__.py +0 -0
- simstack/util/async_zip_utils.py +18 -0
- simstack/util/cleaned_json_schema.py +20 -0
- simstack/util/config_reader.py +273 -0
- simstack/util/custom_model_dump.py +75 -0
- simstack/util/db.py +457 -0
- simstack/util/db_logger.py +117 -0
- simstack/util/default_from_dict.py +57 -0
- simstack/util/directory_iterator.py +216 -0
- simstack/util/file_hashing.py +68 -0
- simstack/util/files.py +396 -0
- simstack/util/find_python_files.py +33 -0
- simstack/util/generate_ui_schema.py +80 -0
- simstack/util/geometry_utils.py +118 -0
- simstack/util/get_module_path.py +26 -0
- simstack/util/git_pull.py +65 -0
- simstack/util/git_repository_status.py +93 -0
- simstack/util/import_module.py +65 -0
- simstack/util/importer.py +163 -0
- simstack/util/make_graph.py +107 -0
- simstack/util/make_table.py +827 -0
- simstack/util/minimal_route_finder.py +72 -0
- simstack/util/mock_db.py +144 -0
- simstack/util/module_path_checker.py +38 -0
- simstack/util/path_manager.py +234 -0
- simstack/util/project_root_finder.py +36 -0
- simstack/util/queue_watcher.py +262 -0
- simstack/util/route_finder.py +74 -0
- simstack/util/runner_util.py +162 -0
- simstack/util/safe_code_executor.py +194 -0
- simstack/util/sample_config.py +98 -0
- simstack/util/sensitive_content_filter.py +48 -0
- simstack/util/setup_logging.py +49 -0
- simstack/util/submit_to_watchdog.py +106 -0
- simstack/util/ui_tools.py +213 -0
- simstack-0.2.0.dist-info/METADATA +361 -0
- simstack-0.2.0.dist-info/RECORD +91 -0
- simstack-0.2.0.dist-info/WHEEL +5 -0
- simstack-0.2.0.dist-info/entry_points.txt +10 -0
- simstack-0.2.0.dist-info/licenses/LICENSE +21 -0
- simstack-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import asyncio
|
|
3
|
+
import importlib
|
|
4
|
+
import inspect
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from simstack.core.find_simstack_modules import find_simstack_modules
|
|
11
|
+
from simstack.models.models import ModelMapping
|
|
12
|
+
from simstack.models.simstack_model import is_simstack_model
|
|
13
|
+
from simstack.util.import_module import import_module_from_file
|
|
14
|
+
from simstack.util.project_root_finder import find_project_root
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger("ModelTable")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class CreateModelTable:
|
|
20
|
+
"""
|
|
21
|
+
Helper class to build the model table without passing around many parameters.
|
|
22
|
+
|
|
23
|
+
Usage:
|
|
24
|
+
creator = CreateModelTable(engine)
|
|
25
|
+
await creator.make_model_table()
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, engine):
|
|
29
|
+
from simstack.core.context import context
|
|
30
|
+
|
|
31
|
+
# Ensure context is initialized and store frequently used objects
|
|
32
|
+
if not context.initialized:
|
|
33
|
+
context.initialize()
|
|
34
|
+
|
|
35
|
+
self.context = context
|
|
36
|
+
self.engine = engine
|
|
37
|
+
self.path_manager = context.path_manager
|
|
38
|
+
|
|
39
|
+
async def make_model_table(self):
|
|
40
|
+
"""Entry point to (re)build the model table."""
|
|
41
|
+
# First, process all simstack modules
|
|
42
|
+
all_modules = find_simstack_modules()
|
|
43
|
+
for module_name in all_modules:
|
|
44
|
+
logger.info(f"Processing module: {module_name}")
|
|
45
|
+
module = importlib.import_module(module_name)
|
|
46
|
+
await self._create_models_from_module(module, drops="")
|
|
47
|
+
|
|
48
|
+
# Then process all configured paths
|
|
49
|
+
for path_name in self.path_manager.paths.keys():
|
|
50
|
+
await self._make_models_for_path(path_name)
|
|
51
|
+
|
|
52
|
+
async def _create_model_models_from_file(self, file_path: str, drops: str):
|
|
53
|
+
"""Create ModelMapping entries for classes in the specified Python file."""
|
|
54
|
+
logger.debug(f"Processing models from: {file_path}")
|
|
55
|
+
module = import_module_from_file(Path(file_path))
|
|
56
|
+
if not module:
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
await self._create_models_from_module(module, drops)
|
|
60
|
+
|
|
61
|
+
async def _create_models_from_module(self, module, drops: str):
|
|
62
|
+
"""Create ModelMapping entries for all relevant classes in a module."""
|
|
63
|
+
classes = inspect.getmembers(module, inspect.isclass)
|
|
64
|
+
|
|
65
|
+
for class_name, new_class in classes:
|
|
66
|
+
# this is required because of the Odmantic Metaclass Model
|
|
67
|
+
# subclass does not work even if applied to the imported classes
|
|
68
|
+
# this is a bug in importlib
|
|
69
|
+
bases = [base.__name__ for base in new_class.__bases__]
|
|
70
|
+
is_ui_model = any("UIModel" in s for s in bases) or is_simstack_model(
|
|
71
|
+
new_class
|
|
72
|
+
)
|
|
73
|
+
is_model = any(s == "Model" for s in bases)
|
|
74
|
+
|
|
75
|
+
is_embedded_model = any(s == "EmbeddedModel" for s in bases)
|
|
76
|
+
|
|
77
|
+
if not (is_model or is_ui_model):
|
|
78
|
+
continue
|
|
79
|
+
if class_name == "Model":
|
|
80
|
+
continue
|
|
81
|
+
if new_class.__module__ != module.__name__:
|
|
82
|
+
continue
|
|
83
|
+
|
|
84
|
+
new_modules = new_class.__module__.split(".")
|
|
85
|
+
# Use drops from the path_info dictionary
|
|
86
|
+
if drops != "":
|
|
87
|
+
drop_modules = drops.split(".")
|
|
88
|
+
while (
|
|
89
|
+
new_modules and drop_modules and new_modules[0] == drop_modules[0]
|
|
90
|
+
):
|
|
91
|
+
new_modules.pop(0)
|
|
92
|
+
drop_modules.pop(0)
|
|
93
|
+
if len(drop_modules) > 0:
|
|
94
|
+
raise ValueError(
|
|
95
|
+
"drop modules not empty: ", drop_modules, new_class.__module__
|
|
96
|
+
)
|
|
97
|
+
full_mapping = ".".join(new_modules) + "." + class_name
|
|
98
|
+
logger.debug(f" Class: {class_name} Model Mapping: {full_mapping}")
|
|
99
|
+
|
|
100
|
+
# Remove any existing ModelMapping entry for this class
|
|
101
|
+
existing_entry = await self.engine.find_one(
|
|
102
|
+
ModelMapping, ModelMapping.name == class_name
|
|
103
|
+
)
|
|
104
|
+
if existing_entry is not None:
|
|
105
|
+
await self.engine.delete(existing_entry)
|
|
106
|
+
logger.debug(f"Deleted ModelMapping entry for {class_name}")
|
|
107
|
+
|
|
108
|
+
# EmbeddedModels have no collection by may be simstack_models. They are never saved/retrieved
|
|
109
|
+
collection_name = getattr(new_class, "__collection__", None)
|
|
110
|
+
if collection_name is None:
|
|
111
|
+
if is_embedded_model:
|
|
112
|
+
collection_name = f"EmbeddedModel"
|
|
113
|
+
else:
|
|
114
|
+
logger.error(f"No collection specified for {class_name}")
|
|
115
|
+
|
|
116
|
+
# Create the new ModelMapping entry (pickle functionality removed)
|
|
117
|
+
if is_ui_model:
|
|
118
|
+
model_entry = ModelMapping(
|
|
119
|
+
name=class_name,
|
|
120
|
+
mapping=full_mapping,
|
|
121
|
+
collection_name=collection_name,
|
|
122
|
+
json_schema=json.dumps(new_class.json_schema()),
|
|
123
|
+
ui_schema=json.dumps(new_class.ui_schema()),
|
|
124
|
+
route="",
|
|
125
|
+
)
|
|
126
|
+
logger.debug(f"SimStack Model: {class_name} Mapping: {full_mapping} Collection: {collection_name}")
|
|
127
|
+
# open a file in a subdirectory of the current file schema/model.json
|
|
128
|
+
project_root = find_project_root()
|
|
129
|
+
json_file_dir = os.path.join(project_root, "schema")
|
|
130
|
+
os.makedirs(json_file_dir, exist_ok=True)
|
|
131
|
+
combined_schema = {
|
|
132
|
+
"json_schema": new_class.json_schema(),
|
|
133
|
+
"ui_schema": new_class.ui_schema(),
|
|
134
|
+
}
|
|
135
|
+
with open(os.path.join(json_file_dir, class_name + ".json"), "w") as f:
|
|
136
|
+
f.write(json.dumps(combined_schema, indent=4))
|
|
137
|
+
else:
|
|
138
|
+
model_entry = ModelMapping(
|
|
139
|
+
name=class_name,
|
|
140
|
+
mapping=full_mapping,
|
|
141
|
+
collection_name=collection_name,
|
|
142
|
+
)
|
|
143
|
+
logger.debug(f"Model: {class_name} Mapping: {full_mapping} Collection: {collection_name}")
|
|
144
|
+
|
|
145
|
+
await self.engine.save(model_entry)
|
|
146
|
+
|
|
147
|
+
async def _make_models_for_path(self, path_name: str):
|
|
148
|
+
"""Build model mappings for all Python files under a configured path."""
|
|
149
|
+
path_info = self.path_manager.get_path(path_name)
|
|
150
|
+
path = path_info["path"]
|
|
151
|
+
drops = path_info["drops"]
|
|
152
|
+
logger.info(f"Making model_table entries for files in {path}")
|
|
153
|
+
|
|
154
|
+
# Process each file in this path
|
|
155
|
+
for file_path in self.path_manager.find_python_files(path_name):
|
|
156
|
+
await self._create_model_models_from_file(file_path, drops)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
# Public API preserved for existing callers (e.g. tests)
|
|
160
|
+
async def make_model_table(engine):
|
|
161
|
+
"""
|
|
162
|
+
Rebuild the model table using the given engine.
|
|
163
|
+
|
|
164
|
+
This is a thin wrapper around CreateModelTable for backward compatibility.
|
|
165
|
+
"""
|
|
166
|
+
creator = CreateModelTable(engine)
|
|
167
|
+
await creator.make_model_table()
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def create_model_table_main():
|
|
171
|
+
# Don't create a new loop with asyncio.run, use an existing one
|
|
172
|
+
parser = argparse.ArgumentParser()
|
|
173
|
+
parser.add_argument("-v", "--verbose", action="count", default=0)
|
|
174
|
+
args = parser.parse_args()
|
|
175
|
+
|
|
176
|
+
level = logging.WARNING
|
|
177
|
+
if args.verbose == 1:
|
|
178
|
+
level = logging.INFO
|
|
179
|
+
elif args.verbose >= 2:
|
|
180
|
+
level = logging.DEBUG
|
|
181
|
+
|
|
182
|
+
loop = asyncio.new_event_loop()
|
|
183
|
+
asyncio.set_event_loop(loop)
|
|
184
|
+
|
|
185
|
+
# Initialize context with this loop
|
|
186
|
+
from simstack.core.context import context
|
|
187
|
+
|
|
188
|
+
context.initialize(log_level=level)
|
|
189
|
+
|
|
190
|
+
# Set pymongo logger level to INFO
|
|
191
|
+
logging.getLogger("pymongo").setLevel(logging.INFO)
|
|
192
|
+
|
|
193
|
+
# Run in the same loop
|
|
194
|
+
loop.run_until_complete(make_model_table(context.db.engine))
|
|
195
|
+
loop.close()
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
if __name__ == "__main__":
|
|
199
|
+
create_model_table_main()
|