aiverify-moonshot 0.4.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.
- aiverify_moonshot-0.4.0.dist-info/METADATA +249 -0
- aiverify_moonshot-0.4.0.dist-info/RECORD +163 -0
- aiverify_moonshot-0.4.0.dist-info/WHEEL +4 -0
- aiverify_moonshot-0.4.0.dist-info/licenses/AUTHORS.md +5 -0
- aiverify_moonshot-0.4.0.dist-info/licenses/LICENSE.md +201 -0
- aiverify_moonshot-0.4.0.dist-info/licenses/NOTICES.md +3340 -0
- moonshot/__init__.py +0 -0
- moonshot/__main__.py +198 -0
- moonshot/api.py +155 -0
- moonshot/integrations/__init__.py +0 -0
- moonshot/integrations/cli/__init__.py +0 -0
- moonshot/integrations/cli/__main__.py +25 -0
- moonshot/integrations/cli/active_session_cfg.py +1 -0
- moonshot/integrations/cli/benchmark/__init__.py +0 -0
- moonshot/integrations/cli/benchmark/benchmark.py +186 -0
- moonshot/integrations/cli/benchmark/cookbook.py +545 -0
- moonshot/integrations/cli/benchmark/datasets.py +164 -0
- moonshot/integrations/cli/benchmark/metrics.py +141 -0
- moonshot/integrations/cli/benchmark/recipe.py +598 -0
- moonshot/integrations/cli/benchmark/result.py +216 -0
- moonshot/integrations/cli/benchmark/run.py +140 -0
- moonshot/integrations/cli/benchmark/runner.py +174 -0
- moonshot/integrations/cli/cli.py +64 -0
- moonshot/integrations/cli/common/__init__.py +0 -0
- moonshot/integrations/cli/common/common.py +72 -0
- moonshot/integrations/cli/common/connectors.py +325 -0
- moonshot/integrations/cli/common/display_helper.py +42 -0
- moonshot/integrations/cli/common/prompt_template.py +94 -0
- moonshot/integrations/cli/initialisation/__init__.py +0 -0
- moonshot/integrations/cli/initialisation/initialisation.py +14 -0
- moonshot/integrations/cli/redteam/__init__.py +0 -0
- moonshot/integrations/cli/redteam/attack_module.py +70 -0
- moonshot/integrations/cli/redteam/context_strategy.py +147 -0
- moonshot/integrations/cli/redteam/prompt_template.py +67 -0
- moonshot/integrations/cli/redteam/redteam.py +90 -0
- moonshot/integrations/cli/redteam/session.py +467 -0
- moonshot/integrations/web_api/.env.dev +7 -0
- moonshot/integrations/web_api/__init__.py +0 -0
- moonshot/integrations/web_api/__main__.py +56 -0
- moonshot/integrations/web_api/app.py +125 -0
- moonshot/integrations/web_api/container.py +146 -0
- moonshot/integrations/web_api/log/.gitkeep +0 -0
- moonshot/integrations/web_api/logging_conf.py +114 -0
- moonshot/integrations/web_api/routes/__init__.py +0 -0
- moonshot/integrations/web_api/routes/attack_modules.py +66 -0
- moonshot/integrations/web_api/routes/benchmark.py +116 -0
- moonshot/integrations/web_api/routes/benchmark_result.py +175 -0
- moonshot/integrations/web_api/routes/context_strategy.py +129 -0
- moonshot/integrations/web_api/routes/cookbook.py +225 -0
- moonshot/integrations/web_api/routes/dataset.py +120 -0
- moonshot/integrations/web_api/routes/endpoint.py +282 -0
- moonshot/integrations/web_api/routes/metric.py +78 -0
- moonshot/integrations/web_api/routes/prompt_template.py +128 -0
- moonshot/integrations/web_api/routes/recipe.py +219 -0
- moonshot/integrations/web_api/routes/redteam.py +609 -0
- moonshot/integrations/web_api/routes/runner.py +239 -0
- moonshot/integrations/web_api/schemas/__init__.py +0 -0
- moonshot/integrations/web_api/schemas/benchmark_runner_dto.py +13 -0
- moonshot/integrations/web_api/schemas/cookbook_create_dto.py +19 -0
- moonshot/integrations/web_api/schemas/cookbook_response_model.py +9 -0
- moonshot/integrations/web_api/schemas/dataset_response_dto.py +9 -0
- moonshot/integrations/web_api/schemas/endpoint_create_dto.py +21 -0
- moonshot/integrations/web_api/schemas/endpoint_response_model.py +11 -0
- moonshot/integrations/web_api/schemas/prompt_response_model.py +14 -0
- moonshot/integrations/web_api/schemas/prompt_template_response_model.py +10 -0
- moonshot/integrations/web_api/schemas/recipe_create_dto.py +32 -0
- moonshot/integrations/web_api/schemas/recipe_response_model.py +7 -0
- moonshot/integrations/web_api/schemas/session_create_dto.py +16 -0
- moonshot/integrations/web_api/schemas/session_prompt_dto.py +7 -0
- moonshot/integrations/web_api/schemas/session_response_model.py +38 -0
- moonshot/integrations/web_api/services/__init__.py +0 -0
- moonshot/integrations/web_api/services/attack_module_service.py +34 -0
- moonshot/integrations/web_api/services/auto_red_team_test_manager.py +86 -0
- moonshot/integrations/web_api/services/auto_red_team_test_state.py +57 -0
- moonshot/integrations/web_api/services/base_service.py +8 -0
- moonshot/integrations/web_api/services/benchmark_result_service.py +25 -0
- moonshot/integrations/web_api/services/benchmark_test_manager.py +106 -0
- moonshot/integrations/web_api/services/benchmark_test_state.py +56 -0
- moonshot/integrations/web_api/services/benchmarking_service.py +31 -0
- moonshot/integrations/web_api/services/context_strategy_service.py +22 -0
- moonshot/integrations/web_api/services/cookbook_service.py +194 -0
- moonshot/integrations/web_api/services/dataset_service.py +20 -0
- moonshot/integrations/web_api/services/endpoint_service.py +65 -0
- moonshot/integrations/web_api/services/metric_service.py +14 -0
- moonshot/integrations/web_api/services/prompt_template_service.py +39 -0
- moonshot/integrations/web_api/services/recipe_service.py +155 -0
- moonshot/integrations/web_api/services/runner_service.py +147 -0
- moonshot/integrations/web_api/services/session_service.py +350 -0
- moonshot/integrations/web_api/services/utils/exceptions_handler.py +41 -0
- moonshot/integrations/web_api/services/utils/results_formatter.py +47 -0
- moonshot/integrations/web_api/status_updater/interface/benchmark_progress_callback.py +14 -0
- moonshot/integrations/web_api/status_updater/interface/redteam_progress_callback.py +14 -0
- moonshot/integrations/web_api/status_updater/moonshot_ui_webhook.py +72 -0
- moonshot/integrations/web_api/types/types.py +99 -0
- moonshot/src/__init__.py +0 -0
- moonshot/src/api/__init__.py +0 -0
- moonshot/src/api/api_connector.py +58 -0
- moonshot/src/api/api_connector_endpoint.py +162 -0
- moonshot/src/api/api_context_strategy.py +57 -0
- moonshot/src/api/api_cookbook.py +160 -0
- moonshot/src/api/api_dataset.py +46 -0
- moonshot/src/api/api_environment_variables.py +17 -0
- moonshot/src/api/api_metrics.py +51 -0
- moonshot/src/api/api_prompt_template.py +43 -0
- moonshot/src/api/api_recipe.py +182 -0
- moonshot/src/api/api_red_teaming.py +59 -0
- moonshot/src/api/api_result.py +84 -0
- moonshot/src/api/api_run.py +74 -0
- moonshot/src/api/api_runner.py +132 -0
- moonshot/src/api/api_session.py +290 -0
- moonshot/src/configs/__init__.py +0 -0
- moonshot/src/configs/env_variables.py +187 -0
- moonshot/src/connectors/__init__.py +0 -0
- moonshot/src/connectors/connector.py +327 -0
- moonshot/src/connectors/connector_prompt_arguments.py +17 -0
- moonshot/src/connectors_endpoints/__init__.py +0 -0
- moonshot/src/connectors_endpoints/connector_endpoint.py +211 -0
- moonshot/src/connectors_endpoints/connector_endpoint_arguments.py +54 -0
- moonshot/src/cookbooks/__init__.py +0 -0
- moonshot/src/cookbooks/cookbook.py +225 -0
- moonshot/src/cookbooks/cookbook_arguments.py +34 -0
- moonshot/src/datasets/__init__.py +0 -0
- moonshot/src/datasets/dataset.py +255 -0
- moonshot/src/datasets/dataset_arguments.py +50 -0
- moonshot/src/metrics/__init__.py +0 -0
- moonshot/src/metrics/metric.py +192 -0
- moonshot/src/metrics/metric_interface.py +95 -0
- moonshot/src/prompt_templates/__init__.py +0 -0
- moonshot/src/prompt_templates/prompt_template.py +103 -0
- moonshot/src/recipes/__init__.py +0 -0
- moonshot/src/recipes/recipe.py +340 -0
- moonshot/src/recipes/recipe_arguments.py +111 -0
- moonshot/src/redteaming/__init__.py +0 -0
- moonshot/src/redteaming/attack/__init__.py +0 -0
- moonshot/src/redteaming/attack/attack_module.py +618 -0
- moonshot/src/redteaming/attack/attack_module_arguments.py +44 -0
- moonshot/src/redteaming/attack/context_strategy.py +131 -0
- moonshot/src/redteaming/context_strategy/__init__.py +0 -0
- moonshot/src/redteaming/context_strategy/context_strategy_interface.py +46 -0
- moonshot/src/redteaming/session/__init__.py +0 -0
- moonshot/src/redteaming/session/chat.py +209 -0
- moonshot/src/redteaming/session/red_teaming_progress.py +128 -0
- moonshot/src/redteaming/session/red_teaming_type.py +6 -0
- moonshot/src/redteaming/session/session.py +775 -0
- moonshot/src/results/__init__.py +0 -0
- moonshot/src/results/result.py +119 -0
- moonshot/src/results/result_arguments.py +44 -0
- moonshot/src/runners/__init__.py +0 -0
- moonshot/src/runners/runner.py +476 -0
- moonshot/src/runners/runner_arguments.py +46 -0
- moonshot/src/runners/runner_type.py +6 -0
- moonshot/src/runs/__init__.py +0 -0
- moonshot/src/runs/run.py +344 -0
- moonshot/src/runs/run_arguments.py +162 -0
- moonshot/src/runs/run_progress.py +145 -0
- moonshot/src/runs/run_status.py +10 -0
- moonshot/src/storage/__init__.py +0 -0
- moonshot/src/storage/db_interface.py +128 -0
- moonshot/src/storage/io_interface.py +31 -0
- moonshot/src/storage/storage.py +525 -0
- moonshot/src/utils/__init__.py +0 -0
- moonshot/src/utils/import_modules.py +96 -0
- moonshot/src/utils/timeit.py +25 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import abstractmethod
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DBInterface:
|
|
8
|
+
@abstractmethod
|
|
9
|
+
def create_connection(self) -> Any | None:
|
|
10
|
+
"""
|
|
11
|
+
This method is used to create a connection to the database. The details of the connection
|
|
12
|
+
are implementation specific and should be provided by the concrete class that inherits from this abstract class.
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
Any | None: The connection object if successful, None otherwise.
|
|
16
|
+
"""
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def close_connection(self) -> None:
|
|
21
|
+
"""
|
|
22
|
+
This method is used to close the connection to the database. The details of the operation
|
|
23
|
+
are implementation specific and should be provided by the concrete class that inherits from this abstract class.
|
|
24
|
+
"""
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
@abstractmethod
|
|
28
|
+
def create_table(self, create_table_sql: str) -> None:
|
|
29
|
+
"""
|
|
30
|
+
This method is used to create a table in the database. The details of the operation
|
|
31
|
+
are implementation specific and should be provided by the concrete class that inherits from this abstract class.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
create_table_sql (str): The SQL query to create a table.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
None
|
|
38
|
+
"""
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def create_record(self, record: tuple, create_record_sql: str) -> None:
|
|
43
|
+
"""
|
|
44
|
+
This method is used to create a record in the database. The details of the operation
|
|
45
|
+
are implementation specific and should be provided by the concrete class that inherits from this abstract class.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
record (tuple): The record to be created.
|
|
49
|
+
create_record_sql (str): The SQL query to create a record.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
None
|
|
53
|
+
"""
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
@abstractmethod
|
|
57
|
+
def read_record(self, record: tuple, read_record_sql: str) -> tuple | None:
|
|
58
|
+
"""
|
|
59
|
+
This method is used to read a record from the database. The details of the operation
|
|
60
|
+
are implementation specific and should be provided by the concrete class that inherits from this abstract class.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
record (tuple): The record to be read.
|
|
64
|
+
read_record_sql (str): The SQL query to read a record.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
tuple | None: The record if found, None otherwise.
|
|
68
|
+
"""
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
@abstractmethod
|
|
72
|
+
def read_records(self, read_records_sql: str) -> list[tuple] | None:
|
|
73
|
+
"""
|
|
74
|
+
Executes a SQL query to read data from a table and returns the results.
|
|
75
|
+
|
|
76
|
+
This method attempts to execute a provided SQL query to read data from a table within the SQLite database.
|
|
77
|
+
If the connection to the database is established, it executes the query and returns all fetched rows as a list.
|
|
78
|
+
In case of an error during the execution of the query, it prints an error message detailing the issue.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
read_records_sql (str): The SQL query string used to read data from a table.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
list | None: A list of tuples representing the rows fetched by the query if successful.
|
|
85
|
+
"""
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
@abstractmethod
|
|
89
|
+
def update_record(self, record: tuple, update_record_sql: str) -> None:
|
|
90
|
+
"""
|
|
91
|
+
This method is used to update a record in the database. The details of the operation
|
|
92
|
+
are implementation specific and should be provided by the concrete class that inherits from this abstract class.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
record (tuple): The record to be updated.
|
|
96
|
+
update_record_sql (str): The SQL query to update a record.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
None
|
|
100
|
+
"""
|
|
101
|
+
pass
|
|
102
|
+
|
|
103
|
+
@abstractmethod
|
|
104
|
+
def check_database_table_exists(self, table_name: str) -> bool:
|
|
105
|
+
"""
|
|
106
|
+
This method is used to check if a table exists in the database.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
table_name (str): The name of the table to check for existence.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
bool: True if the table exists, False otherwise.
|
|
113
|
+
"""
|
|
114
|
+
pass
|
|
115
|
+
|
|
116
|
+
@abstractmethod
|
|
117
|
+
def delete_database_table(self, delete_table_sql: str) -> None:
|
|
118
|
+
"""
|
|
119
|
+
This method is used to delete a table from the database. The details of the operation
|
|
120
|
+
are implementation specific and should be provided by the concrete class that inherits from this abstract class.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
table_name (str): The name of the table to be deleted.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
None
|
|
127
|
+
"""
|
|
128
|
+
pass
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class IOInterface:
|
|
6
|
+
@abstractmethod
|
|
7
|
+
def create_file(self, data: dict) -> Any | None:
|
|
8
|
+
"""
|
|
9
|
+
Creates a file with the given data.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
data (dict): The data to be written to the file.
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
Any | None: The result of the file creation operation, or None if the operation was unsuccessful.
|
|
16
|
+
"""
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def read_file(self, filepath: str) -> dict | None:
|
|
21
|
+
"""
|
|
22
|
+
Reads the file at the given filepath.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
filepath (str): The path to the file to be read.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
dict | None: The data from the file if the file was successfully read, or None if the operation was
|
|
29
|
+
unsuccessful.
|
|
30
|
+
"""
|
|
31
|
+
pass
|
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import glob
|
|
3
|
+
import os
|
|
4
|
+
from itertools import chain
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Iterator
|
|
7
|
+
|
|
8
|
+
import xxhash
|
|
9
|
+
from pydantic import validate_call
|
|
10
|
+
|
|
11
|
+
from moonshot.src.configs.env_variables import EnvironmentVars, EnvVariables
|
|
12
|
+
from moonshot.src.storage.db_interface import DBInterface
|
|
13
|
+
from moonshot.src.utils.import_modules import get_instance
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Storage:
|
|
17
|
+
@staticmethod
|
|
18
|
+
@validate_call
|
|
19
|
+
def create_object(
|
|
20
|
+
obj_type: str,
|
|
21
|
+
obj_id: str,
|
|
22
|
+
obj_info: dict,
|
|
23
|
+
obj_extension: str,
|
|
24
|
+
obj_mod_type: str = "jsonio",
|
|
25
|
+
) -> bool:
|
|
26
|
+
"""
|
|
27
|
+
Writes the object information to a file.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
obj_type (str): The type of the object (e.g., 'recipe', 'cookbook').
|
|
31
|
+
obj_id (str): The ID of the object.
|
|
32
|
+
obj_info (dict): A dictionary containing the object information.
|
|
33
|
+
obj_extension (str): The file extension (e.g., 'json', 'py').
|
|
34
|
+
obj_mod_type (str, optional): The module type for object serialization. Defaults to 'jsonio'.
|
|
35
|
+
"""
|
|
36
|
+
if not hasattr(EnvironmentVars, obj_type):
|
|
37
|
+
raise RuntimeError(
|
|
38
|
+
f"'{obj_type}' is not a recognized EnvironmentVar value."
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
obj_filepath = Storage.get_filepath(obj_type, obj_id, obj_extension, True)
|
|
42
|
+
if obj_filepath and isinstance(obj_filepath, str):
|
|
43
|
+
obj_mod_instance = get_instance(
|
|
44
|
+
obj_mod_type,
|
|
45
|
+
Storage.get_filepath(EnvVariables.IO_MODULES.name, obj_mod_type, "py"),
|
|
46
|
+
)
|
|
47
|
+
if obj_mod_instance and callable(obj_mod_instance):
|
|
48
|
+
return obj_mod_instance(obj_filepath).create_file(obj_info)
|
|
49
|
+
else:
|
|
50
|
+
raise RuntimeError(
|
|
51
|
+
f"Unable to get defined object module instance - {obj_mod_instance}"
|
|
52
|
+
)
|
|
53
|
+
else:
|
|
54
|
+
raise RuntimeError("Unable to create object.")
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
@validate_call
|
|
58
|
+
def read_object_with_iterator(
|
|
59
|
+
obj_type: str,
|
|
60
|
+
obj_id: str,
|
|
61
|
+
obj_extension: str,
|
|
62
|
+
obj_mod_type: str = "jsonio",
|
|
63
|
+
json_keys: list[str] | None = None,
|
|
64
|
+
iterator_keys: list[str] | None = None,
|
|
65
|
+
) -> dict:
|
|
66
|
+
"""
|
|
67
|
+
Retrieves object data from a file, with options to filter by specific keys for efficient data handling.
|
|
68
|
+
|
|
69
|
+
This function reads from a file corresponding to the given object type and ID, deserializing the content
|
|
70
|
+
using the specified module. It can also selectively extract values or create iterators for specified keys,
|
|
71
|
+
which is useful for handling large datasets or deeply nested JSON structures.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
obj_type (str): The category of the object to read (e.g., 'recipe', 'cookbook').
|
|
75
|
+
obj_id (str): The unique identifier for the object.
|
|
76
|
+
obj_extension (str): The file extension indicating the file type (e.g., 'json', 'py').
|
|
77
|
+
obj_mod_type (str, optional): The deserialization module type to use. Defaults to 'jsonio'.
|
|
78
|
+
json_keys (list[str] | None, optional): Keys for which to directly extract values from the file.
|
|
79
|
+
If provided, only these keys will be included in the returned dictionary.
|
|
80
|
+
iterator_keys (list[str] | None, optional): Keys for which to create iterators, allowing for
|
|
81
|
+
streamed access to large or nested structures within the file.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
dict: A dictionary with the requested object data. If `json_keys` is provided, the dictionary
|
|
85
|
+
will contain only the specified keys and their values. If `iterator_keys` is provided, the dictionary
|
|
86
|
+
will include iterators for the specified keys, enabling streamed data access.
|
|
87
|
+
"""
|
|
88
|
+
if not hasattr(EnvironmentVars, obj_type):
|
|
89
|
+
raise RuntimeError(
|
|
90
|
+
f"'{obj_type}' is not a recognized EnvironmentVar value."
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
obj_filepath = Storage.get_filepath(obj_type, obj_id, obj_extension)
|
|
94
|
+
if obj_filepath and isinstance(obj_filepath, str):
|
|
95
|
+
obj_mod_instance = get_instance(
|
|
96
|
+
obj_mod_type,
|
|
97
|
+
Storage.get_filepath(EnvVariables.IO_MODULES.name, obj_mod_type, "py"),
|
|
98
|
+
)
|
|
99
|
+
if obj_mod_instance and callable(obj_mod_instance):
|
|
100
|
+
return obj_mod_instance(obj_filepath).read_file_iterator(
|
|
101
|
+
json_keys, iterator_keys
|
|
102
|
+
)
|
|
103
|
+
else:
|
|
104
|
+
raise RuntimeError(
|
|
105
|
+
f"Unable to get defined object module instance - {obj_mod_instance}"
|
|
106
|
+
)
|
|
107
|
+
else:
|
|
108
|
+
raise RuntimeError(f"No {obj_type.lower()} found with ID: {obj_id}")
|
|
109
|
+
|
|
110
|
+
@staticmethod
|
|
111
|
+
@validate_call
|
|
112
|
+
def read_object(
|
|
113
|
+
obj_type: str, obj_id: str, obj_extension: str, obj_mod_type: str = "jsonio"
|
|
114
|
+
) -> dict:
|
|
115
|
+
"""
|
|
116
|
+
Reads the object information from a file.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
obj_type (str): The type of the object (e.g., 'recipe', 'cookbook').
|
|
120
|
+
obj_id (str): The ID of the object.
|
|
121
|
+
obj_extension (str): The file extension (e.g., 'json', 'py').
|
|
122
|
+
obj_mod_type (str, optional): The module type for object deserialization. Defaults to 'json'.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
dict: A dictionary containing the object information.
|
|
126
|
+
"""
|
|
127
|
+
if not hasattr(EnvironmentVars, obj_type):
|
|
128
|
+
raise RuntimeError(
|
|
129
|
+
f"'{obj_type}' is not a recognized EnvironmentVar value."
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
obj_filepath = Storage.get_filepath(obj_type, obj_id, obj_extension)
|
|
133
|
+
if obj_filepath and isinstance(obj_filepath, str):
|
|
134
|
+
obj_mod_instance = get_instance(
|
|
135
|
+
obj_mod_type,
|
|
136
|
+
Storage.get_filepath(EnvVariables.IO_MODULES.name, obj_mod_type, "py"),
|
|
137
|
+
)
|
|
138
|
+
if obj_mod_instance and callable(obj_mod_instance):
|
|
139
|
+
return obj_mod_instance(obj_filepath).read_file()
|
|
140
|
+
else:
|
|
141
|
+
raise RuntimeError(
|
|
142
|
+
f"Unable to get defined object module instance - {obj_mod_instance}"
|
|
143
|
+
)
|
|
144
|
+
else:
|
|
145
|
+
raise RuntimeError(f"No {obj_type.lower()} found with ID: {obj_id}")
|
|
146
|
+
|
|
147
|
+
@staticmethod
|
|
148
|
+
@validate_call
|
|
149
|
+
def delete_object(obj_type: str, obj_id: str, obj_extension: str) -> bool:
|
|
150
|
+
"""
|
|
151
|
+
Deletes the specified object file.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
obj_type (str): The type of the object (e.g., 'recipe', 'cookbook').
|
|
155
|
+
obj_id (str): The ID of the object.
|
|
156
|
+
obj_extension (str): The file extension (e.g., 'json', 'py').
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
bool: True if the file was successfully deleted.
|
|
160
|
+
|
|
161
|
+
Raises:
|
|
162
|
+
RuntimeError: If no file is found with the specified ID and type.
|
|
163
|
+
"""
|
|
164
|
+
obj_filepath = Storage.get_filepath(obj_type, obj_id, obj_extension)
|
|
165
|
+
if obj_filepath:
|
|
166
|
+
Path(obj_filepath).unlink()
|
|
167
|
+
return True
|
|
168
|
+
else:
|
|
169
|
+
raise RuntimeError(f"No {obj_type.lower()} found with ID: {obj_id}")
|
|
170
|
+
|
|
171
|
+
@staticmethod
|
|
172
|
+
def count_objects(
|
|
173
|
+
obj_type: str, obj_id: str, obj_extension: str, item_path: str
|
|
174
|
+
) -> int:
|
|
175
|
+
"""
|
|
176
|
+
Counts the number of objects in a dataset without loading them fully into memory.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
obj_type (str): The type of the object (e.g., 'dataset').
|
|
180
|
+
obj_id (str): The ID of the object.
|
|
181
|
+
obj_extension (str): The file extension (e.g., 'json').
|
|
182
|
+
item_path (str): The path to the items in the JSON file.
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
int: The count of the objects.
|
|
186
|
+
"""
|
|
187
|
+
count = 0
|
|
188
|
+
generator = Storage.read_object_with_iterator(
|
|
189
|
+
obj_type, obj_id, obj_extension, iterator_keys=[item_path]
|
|
190
|
+
)
|
|
191
|
+
for _ in generator[item_path.split(".")[0]]:
|
|
192
|
+
count += 1
|
|
193
|
+
return count
|
|
194
|
+
|
|
195
|
+
@staticmethod
|
|
196
|
+
@validate_call
|
|
197
|
+
def get_objects(obj_type: str, obj_extension: str) -> Iterator[str]:
|
|
198
|
+
"""
|
|
199
|
+
Retrieves all the object files with the specified extension from one or more directories.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
obj_type (str): The type of the object (e.g., 'recipe', 'cookbook').
|
|
203
|
+
obj_extension (str): The file extension (e.g., 'json', 'py').
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
Iterator[str]: An iterator that yields the filepaths of the object files.
|
|
207
|
+
"""
|
|
208
|
+
if not hasattr(EnvironmentVars, obj_type):
|
|
209
|
+
raise RuntimeError(
|
|
210
|
+
f"'{obj_type}' is not a recognized EnvironmentVar value."
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
directories = EnvironmentVars.get_file_directory(obj_type)
|
|
214
|
+
return chain.from_iterable(
|
|
215
|
+
glob.iglob(f"{directory}/*.{obj_extension}") for directory in directories
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
@staticmethod
|
|
219
|
+
def get_creation_datetime(
|
|
220
|
+
obj_type: str, obj_id: str, obj_extension: str
|
|
221
|
+
) -> datetime.datetime:
|
|
222
|
+
"""
|
|
223
|
+
Retrieves the creation datetime of an object.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
obj_type (str): The type of the object (e.g., 'recipe', 'cookbook').
|
|
227
|
+
obj_id (str): The ID of the object.
|
|
228
|
+
obj_extension (str): The file extension (e.g., 'json', 'py').
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
datetime: The creation datetime of the object.
|
|
232
|
+
"""
|
|
233
|
+
obj_filepath = Storage.get_filepath(obj_type, obj_id, obj_extension)
|
|
234
|
+
if obj_filepath:
|
|
235
|
+
creation_timestamp = os.path.getctime(obj_filepath)
|
|
236
|
+
creation_datetime = datetime.datetime.fromtimestamp(creation_timestamp)
|
|
237
|
+
return creation_datetime
|
|
238
|
+
else:
|
|
239
|
+
raise RuntimeError(f"No {obj_type.lower()} found with ID: {obj_id}")
|
|
240
|
+
|
|
241
|
+
@staticmethod
|
|
242
|
+
def get_file_hash(obj_type: str, obj_id: str, obj_extension: str) -> str:
|
|
243
|
+
"""
|
|
244
|
+
Retrieves the hash of the file content for an object using the 'xxhash' library, which provides
|
|
245
|
+
an extremely fast non-cryptographic hash algorithm.
|
|
246
|
+
|
|
247
|
+
Args:
|
|
248
|
+
obj_type (str): The type of the object (e.g., 'recipe', 'cookbook').
|
|
249
|
+
obj_id (str): The ID of the object.
|
|
250
|
+
obj_extension (str): The file extension (e.g., 'json', 'py').
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
str: The hex digest of the xxHash of the file content.
|
|
254
|
+
"""
|
|
255
|
+
obj_filepath = Storage.get_filepath(obj_type, obj_id, obj_extension)
|
|
256
|
+
if obj_filepath and Path(obj_filepath).exists():
|
|
257
|
+
with open(obj_filepath, "rb") as file:
|
|
258
|
+
file_content = file.read()
|
|
259
|
+
file_hash = xxhash.xxh64(file_content).hexdigest()
|
|
260
|
+
return file_hash
|
|
261
|
+
else:
|
|
262
|
+
raise RuntimeError(f"No {obj_type.lower()} found with ID: {obj_id}")
|
|
263
|
+
|
|
264
|
+
@staticmethod
|
|
265
|
+
def get_filepath(
|
|
266
|
+
obj_type: str, obj_id: str, obj_extension: str, ignore_existance: bool = False
|
|
267
|
+
) -> str:
|
|
268
|
+
"""
|
|
269
|
+
Retrieves the file path for an object.
|
|
270
|
+
|
|
271
|
+
This method uses the provided object type, object ID, and object extension to construct the file path
|
|
272
|
+
of the object. If the creation flag is set to True, it returns the file path even if the file does not exist.
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
obj_type (str): The type of the object (e.g., 'recipe', 'cookbook').
|
|
276
|
+
obj_id (str): The ID of the object.
|
|
277
|
+
obj_extension (str): The file extension (e.g., 'json', 'py').
|
|
278
|
+
ignore_existance (bool, optional): A flag indicating whether to return the file path
|
|
279
|
+
even if the file does not exist. Defaults to False.
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
str: The file path of the object.
|
|
283
|
+
"""
|
|
284
|
+
return EnvironmentVars.get_file_path(
|
|
285
|
+
obj_type, f"{obj_id}.{obj_extension}", ignore_existance
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
@staticmethod
|
|
289
|
+
@validate_call
|
|
290
|
+
def is_object_exists(obj_type: str, obj_id: str, obj_extension: str) -> bool:
|
|
291
|
+
"""
|
|
292
|
+
Checks if the object exists.
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
obj_type (str): The type of the object (e.g., 'runner', 'recipe', 'cookbook').
|
|
296
|
+
obj_id (str): The ID of the object.
|
|
297
|
+
obj_extension (str): The file extension (e.g., 'json', 'py').
|
|
298
|
+
|
|
299
|
+
Returns:
|
|
300
|
+
bool: True if the object exists, False otherwise.
|
|
301
|
+
"""
|
|
302
|
+
filepath = Storage.get_filepath(obj_type, obj_id, obj_extension)
|
|
303
|
+
if filepath:
|
|
304
|
+
return Path(filepath).exists()
|
|
305
|
+
else:
|
|
306
|
+
return False
|
|
307
|
+
|
|
308
|
+
@staticmethod
|
|
309
|
+
def create_database_connection(
|
|
310
|
+
obj_type: str, obj_id: str, obj_extension: str, db_mod_type: str = "sqlite"
|
|
311
|
+
) -> DBInterface:
|
|
312
|
+
"""
|
|
313
|
+
Establishes a database connection for a specific object.
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
obj_type (str): The type of the object for which the database connection is to be established
|
|
317
|
+
(e.g., 'runner', 'recipe', 'cookbook').
|
|
318
|
+
|
|
319
|
+
obj_id (str): The unique identifier of the object for which the database connection is to be established.
|
|
320
|
+
|
|
321
|
+
obj_extension (str): The file extension of the object for which the database connection is to be established
|
|
322
|
+
(e.g., 'json', 'py').
|
|
323
|
+
|
|
324
|
+
db_mod_type (str): The type of database module to use for establishing the connection (e.g., 'sqlite).
|
|
325
|
+
Defaults to 'sqlite'.
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
DBInterface: An instance of the database accessor, which can be used to interact with the database.
|
|
329
|
+
"""
|
|
330
|
+
database_instance = get_instance(
|
|
331
|
+
db_mod_type,
|
|
332
|
+
Storage.get_filepath(
|
|
333
|
+
EnvVariables.DATABASES_MODULES.name, db_mod_type, "py"
|
|
334
|
+
),
|
|
335
|
+
)
|
|
336
|
+
if database_instance:
|
|
337
|
+
database_instance = database_instance(
|
|
338
|
+
Path(Storage.get_filepath(obj_type, obj_id, obj_extension, True))
|
|
339
|
+
)
|
|
340
|
+
if database_instance.create_connection():
|
|
341
|
+
return database_instance
|
|
342
|
+
else:
|
|
343
|
+
raise RuntimeError(f"Failed to create connection - {db_mod_type}")
|
|
344
|
+
else:
|
|
345
|
+
raise RuntimeError(
|
|
346
|
+
f"Unable to get defined database instance - {db_mod_type}"
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
@staticmethod
|
|
350
|
+
def close_database_connection(database_instance: DBInterface) -> None:
|
|
351
|
+
"""
|
|
352
|
+
Closes the database connection.
|
|
353
|
+
|
|
354
|
+
Args:
|
|
355
|
+
database_instance (DBInterface): The instance of the database accessor.
|
|
356
|
+
|
|
357
|
+
Returns:
|
|
358
|
+
None
|
|
359
|
+
"""
|
|
360
|
+
if database_instance:
|
|
361
|
+
database_instance.close_connection()
|
|
362
|
+
else:
|
|
363
|
+
raise RuntimeError("Database instance is not initialised.")
|
|
364
|
+
|
|
365
|
+
@staticmethod
|
|
366
|
+
def create_database_table(
|
|
367
|
+
database_instance: DBInterface, sql_create_table: str
|
|
368
|
+
) -> None:
|
|
369
|
+
"""
|
|
370
|
+
Creates a table in the database.
|
|
371
|
+
|
|
372
|
+
This method is used to create a table in the database. If the database instance is not initialised,
|
|
373
|
+
it raises a RuntimeError. Otherwise, it calls the create_table method of the database instance.
|
|
374
|
+
|
|
375
|
+
Args:
|
|
376
|
+
database_instance (DBInterface): The database accessor instance.
|
|
377
|
+
sql_create_table (str): The SQL query to create a table.
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
None
|
|
381
|
+
"""
|
|
382
|
+
if database_instance:
|
|
383
|
+
database_instance.create_table(sql_create_table)
|
|
384
|
+
else:
|
|
385
|
+
raise RuntimeError("Database instance is not initialised.")
|
|
386
|
+
|
|
387
|
+
@staticmethod
|
|
388
|
+
def create_database_record(
|
|
389
|
+
database_instance: DBInterface, data: tuple, sql_create_record: str
|
|
390
|
+
) -> tuple | None:
|
|
391
|
+
"""
|
|
392
|
+
Inserts a record into the database.
|
|
393
|
+
|
|
394
|
+
This method is used to insert a record into the database. If the database instance is not initialised,
|
|
395
|
+
it raises a RuntimeError. If the database instance is initialised, it calls the create_record method of the
|
|
396
|
+
database instance with the provided data and SQL query.
|
|
397
|
+
|
|
398
|
+
Args:
|
|
399
|
+
database_instance (DBInterface): The database accessor instance.
|
|
400
|
+
data (tuple): The data to be inserted into the database.
|
|
401
|
+
sql_create_record (str): The SQL query to insert a record.
|
|
402
|
+
|
|
403
|
+
Returns:
|
|
404
|
+
tuple | None: The inserted record if successful, None otherwise.
|
|
405
|
+
"""
|
|
406
|
+
if database_instance:
|
|
407
|
+
return database_instance.create_record(data, sql_create_record)
|
|
408
|
+
else:
|
|
409
|
+
raise RuntimeError("Database instance is not initialised.")
|
|
410
|
+
|
|
411
|
+
@staticmethod
|
|
412
|
+
def read_database_record(
|
|
413
|
+
database_instance: DBInterface, data: tuple, sql_read_record: str
|
|
414
|
+
) -> tuple | None:
|
|
415
|
+
"""
|
|
416
|
+
Reads a record from the database.
|
|
417
|
+
|
|
418
|
+
This method is used to retrieve a record from the database. If the database instance is not initialised,
|
|
419
|
+
it raises a RuntimeError. If the database instance is initialised, it calls the read_record method of the
|
|
420
|
+
database instance and returns the record if found.
|
|
421
|
+
|
|
422
|
+
Args:
|
|
423
|
+
database_instance (DBInterface): The database accessor instance.
|
|
424
|
+
data (tuple): The data to be matched for reading the record.
|
|
425
|
+
sql_read_records (str): The SQL query to read a record.
|
|
426
|
+
|
|
427
|
+
Returns:
|
|
428
|
+
tuple | None: The record if found, None otherwise.
|
|
429
|
+
"""
|
|
430
|
+
if database_instance:
|
|
431
|
+
return database_instance.read_record(data, sql_read_record)
|
|
432
|
+
else:
|
|
433
|
+
raise RuntimeError("Database instance is not initialised.")
|
|
434
|
+
|
|
435
|
+
@staticmethod
|
|
436
|
+
def read_database_records(
|
|
437
|
+
database_instance: DBInterface, sql_read_records: str
|
|
438
|
+
) -> list[tuple] | None:
|
|
439
|
+
"""
|
|
440
|
+
Reads records from the database.
|
|
441
|
+
|
|
442
|
+
This method is used to retrieve records from the database. If the database instance is not initialised,
|
|
443
|
+
it raises a RuntimeError. If the database instance is initialised, it calls the read_records method of the
|
|
444
|
+
database instance and returns the record if found.
|
|
445
|
+
|
|
446
|
+
Args:
|
|
447
|
+
database_instance (DBInterface): The database accessor instance.
|
|
448
|
+
data (tuple): The data to be matched for reading the record.
|
|
449
|
+
sql_read_records (str): The SQL query to read a record.
|
|
450
|
+
|
|
451
|
+
Returns:
|
|
452
|
+
tuple | None: The record if found, None otherwise.
|
|
453
|
+
"""
|
|
454
|
+
if database_instance:
|
|
455
|
+
return database_instance.read_records(sql_read_records)
|
|
456
|
+
else:
|
|
457
|
+
raise RuntimeError("Database instance is not initialised.")
|
|
458
|
+
|
|
459
|
+
@staticmethod
|
|
460
|
+
def update_database_record(
|
|
461
|
+
database_instance: DBInterface, data: tuple, sql_update_record: str
|
|
462
|
+
) -> None:
|
|
463
|
+
"""
|
|
464
|
+
Updates a record in the database.
|
|
465
|
+
|
|
466
|
+
This method is used to update a record in the database. If the database instance is not initialised,
|
|
467
|
+
it raises a RuntimeError. Otherwise, it calls the update_record method of the database instance.
|
|
468
|
+
|
|
469
|
+
Args:
|
|
470
|
+
database_instance (DBInterface): The database accessor instance.
|
|
471
|
+
data (tuple): The data to be updated.
|
|
472
|
+
sql_update_record (str): The SQL query to update a record.
|
|
473
|
+
|
|
474
|
+
Returns:
|
|
475
|
+
None
|
|
476
|
+
"""
|
|
477
|
+
if database_instance:
|
|
478
|
+
database_instance.update_record(data, sql_update_record)
|
|
479
|
+
else:
|
|
480
|
+
raise RuntimeError("Database instance is not initialised.")
|
|
481
|
+
|
|
482
|
+
@staticmethod
|
|
483
|
+
def check_database_table_exists(
|
|
484
|
+
database_instance: DBInterface, table_name: str
|
|
485
|
+
) -> bool | None:
|
|
486
|
+
"""
|
|
487
|
+
Checks if a table exists in the database.
|
|
488
|
+
|
|
489
|
+
This method checks if the specified table exists in the database. If the database instance is not initialised,
|
|
490
|
+
it raises a RuntimeError.
|
|
491
|
+
|
|
492
|
+
Args:
|
|
493
|
+
database_instance (DBInterface): The database accessor instance.
|
|
494
|
+
table_name (str): The name of the table to check for existence.
|
|
495
|
+
|
|
496
|
+
Returns:
|
|
497
|
+
bool | None: True if the table exists, False if it does not, None if the database
|
|
498
|
+
instance is not initialised.
|
|
499
|
+
"""
|
|
500
|
+
if database_instance:
|
|
501
|
+
return database_instance.check_database_table_exists(table_name)
|
|
502
|
+
else:
|
|
503
|
+
raise RuntimeError("Database instance is not initialised.")
|
|
504
|
+
|
|
505
|
+
@staticmethod
|
|
506
|
+
def delete_database_table(
|
|
507
|
+
database_instance: DBInterface, sql_delete_table: str
|
|
508
|
+
) -> None:
|
|
509
|
+
"""
|
|
510
|
+
Deletes a table from the database.
|
|
511
|
+
|
|
512
|
+
This method is used to delete a table from the database. If the database instance is not initialised,
|
|
513
|
+
it raises a RuntimeError. Otherwise, it calls the delete_database_table method of the database instance.
|
|
514
|
+
|
|
515
|
+
Args:
|
|
516
|
+
database_instance (DBInterface): The database accessor instance.
|
|
517
|
+
sql_delete_table (str): The SQL query to delete a table.
|
|
518
|
+
|
|
519
|
+
Returns:
|
|
520
|
+
None
|
|
521
|
+
"""
|
|
522
|
+
if database_instance:
|
|
523
|
+
database_instance.delete_database_table(sql_delete_table)
|
|
524
|
+
else:
|
|
525
|
+
raise RuntimeError("Database instance is not initialised.")
|
|
File without changes
|