aiverify-moonshot 0.4.1__py3-none-any.whl → 0.4.2__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.
- {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/METADATA +2 -2
- {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/RECORD +59 -49
- moonshot/__main__.py +77 -35
- moonshot/api.py +14 -0
- moonshot/integrations/cli/benchmark/benchmark.py +29 -13
- moonshot/integrations/cli/benchmark/cookbook.py +36 -6
- moonshot/integrations/cli/benchmark/datasets.py +33 -3
- moonshot/integrations/cli/benchmark/metrics.py +33 -3
- moonshot/integrations/cli/benchmark/recipe.py +36 -6
- moonshot/integrations/cli/benchmark/result.py +33 -3
- moonshot/integrations/cli/benchmark/run.py +34 -3
- moonshot/integrations/cli/common/common.py +12 -6
- moonshot/integrations/cli/common/connectors.py +73 -9
- moonshot/integrations/cli/common/prompt_template.py +38 -3
- moonshot/integrations/cli/redteam/attack_module.py +75 -24
- moonshot/integrations/cli/redteam/context_strategy.py +77 -23
- moonshot/integrations/cli/redteam/prompt_template.py +1 -1
- moonshot/integrations/cli/redteam/redteam.py +52 -6
- moonshot/integrations/cli/redteam/session.py +539 -43
- moonshot/integrations/web_api/__main__.py +2 -0
- moonshot/integrations/web_api/app.py +6 -6
- moonshot/integrations/web_api/container.py +12 -2
- moonshot/integrations/web_api/routes/bookmark.py +173 -0
- moonshot/integrations/web_api/schemas/bookmark_create_dto.py +13 -0
- moonshot/integrations/web_api/services/bookmark_service.py +90 -0
- moonshot/integrations/web_api/services/utils/file_manager.py +52 -0
- moonshot/integrations/web_api/status_updater/moonshot_ui_webhook.py +0 -1
- moonshot/integrations/web_api/temp/.gitkeep +0 -0
- moonshot/src/api/api_bookmark.py +95 -0
- moonshot/src/api/api_connector_endpoint.py +1 -1
- moonshot/src/api/api_context_strategy.py +2 -2
- moonshot/src/api/api_session.py +1 -1
- moonshot/src/bookmark/bookmark.py +257 -0
- moonshot/src/bookmark/bookmark_arguments.py +38 -0
- moonshot/src/configs/env_variables.py +12 -2
- moonshot/src/connectors/connector.py +15 -7
- moonshot/src/connectors_endpoints/connector_endpoint.py +65 -49
- moonshot/src/cookbooks/cookbook.py +57 -37
- moonshot/src/datasets/dataset.py +9 -5
- moonshot/src/metrics/metric.py +8 -4
- moonshot/src/metrics/metric_interface.py +8 -2
- moonshot/src/prompt_templates/prompt_template.py +5 -1
- moonshot/src/recipes/recipe.py +38 -25
- moonshot/src/redteaming/attack/attack_module.py +18 -8
- moonshot/src/redteaming/attack/context_strategy.py +6 -2
- moonshot/src/redteaming/session/session.py +15 -11
- moonshot/src/results/result.py +7 -3
- moonshot/src/runners/runner.py +65 -42
- moonshot/src/runs/run.py +15 -11
- moonshot/src/runs/run_progress.py +7 -3
- moonshot/src/storage/db_interface.py +14 -0
- moonshot/src/storage/storage.py +33 -2
- moonshot/src/utils/find_feature.py +45 -0
- moonshot/src/utils/log.py +66 -0
- moonshot/src/utils/timeit.py +8 -1
- {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/WHEEL +0 -0
- {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/licenses/AUTHORS.md +0 -0
- {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/licenses/LICENSE.md +0 -0
- {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/licenses/NOTICES.md +0 -0
|
@@ -17,6 +17,10 @@ from moonshot.src.runs.run_status import RunStatus
|
|
|
17
17
|
from moonshot.src.storage.db_interface import DBInterface
|
|
18
18
|
from moonshot.src.storage.storage import Storage
|
|
19
19
|
from moonshot.src.utils.import_modules import get_instance
|
|
20
|
+
from moonshot.src.utils.log import configure_logger
|
|
21
|
+
|
|
22
|
+
# Create a logger for this module
|
|
23
|
+
logger = configure_logger(__name__)
|
|
20
24
|
|
|
21
25
|
|
|
22
26
|
class SessionMetadata:
|
|
@@ -283,13 +287,13 @@ class Session:
|
|
|
283
287
|
|
|
284
288
|
# check if the session metadata record already exists
|
|
285
289
|
if session_metadata_records:
|
|
286
|
-
|
|
290
|
+
logger.info("[Session] Session already exists.")
|
|
287
291
|
self.session_metadata = SessionMetadata.from_tuple(
|
|
288
292
|
session_metadata_records[0]
|
|
289
293
|
)
|
|
290
294
|
# create a new record if session metadata does not exist
|
|
291
295
|
else:
|
|
292
|
-
|
|
296
|
+
logger.info("[Session] Creating new session.")
|
|
293
297
|
|
|
294
298
|
# create chat history table for each endpoint
|
|
295
299
|
|
|
@@ -379,13 +383,13 @@ class Session:
|
|
|
379
383
|
# ------------------------------------------------------------------------------
|
|
380
384
|
# Part 1: Get asyncio running loop
|
|
381
385
|
# ------------------------------------------------------------------------------
|
|
382
|
-
|
|
386
|
+
logger.debug("[Session] Part 1: Loading asyncio running loop...")
|
|
383
387
|
loop = asyncio.get_running_loop()
|
|
384
388
|
|
|
385
389
|
# ------------------------------------------------------------------------------
|
|
386
390
|
# Part 2: Load runner processing module
|
|
387
391
|
# ------------------------------------------------------------------------------
|
|
388
|
-
|
|
392
|
+
logger.debug("[Session] Part 2: Loading runner processing module...")
|
|
389
393
|
start_time = time.perf_counter()
|
|
390
394
|
runner_module_instance = None
|
|
391
395
|
try:
|
|
@@ -414,20 +418,20 @@ class Session:
|
|
|
414
418
|
)
|
|
415
419
|
|
|
416
420
|
except Exception as e:
|
|
417
|
-
|
|
421
|
+
logger.error(
|
|
418
422
|
f"[Session] Failed to load runner processing module in Part 2 due to error: {str(e)}"
|
|
419
423
|
)
|
|
420
424
|
raise e
|
|
421
425
|
|
|
422
426
|
finally:
|
|
423
|
-
|
|
427
|
+
logger.debug(
|
|
424
428
|
f"[Session] Loading runner processing module took {(time.perf_counter() - start_time):.4f}s"
|
|
425
429
|
)
|
|
426
430
|
|
|
427
431
|
# ------------------------------------------------------------------------------
|
|
428
432
|
# Part 3: Run runner processing module
|
|
429
433
|
# ------------------------------------------------------------------------------
|
|
430
|
-
|
|
434
|
+
logger.debug("[Session] Part 3: Running runner processing module...")
|
|
431
435
|
start_time = time.perf_counter()
|
|
432
436
|
runner_results = {}
|
|
433
437
|
|
|
@@ -446,7 +450,7 @@ class Session:
|
|
|
446
450
|
raise RuntimeError("Failed to initialise runner module instance.")
|
|
447
451
|
|
|
448
452
|
except Exception as e:
|
|
449
|
-
|
|
453
|
+
logger.error(
|
|
450
454
|
f"[Session] Failed to run runner processing module in Part 3 due to error: {str(e)}"
|
|
451
455
|
)
|
|
452
456
|
raise e
|
|
@@ -455,14 +459,14 @@ class Session:
|
|
|
455
459
|
self.red_teaming_progress.status = RunStatus.COMPLETED
|
|
456
460
|
if self.check_redteaming_type() == RedTeamingType.AUTOMATED:
|
|
457
461
|
self.red_teaming_progress.notify_progress()
|
|
458
|
-
|
|
462
|
+
logger.debug(
|
|
459
463
|
f"[Session] Running runner processing module took {(time.perf_counter() - start_time):.4f}s"
|
|
460
464
|
)
|
|
461
465
|
|
|
462
466
|
# ------------------------------------------------------------------------------
|
|
463
467
|
# Part 4: Wrap up run
|
|
464
468
|
# ------------------------------------------------------------------------------
|
|
465
|
-
|
|
469
|
+
logger.debug("[Session] Part 4: Wrap up run...")
|
|
466
470
|
return runner_results
|
|
467
471
|
|
|
468
472
|
def cancel(self) -> None:
|
|
@@ -476,7 +480,7 @@ class Session:
|
|
|
476
480
|
Returns:
|
|
477
481
|
None
|
|
478
482
|
"""
|
|
479
|
-
|
|
483
|
+
logger.warning("[Session] Cancelling automated red teaming...")
|
|
480
484
|
self.cancel_event.set()
|
|
481
485
|
|
|
482
486
|
def check_redteaming_type(self) -> RedTeamingType:
|
moonshot/src/results/result.py
CHANGED
|
@@ -6,6 +6,10 @@ from pydantic import validate_call
|
|
|
6
6
|
|
|
7
7
|
from moonshot.src.configs.env_variables import EnvVariables
|
|
8
8
|
from moonshot.src.storage.storage import Storage
|
|
9
|
+
from moonshot.src.utils.log import configure_logger
|
|
10
|
+
|
|
11
|
+
# Create a logger for this module
|
|
12
|
+
logger = configure_logger(__name__)
|
|
9
13
|
|
|
10
14
|
|
|
11
15
|
class Result:
|
|
@@ -35,7 +39,7 @@ class Result:
|
|
|
35
39
|
raise RuntimeError("Result ID is empty")
|
|
36
40
|
|
|
37
41
|
except Exception as e:
|
|
38
|
-
|
|
42
|
+
logger.error(f"Failed to read result: {str(e)}")
|
|
39
43
|
raise e
|
|
40
44
|
|
|
41
45
|
@staticmethod
|
|
@@ -85,7 +89,7 @@ class Result:
|
|
|
85
89
|
return True
|
|
86
90
|
|
|
87
91
|
except Exception as e:
|
|
88
|
-
|
|
92
|
+
logger.error(f"Failed to delete result: {str(e)}")
|
|
89
93
|
raise e
|
|
90
94
|
|
|
91
95
|
@staticmethod
|
|
@@ -115,5 +119,5 @@ class Result:
|
|
|
115
119
|
return retn_results_ids, retn_results
|
|
116
120
|
|
|
117
121
|
except Exception as e:
|
|
118
|
-
|
|
122
|
+
logger.error(f"Failed to get available results: {str(e)}")
|
|
119
123
|
raise e
|
moonshot/src/runners/runner.py
CHANGED
|
@@ -13,6 +13,10 @@ from moonshot.src.runners.runner_arguments import RunnerArguments
|
|
|
13
13
|
from moonshot.src.runners.runner_type import RunnerType
|
|
14
14
|
from moonshot.src.runs.run import Run
|
|
15
15
|
from moonshot.src.storage.storage import Storage
|
|
16
|
+
from moonshot.src.utils.log import configure_logger
|
|
17
|
+
|
|
18
|
+
# Create a logger for this module
|
|
19
|
+
logger = configure_logger(__name__)
|
|
16
20
|
|
|
17
21
|
|
|
18
22
|
class Runner:
|
|
@@ -82,13 +86,13 @@ class Runner:
|
|
|
82
86
|
)
|
|
83
87
|
runner_args = Runner.read(runner_id)
|
|
84
88
|
runner_args.database_instance = Storage.create_database_connection(
|
|
85
|
-
EnvVariables.DATABASES.name,
|
|
89
|
+
EnvVariables.DATABASES.name, Path(runner_args.database_file).stem, "db"
|
|
86
90
|
)
|
|
87
91
|
runner_args.progress_callback_func = progress_callback_func
|
|
88
92
|
return cls(runner_args)
|
|
89
93
|
|
|
90
94
|
except Exception as e:
|
|
91
|
-
|
|
95
|
+
logger.error(f"[Runner] Failed to load runner: {str(e)}")
|
|
92
96
|
raise e
|
|
93
97
|
|
|
94
98
|
@classmethod
|
|
@@ -114,6 +118,14 @@ class Runner:
|
|
|
114
118
|
"""
|
|
115
119
|
try:
|
|
116
120
|
runner_id = slugify(runner_args.name, lowercase=True)
|
|
121
|
+
runner_info = {
|
|
122
|
+
"name": runner_args.name,
|
|
123
|
+
"database_file": Storage.get_filepath(
|
|
124
|
+
EnvVariables.DATABASES.name, runner_id, "db", True
|
|
125
|
+
),
|
|
126
|
+
"endpoints": runner_args.endpoints,
|
|
127
|
+
"description": runner_args.description,
|
|
128
|
+
}
|
|
117
129
|
|
|
118
130
|
# Check if runner file exists. If it exists, raise an error.
|
|
119
131
|
if Storage.is_object_exists(EnvVariables.RUNNERS.name, runner_id, "json"):
|
|
@@ -129,35 +141,27 @@ class Runner:
|
|
|
129
141
|
f"[Runner] Connector endpoint {endpoint} does not exist."
|
|
130
142
|
)
|
|
131
143
|
|
|
132
|
-
runner_info = {
|
|
133
|
-
"id": runner_id,
|
|
134
|
-
"name": runner_args.name,
|
|
135
|
-
"endpoints": runner_args.endpoints,
|
|
136
|
-
"database_file": Storage.get_filepath(
|
|
137
|
-
EnvVariables.DATABASES.name, runner_id, "db", True
|
|
138
|
-
),
|
|
139
|
-
"progress_callback_func": runner_args.progress_callback_func,
|
|
140
|
-
"description": runner_args.description,
|
|
141
|
-
}
|
|
142
|
-
runner_args = RunnerArguments(**runner_info)
|
|
143
|
-
runner_args.database_instance = Storage.create_database_connection(
|
|
144
|
-
EnvVariables.DATABASES.name, runner_id, "db"
|
|
145
|
-
)
|
|
146
|
-
|
|
147
144
|
# Create runner file
|
|
148
145
|
Storage.create_object(
|
|
149
|
-
EnvVariables.RUNNERS.name, runner_id,
|
|
146
|
+
EnvVariables.RUNNERS.name, runner_id, runner_info, "json"
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# Add additional attributes (id, database instance and update progress_callback_func)
|
|
150
|
+
runner_info["id"] = runner_id
|
|
151
|
+
runner_info["database_instance"] = Storage.create_database_connection(
|
|
152
|
+
EnvVariables.DATABASES.name, runner_id, "db"
|
|
150
153
|
)
|
|
154
|
+
runner_info["progress_callback_func"] = runner_args.progress_callback_func
|
|
151
155
|
|
|
152
156
|
# Create runner cache table
|
|
153
157
|
Storage.create_database_table(
|
|
154
|
-
|
|
158
|
+
runner_info["database_instance"], Runner.sql_create_runner_cache_table
|
|
155
159
|
)
|
|
156
160
|
|
|
157
|
-
return cls(
|
|
161
|
+
return cls(RunnerArguments(**runner_info))
|
|
158
162
|
|
|
159
163
|
except Exception as e:
|
|
160
|
-
|
|
164
|
+
logger.error(f"[Runner] Failed to create runner: {str(e)}")
|
|
161
165
|
raise e
|
|
162
166
|
|
|
163
167
|
@staticmethod
|
|
@@ -179,17 +183,40 @@ class Runner:
|
|
|
179
183
|
Exception: If an error occurs during the data retrieval or any other operation within the method.
|
|
180
184
|
"""
|
|
181
185
|
try:
|
|
182
|
-
if runner_id:
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
raise RuntimeError("Runner ID
|
|
186
|
+
if not runner_id:
|
|
187
|
+
raise RuntimeError("Runner ID is empty.")
|
|
188
|
+
|
|
189
|
+
runner_details = Runner._read_runner(runner_id)
|
|
190
|
+
if not runner_details:
|
|
191
|
+
raise RuntimeError(f"Runner with ID '{runner_id}' does not exist.")
|
|
192
|
+
|
|
193
|
+
return RunnerArguments(**runner_details)
|
|
188
194
|
|
|
189
195
|
except Exception as e:
|
|
190
|
-
|
|
196
|
+
logger.error(f"[Runner] Failed to read runner: {str(e)}")
|
|
191
197
|
raise e
|
|
192
198
|
|
|
199
|
+
@staticmethod
|
|
200
|
+
def _read_runner(runner_id: str) -> dict:
|
|
201
|
+
"""
|
|
202
|
+
Retrieves the runner's information from a JSON file.
|
|
203
|
+
|
|
204
|
+
This internal method is designed to fetch the details of a specific runner by its ID. It searches for the
|
|
205
|
+
corresponding JSON file within the directory specified by `EnvVariables.RUNNERS`. The method returns a
|
|
206
|
+
dictionary containing the runner's information.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
runner_id (str): The unique identifier of the runner whose information is being retrieved.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
dict: A dictionary with the runner's information.
|
|
213
|
+
"""
|
|
214
|
+
runner_info = {"id": runner_id}
|
|
215
|
+
runner_info.update(
|
|
216
|
+
Storage.read_object(EnvVariables.RUNNERS.name, runner_id, "json")
|
|
217
|
+
)
|
|
218
|
+
return runner_info
|
|
219
|
+
|
|
193
220
|
@staticmethod
|
|
194
221
|
@validate_call
|
|
195
222
|
def delete(runner_id: str) -> bool:
|
|
@@ -216,7 +243,7 @@ class Runner:
|
|
|
216
243
|
return True
|
|
217
244
|
|
|
218
245
|
except Exception as e:
|
|
219
|
-
|
|
246
|
+
logger.error(f"[Runner] Failed to delete runner: {str(e)}")
|
|
220
247
|
raise e
|
|
221
248
|
|
|
222
249
|
@staticmethod
|
|
@@ -245,18 +272,14 @@ class Runner:
|
|
|
245
272
|
if "__" in runner:
|
|
246
273
|
continue
|
|
247
274
|
|
|
248
|
-
runner_info = RunnerArguments(
|
|
249
|
-
**Storage.read_object(
|
|
250
|
-
EnvVariables.RUNNERS.name, Path(runner).stem, "json"
|
|
251
|
-
)
|
|
252
|
-
)
|
|
275
|
+
runner_info = RunnerArguments(**Runner._read_runner(Path(runner).stem))
|
|
253
276
|
retn_runners.append(runner_info)
|
|
254
277
|
retn_runners_ids.append(runner_info.id)
|
|
255
278
|
|
|
256
279
|
return retn_runners_ids, retn_runners
|
|
257
280
|
|
|
258
281
|
except Exception as e:
|
|
259
|
-
|
|
282
|
+
logger.error(f"[Runner] Failed to get available runners: {str(e)}")
|
|
260
283
|
raise e
|
|
261
284
|
|
|
262
285
|
def close(self) -> None:
|
|
@@ -285,7 +308,7 @@ class Runner:
|
|
|
285
308
|
"""
|
|
286
309
|
async with self.current_operation_lock:
|
|
287
310
|
if self.current_operation:
|
|
288
|
-
|
|
311
|
+
logger.warning(f"[Runner] {self.id} - Cancelling current operation...")
|
|
289
312
|
self.current_operation.cancel()
|
|
290
313
|
self.current_operation = None # Reset the current operation
|
|
291
314
|
|
|
@@ -328,7 +351,7 @@ class Runner:
|
|
|
328
351
|
"""
|
|
329
352
|
async with self.current_operation_lock: # Acquire the lock
|
|
330
353
|
# Create new benchmark recipe test run
|
|
331
|
-
|
|
354
|
+
logger.info(f"[Runner] {self.id} - Running benchmark recipe run...")
|
|
332
355
|
self.current_operation = Run(
|
|
333
356
|
self.id,
|
|
334
357
|
RunnerType.BENCHMARK,
|
|
@@ -354,7 +377,7 @@ class Runner:
|
|
|
354
377
|
# After completion, reset current_operation to None within the lock
|
|
355
378
|
async with self.current_operation_lock:
|
|
356
379
|
self.current_operation = None
|
|
357
|
-
|
|
380
|
+
logger.info(f"[Runner] {self.id} - Benchmark recipe run completed.")
|
|
358
381
|
|
|
359
382
|
async def run_cookbooks(
|
|
360
383
|
self,
|
|
@@ -396,7 +419,7 @@ class Runner:
|
|
|
396
419
|
"""
|
|
397
420
|
async with self.current_operation_lock: # Acquire the lock
|
|
398
421
|
# Create new benchmark cookbook test run
|
|
399
|
-
|
|
422
|
+
logger.info(f"[Runner] {self.id} - Running benchmark cookbook run...")
|
|
400
423
|
self.current_operation = Run(
|
|
401
424
|
self.id,
|
|
402
425
|
RunnerType.BENCHMARK,
|
|
@@ -422,7 +445,7 @@ class Runner:
|
|
|
422
445
|
# After completion, reset current_operation to None within the lock
|
|
423
446
|
async with self.current_operation_lock:
|
|
424
447
|
self.current_operation = None
|
|
425
|
-
|
|
448
|
+
logger.info(f"[Runner] {self.id} - Benchmark cookbook run completed.")
|
|
426
449
|
|
|
427
450
|
async def run_red_teaming(
|
|
428
451
|
self,
|
|
@@ -450,7 +473,7 @@ class Runner:
|
|
|
450
473
|
Exception: If any error occurs during the setup or execution of the red teaming session.
|
|
451
474
|
"""
|
|
452
475
|
async with self.current_operation_lock: # Acquire the lock
|
|
453
|
-
|
|
476
|
+
logger.info(f"[Runner] {self.id} - Running red teaming session...")
|
|
454
477
|
self.current_operation = Session(
|
|
455
478
|
self.id,
|
|
456
479
|
RunnerType.REDTEAM,
|
|
@@ -471,6 +494,6 @@ class Runner:
|
|
|
471
494
|
# After completion, reset current_operation to None within the lock
|
|
472
495
|
async with self.current_operation_lock:
|
|
473
496
|
self.current_operation = None
|
|
474
|
-
|
|
497
|
+
logger.info(f"[Runner] {self.id} - Red teaming run completed.")
|
|
475
498
|
|
|
476
499
|
return red_teaming_results
|
moonshot/src/runs/run.py
CHANGED
|
@@ -13,6 +13,10 @@ from moonshot.src.runs.run_status import RunStatus
|
|
|
13
13
|
from moonshot.src.storage.db_interface import DBInterface
|
|
14
14
|
from moonshot.src.storage.storage import Storage
|
|
15
15
|
from moonshot.src.utils.import_modules import get_instance
|
|
16
|
+
from moonshot.src.utils.log import configure_logger
|
|
17
|
+
|
|
18
|
+
# Create a logger for this module
|
|
19
|
+
logger = configure_logger(__name__)
|
|
16
20
|
|
|
17
21
|
|
|
18
22
|
class Run:
|
|
@@ -164,7 +168,7 @@ class Run:
|
|
|
164
168
|
Returns:
|
|
165
169
|
None
|
|
166
170
|
"""
|
|
167
|
-
|
|
171
|
+
logger.warning("[Run] Cancelling run...")
|
|
168
172
|
self.cancel_event.set()
|
|
169
173
|
|
|
170
174
|
async def run(self) -> ResultArguments | None:
|
|
@@ -184,7 +188,7 @@ class Run:
|
|
|
184
188
|
# ------------------------------------------------------------------------------
|
|
185
189
|
# Part 0: Initialise
|
|
186
190
|
# ------------------------------------------------------------------------------
|
|
187
|
-
|
|
191
|
+
logger.debug("[Run] Part 0: Initialising run...")
|
|
188
192
|
start_time = time.perf_counter()
|
|
189
193
|
try:
|
|
190
194
|
# Initialise the run
|
|
@@ -219,20 +223,20 @@ class Run:
|
|
|
219
223
|
self.run_progress.notify_error(error_message)
|
|
220
224
|
|
|
221
225
|
finally:
|
|
222
|
-
|
|
226
|
+
logger.debug(
|
|
223
227
|
f"[Run] Initialise run took {(time.perf_counter() - start_time):.4f}s"
|
|
224
228
|
)
|
|
225
229
|
|
|
226
230
|
# ------------------------------------------------------------------------------
|
|
227
231
|
# Part 1: Get asyncio running loop
|
|
228
232
|
# ------------------------------------------------------------------------------
|
|
229
|
-
|
|
233
|
+
logger.debug("[Run] Part 1: Loading asyncio running loop...")
|
|
230
234
|
loop = asyncio.get_running_loop()
|
|
231
235
|
|
|
232
236
|
# ------------------------------------------------------------------------------
|
|
233
237
|
# Part 2: Load runner and result processing module
|
|
234
238
|
# ------------------------------------------------------------------------------
|
|
235
|
-
|
|
239
|
+
logger.debug("[Run] Part 2: Loading modules...")
|
|
236
240
|
start_time = time.perf_counter()
|
|
237
241
|
runner_module_instance = None
|
|
238
242
|
result_module_instance = None
|
|
@@ -246,14 +250,14 @@ class Run:
|
|
|
246
250
|
except Exception as e:
|
|
247
251
|
self.run_progress.notify_error(f"[Run] Module loading error: {e}")
|
|
248
252
|
finally:
|
|
249
|
-
|
|
253
|
+
logger.debug(
|
|
250
254
|
f"[Run] Module loading took {(time.perf_counter() - start_time):.4f}s"
|
|
251
255
|
)
|
|
252
256
|
|
|
253
257
|
# ------------------------------------------------------------------------------
|
|
254
258
|
# Part 3: Run runner processing module
|
|
255
259
|
# ------------------------------------------------------------------------------
|
|
256
|
-
|
|
260
|
+
logger.debug("[Run] Part 3: Running runner processing module...")
|
|
257
261
|
start_time = time.perf_counter()
|
|
258
262
|
runner_results = None
|
|
259
263
|
try:
|
|
@@ -274,14 +278,14 @@ class Run:
|
|
|
274
278
|
self.run_progress.notify_error(error_message)
|
|
275
279
|
|
|
276
280
|
finally:
|
|
277
|
-
|
|
281
|
+
logger.debug(
|
|
278
282
|
f"[Run] Running runner processing module took {(time.perf_counter() - start_time):.4f}s"
|
|
279
283
|
)
|
|
280
284
|
|
|
281
285
|
# ------------------------------------------------------------------------------
|
|
282
286
|
# Part 4: Run result processing module
|
|
283
287
|
# ------------------------------------------------------------------------------
|
|
284
|
-
|
|
288
|
+
logger.debug("[Run] Part 4: Running result processing module...")
|
|
285
289
|
start_time = time.perf_counter()
|
|
286
290
|
updated_runner_results = None
|
|
287
291
|
try:
|
|
@@ -301,14 +305,14 @@ class Run:
|
|
|
301
305
|
self.run_progress.notify_error(error_message)
|
|
302
306
|
|
|
303
307
|
finally:
|
|
304
|
-
|
|
308
|
+
logger.debug(
|
|
305
309
|
f"[Run] Running result processing module took {(time.perf_counter() - start_time):.4f}s"
|
|
306
310
|
)
|
|
307
311
|
|
|
308
312
|
# ------------------------------------------------------------------------------
|
|
309
313
|
# Part 5: Wrap up run
|
|
310
314
|
# ------------------------------------------------------------------------------
|
|
311
|
-
|
|
315
|
+
logger.debug("[Run] Part 5: Wrap up run...")
|
|
312
316
|
return updated_runner_results
|
|
313
317
|
|
|
314
318
|
def _load_module(self, arg_key: str, env_var: str):
|
|
@@ -4,6 +4,10 @@ from typing import Callable
|
|
|
4
4
|
from moonshot.src.runs.run_arguments import RunArguments
|
|
5
5
|
from moonshot.src.runs.run_status import RunStatus
|
|
6
6
|
from moonshot.src.storage.storage import Storage
|
|
7
|
+
from moonshot.src.utils.log import configure_logger
|
|
8
|
+
|
|
9
|
+
# Create a logger for this module
|
|
10
|
+
logger = configure_logger(__name__)
|
|
7
11
|
|
|
8
12
|
|
|
9
13
|
class RunProgress:
|
|
@@ -40,7 +44,7 @@ class RunProgress:
|
|
|
40
44
|
error_message (str): The error message to be logged and recorded.
|
|
41
45
|
"""
|
|
42
46
|
# Update error message
|
|
43
|
-
|
|
47
|
+
logger.error(error_message)
|
|
44
48
|
self.run_arguments.error_messages.append(error_message)
|
|
45
49
|
|
|
46
50
|
# Update progress status
|
|
@@ -108,8 +112,8 @@ class RunProgress:
|
|
|
108
112
|
RunProgress.sql_update_run_record,
|
|
109
113
|
)
|
|
110
114
|
else:
|
|
111
|
-
|
|
112
|
-
"[RunProgress] Failed to update run progress:
|
|
115
|
+
logger.warning(
|
|
116
|
+
"[RunProgress] Failed to update run progress: database instance is not initialised."
|
|
113
117
|
)
|
|
114
118
|
|
|
115
119
|
# If a callback function is provided, call it with the updated run arguments
|
|
@@ -100,6 +100,20 @@ class DBInterface:
|
|
|
100
100
|
"""
|
|
101
101
|
pass
|
|
102
102
|
|
|
103
|
+
@abstractmethod
|
|
104
|
+
def delete_records_in_table(self, delete_record_sql: str) -> None:
|
|
105
|
+
"""
|
|
106
|
+
This method is used to delete all records from a specified table in the database. The details of the operation
|
|
107
|
+
are implementation specific and should be provided by the concrete class that inherits from this abstract class.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
delete_record_sql (str): The SQL query to delete all records from a table.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
None
|
|
114
|
+
"""
|
|
115
|
+
pass
|
|
116
|
+
|
|
103
117
|
@abstractmethod
|
|
104
118
|
def check_database_table_exists(self, table_name: str) -> bool:
|
|
105
119
|
"""
|
moonshot/src/storage/storage.py
CHANGED
|
@@ -22,7 +22,7 @@ class Storage:
|
|
|
22
22
|
obj_info: dict,
|
|
23
23
|
obj_extension: str,
|
|
24
24
|
obj_mod_type: str = "jsonio",
|
|
25
|
-
) ->
|
|
25
|
+
) -> str:
|
|
26
26
|
"""
|
|
27
27
|
Writes the object information to a file.
|
|
28
28
|
|
|
@@ -32,6 +32,9 @@ class Storage:
|
|
|
32
32
|
obj_info (dict): A dictionary containing the object information.
|
|
33
33
|
obj_extension (str): The file extension (e.g., 'json', 'py').
|
|
34
34
|
obj_mod_type (str, optional): The module type for object serialization. Defaults to 'jsonio'.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
str: A filepath string of the object that has just been created.
|
|
35
38
|
"""
|
|
36
39
|
if not hasattr(EnvironmentVars, obj_type):
|
|
37
40
|
raise RuntimeError(
|
|
@@ -45,7 +48,11 @@ class Storage:
|
|
|
45
48
|
Storage.get_filepath(EnvVariables.IO_MODULES.name, obj_mod_type, "py"),
|
|
46
49
|
)
|
|
47
50
|
if obj_mod_instance and callable(obj_mod_instance):
|
|
48
|
-
|
|
51
|
+
try:
|
|
52
|
+
obj_mod_instance(obj_filepath).create_file(obj_info)
|
|
53
|
+
return obj_filepath
|
|
54
|
+
except Exception as e:
|
|
55
|
+
raise e
|
|
49
56
|
else:
|
|
50
57
|
raise RuntimeError(
|
|
51
58
|
f"Unable to get defined object module instance - {obj_mod_instance}"
|
|
@@ -479,6 +486,30 @@ class Storage:
|
|
|
479
486
|
else:
|
|
480
487
|
raise RuntimeError("Database instance is not initialised.")
|
|
481
488
|
|
|
489
|
+
@staticmethod
|
|
490
|
+
def delete_database_record_in_table(
|
|
491
|
+
database_instance: DBInterface, sql_delete_record: str
|
|
492
|
+
) -> None:
|
|
493
|
+
"""
|
|
494
|
+
Deletes records from a table in the database based on a SQL condition.
|
|
495
|
+
|
|
496
|
+
This method is used to delete records from a specific table in the database
|
|
497
|
+
that meet the condition specified in the SQL delete statement.
|
|
498
|
+
If the database instance is not initialised, it raises a RuntimeError.
|
|
499
|
+
Otherwise, it calls the delete_records_in_table method of the database instance with the provided SQL query.
|
|
500
|
+
|
|
501
|
+
Args:
|
|
502
|
+
database_instance (DBInterface): The database accessor instance.
|
|
503
|
+
sql_delete_record (str): The SQL query to delete records from a table.
|
|
504
|
+
|
|
505
|
+
Returns:
|
|
506
|
+
None
|
|
507
|
+
"""
|
|
508
|
+
if database_instance:
|
|
509
|
+
database_instance.delete_records_in_table(sql_delete_record)
|
|
510
|
+
else:
|
|
511
|
+
raise RuntimeError("Database instance is not initialised.")
|
|
512
|
+
|
|
482
513
|
@staticmethod
|
|
483
514
|
def check_database_table_exists(
|
|
484
515
|
database_instance: DBInterface, table_name: str
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from typing import Any, Union
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def find_keyword(
|
|
5
|
+
keyword: str, target: Union[str, list[str], list[list[str]], list[dict], list, dict]
|
|
6
|
+
) -> Any:
|
|
7
|
+
"""
|
|
8
|
+
Find the keyword in the target and return the matching elements.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
keyword (str): The keyword to search for.
|
|
12
|
+
target: The target to search within.
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
Any: The matching elements or None if no match is found.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
# find in single string
|
|
19
|
+
if isinstance(target, str):
|
|
20
|
+
if target.find(keyword) != -1:
|
|
21
|
+
return target
|
|
22
|
+
return ""
|
|
23
|
+
|
|
24
|
+
# find in single dict
|
|
25
|
+
elif isinstance(target, dict):
|
|
26
|
+
if any(str(keyword) in str(value).lower() for value in target.values()):
|
|
27
|
+
return target
|
|
28
|
+
return {}
|
|
29
|
+
|
|
30
|
+
# find in list
|
|
31
|
+
elif isinstance(target, list):
|
|
32
|
+
# list of string
|
|
33
|
+
if all(isinstance(item, str) for item in target):
|
|
34
|
+
return [item for item in target if str(item).lower().find(keyword) != -1]
|
|
35
|
+
|
|
36
|
+
# list of dict
|
|
37
|
+
elif all(isinstance(item, dict) for item in target):
|
|
38
|
+
return [
|
|
39
|
+
item
|
|
40
|
+
for item in target
|
|
41
|
+
if isinstance(item, dict)
|
|
42
|
+
and any(str(keyword) in str(value).lower() for value in item.values())
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
return None
|