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.
Files changed (91) hide show
  1. simstack/__init__.py +0 -0
  2. simstack/_version.py +34 -0
  3. simstack/core/__init__.py +0 -0
  4. simstack/core/artifacts.py +447 -0
  5. simstack/core/asnyc_helper.py +14 -0
  6. simstack/core/config_file.py +60 -0
  7. simstack/core/context.py +167 -0
  8. simstack/core/data.py +139 -0
  9. simstack/core/definitions.py +21 -0
  10. simstack/core/engine.py +116 -0
  11. simstack/core/find_simstack_modules.py +43 -0
  12. simstack/core/hash.py +177 -0
  13. simstack/core/model_table.py +199 -0
  14. simstack/core/node.py +911 -0
  15. simstack/core/node_runner.py +254 -0
  16. simstack/core/node_table.py +380 -0
  17. simstack/core/recompute_artifacts.py +120 -0
  18. simstack/core/reset_db.py +12 -0
  19. simstack/core/resources.py +101 -0
  20. simstack/core/run_node.py +69 -0
  21. simstack/core/runner.py +435 -0
  22. simstack/core/simstack_result.py +41 -0
  23. simstack/core/submit_node.py +143 -0
  24. simstack/core/task_id.py +22 -0
  25. simstack/data/__init__.py +0 -0
  26. simstack/methods/__init__.py +0 -0
  27. simstack/methods/get_file.py +10 -0
  28. simstack/methods/multiple_executor.py +307 -0
  29. simstack/models/__init__.py +37 -0
  30. simstack/models/array_list.py +48 -0
  31. simstack/models/array_storage.py +54 -0
  32. simstack/models/artifact_models.py +127 -0
  33. simstack/models/base_types.py +208 -0
  34. simstack/models/charts_artifact.py +411 -0
  35. simstack/models/dataset.py +432 -0
  36. simstack/models/dataset_metadata.py +303 -0
  37. simstack/models/file_instance.py +77 -0
  38. simstack/models/file_list.py +321 -0
  39. simstack/models/files.py +229 -0
  40. simstack/models/log_entry_model.py +37 -0
  41. simstack/models/models.py +40 -0
  42. simstack/models/node_registry.py +105 -0
  43. simstack/models/pandas_model.py +210 -0
  44. simstack/models/parameters.py +388 -0
  45. simstack/models/pickle_models.py +311 -0
  46. simstack/models/runner_model.py +39 -0
  47. simstack/models/simple_table.py +32 -0
  48. simstack/models/simstack_model.py +97 -0
  49. simstack/models/slurm_info.py +17 -0
  50. simstack/models/table_artifact.py +87 -0
  51. simstack/util/__init__.py +0 -0
  52. simstack/util/async_zip_utils.py +18 -0
  53. simstack/util/cleaned_json_schema.py +20 -0
  54. simstack/util/config_reader.py +273 -0
  55. simstack/util/custom_model_dump.py +75 -0
  56. simstack/util/db.py +457 -0
  57. simstack/util/db_logger.py +117 -0
  58. simstack/util/default_from_dict.py +57 -0
  59. simstack/util/directory_iterator.py +216 -0
  60. simstack/util/file_hashing.py +68 -0
  61. simstack/util/files.py +396 -0
  62. simstack/util/find_python_files.py +33 -0
  63. simstack/util/generate_ui_schema.py +80 -0
  64. simstack/util/geometry_utils.py +118 -0
  65. simstack/util/get_module_path.py +26 -0
  66. simstack/util/git_pull.py +65 -0
  67. simstack/util/git_repository_status.py +93 -0
  68. simstack/util/import_module.py +65 -0
  69. simstack/util/importer.py +163 -0
  70. simstack/util/make_graph.py +107 -0
  71. simstack/util/make_table.py +827 -0
  72. simstack/util/minimal_route_finder.py +72 -0
  73. simstack/util/mock_db.py +144 -0
  74. simstack/util/module_path_checker.py +38 -0
  75. simstack/util/path_manager.py +234 -0
  76. simstack/util/project_root_finder.py +36 -0
  77. simstack/util/queue_watcher.py +262 -0
  78. simstack/util/route_finder.py +74 -0
  79. simstack/util/runner_util.py +162 -0
  80. simstack/util/safe_code_executor.py +194 -0
  81. simstack/util/sample_config.py +98 -0
  82. simstack/util/sensitive_content_filter.py +48 -0
  83. simstack/util/setup_logging.py +49 -0
  84. simstack/util/submit_to_watchdog.py +106 -0
  85. simstack/util/ui_tools.py +213 -0
  86. simstack-0.2.0.dist-info/METADATA +361 -0
  87. simstack-0.2.0.dist-info/RECORD +91 -0
  88. simstack-0.2.0.dist-info/WHEEL +5 -0
  89. simstack-0.2.0.dist-info/entry_points.txt +10 -0
  90. simstack-0.2.0.dist-info/licenses/LICENSE +21 -0
  91. 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()