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.
Files changed (59) hide show
  1. {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/METADATA +2 -2
  2. {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/RECORD +59 -49
  3. moonshot/__main__.py +77 -35
  4. moonshot/api.py +14 -0
  5. moonshot/integrations/cli/benchmark/benchmark.py +29 -13
  6. moonshot/integrations/cli/benchmark/cookbook.py +36 -6
  7. moonshot/integrations/cli/benchmark/datasets.py +33 -3
  8. moonshot/integrations/cli/benchmark/metrics.py +33 -3
  9. moonshot/integrations/cli/benchmark/recipe.py +36 -6
  10. moonshot/integrations/cli/benchmark/result.py +33 -3
  11. moonshot/integrations/cli/benchmark/run.py +34 -3
  12. moonshot/integrations/cli/common/common.py +12 -6
  13. moonshot/integrations/cli/common/connectors.py +73 -9
  14. moonshot/integrations/cli/common/prompt_template.py +38 -3
  15. moonshot/integrations/cli/redteam/attack_module.py +75 -24
  16. moonshot/integrations/cli/redteam/context_strategy.py +77 -23
  17. moonshot/integrations/cli/redteam/prompt_template.py +1 -1
  18. moonshot/integrations/cli/redteam/redteam.py +52 -6
  19. moonshot/integrations/cli/redteam/session.py +539 -43
  20. moonshot/integrations/web_api/__main__.py +2 -0
  21. moonshot/integrations/web_api/app.py +6 -6
  22. moonshot/integrations/web_api/container.py +12 -2
  23. moonshot/integrations/web_api/routes/bookmark.py +173 -0
  24. moonshot/integrations/web_api/schemas/bookmark_create_dto.py +13 -0
  25. moonshot/integrations/web_api/services/bookmark_service.py +90 -0
  26. moonshot/integrations/web_api/services/utils/file_manager.py +52 -0
  27. moonshot/integrations/web_api/status_updater/moonshot_ui_webhook.py +0 -1
  28. moonshot/integrations/web_api/temp/.gitkeep +0 -0
  29. moonshot/src/api/api_bookmark.py +95 -0
  30. moonshot/src/api/api_connector_endpoint.py +1 -1
  31. moonshot/src/api/api_context_strategy.py +2 -2
  32. moonshot/src/api/api_session.py +1 -1
  33. moonshot/src/bookmark/bookmark.py +257 -0
  34. moonshot/src/bookmark/bookmark_arguments.py +38 -0
  35. moonshot/src/configs/env_variables.py +12 -2
  36. moonshot/src/connectors/connector.py +15 -7
  37. moonshot/src/connectors_endpoints/connector_endpoint.py +65 -49
  38. moonshot/src/cookbooks/cookbook.py +57 -37
  39. moonshot/src/datasets/dataset.py +9 -5
  40. moonshot/src/metrics/metric.py +8 -4
  41. moonshot/src/metrics/metric_interface.py +8 -2
  42. moonshot/src/prompt_templates/prompt_template.py +5 -1
  43. moonshot/src/recipes/recipe.py +38 -25
  44. moonshot/src/redteaming/attack/attack_module.py +18 -8
  45. moonshot/src/redteaming/attack/context_strategy.py +6 -2
  46. moonshot/src/redteaming/session/session.py +15 -11
  47. moonshot/src/results/result.py +7 -3
  48. moonshot/src/runners/runner.py +65 -42
  49. moonshot/src/runs/run.py +15 -11
  50. moonshot/src/runs/run_progress.py +7 -3
  51. moonshot/src/storage/db_interface.py +14 -0
  52. moonshot/src/storage/storage.py +33 -2
  53. moonshot/src/utils/find_feature.py +45 -0
  54. moonshot/src/utils/log.py +66 -0
  55. moonshot/src/utils/timeit.py +8 -1
  56. {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/WHEEL +0 -0
  57. {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/licenses/AUTHORS.md +0 -0
  58. {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/licenses/LICENSE.md +0 -0
  59. {aiverify_moonshot-0.4.1.dist-info → aiverify_moonshot-0.4.2.dist-info}/licenses/NOTICES.md +0 -0
@@ -0,0 +1,257 @@
1
+ from datetime import datetime
2
+
3
+ from moonshot.src.bookmark.bookmark_arguments import BookmarkArguments
4
+ from moonshot.src.configs.env_variables import EnvVariables
5
+ from moonshot.src.storage.storage import Storage
6
+ from moonshot.src.utils.log import configure_logger
7
+
8
+ # Create a logger for this module
9
+ logger = configure_logger(__name__)
10
+
11
+
12
+ class Bookmark:
13
+ _instance = None
14
+
15
+ def __new__(cls, db_name="bookmark"):
16
+ """
17
+ Create a new instance of the Bookmark class or return the existing instance.
18
+
19
+ Args:
20
+ db_name (str): The name of the database.
21
+
22
+ Returns:
23
+ Bookmark: The singleton instance of the Bookmark class.
24
+ """
25
+ if cls._instance is None:
26
+ cls._instance = super(Bookmark, cls).__new__(cls)
27
+ cls._instance.__init_instance(db_name)
28
+ return cls._instance
29
+
30
+ @classmethod
31
+ def get_instance(cls, db_name="bookmark"):
32
+ """
33
+ Get the singleton instance of the Bookmark class.
34
+
35
+ Args:
36
+ db_name (str): The name of the database.
37
+
38
+ Returns:
39
+ Bookmark: The singleton instance of the Bookmark class.
40
+ """
41
+ if cls._instance is None:
42
+ cls._instance = super(Bookmark, cls).__new__(cls)
43
+ cls._instance.__init_instance(db_name)
44
+ return cls._instance
45
+
46
+ sql_create_bookmark_table = """
47
+ CREATE TABLE IF NOT EXISTS bookmark (
48
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
49
+ name TEXT NOT NULL UNIQUE,
50
+ prompt TEXT NOT NULL,
51
+ prepared_prompt TEXT NOT NULL,
52
+ response TEXT NOT NULL,
53
+ context_strategy TEXT,
54
+ prompt_template TEXT,
55
+ attack_module TEXT,
56
+ metric TEXT,
57
+ bookmark_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
58
+ );
59
+ """
60
+
61
+ sql_insert_bookmark_record = """
62
+ INSERT INTO bookmark (
63
+ name, prompt, prepared_prompt, response, context_strategy, prompt_template, attack_module,
64
+ metric, bookmark_time)
65
+ VALUES (?,?,?,?,?,?,?,?,?);
66
+ """
67
+
68
+ sql_select_bookmarks_record = """
69
+ SELECT * FROM bookmark;
70
+ """
71
+
72
+ sql_select_bookmark_record = """
73
+ SELECT * FROM bookmark WHERE name = ? ;
74
+ """
75
+
76
+ sql_delete_bookmark_records = """
77
+ DELETE FROM bookmark;
78
+ """
79
+
80
+ def __init_instance(self, db_name) -> None:
81
+ """
82
+ Initialize the database instance for the Bookmark class.
83
+
84
+ Args:
85
+ db_name (str): The name of the database.
86
+ """
87
+ self.db_instance = Storage.create_database_connection(
88
+ EnvVariables.BOOKMARKS.name, db_name, "db"
89
+ )
90
+ Storage.create_database_table(
91
+ self.db_instance, Bookmark.sql_create_bookmark_table
92
+ )
93
+
94
+ def add_bookmark(self, bookmark: BookmarkArguments) -> dict:
95
+ """
96
+ Add a new bookmark to the database and return the success status.
97
+
98
+ Args:
99
+ bookmark (BookmarkArguments): The bookmark data to add.
100
+
101
+ Returns:
102
+ bool: True if the bookmark was added successfully, False otherwise.
103
+ """
104
+ bookmark.bookmark_time = datetime.now().replace(microsecond=0).isoformat(" ")
105
+
106
+ data = (
107
+ bookmark.name,
108
+ bookmark.prompt,
109
+ bookmark.prepared_prompt,
110
+ bookmark.response,
111
+ bookmark.context_strategy,
112
+ bookmark.prompt_template,
113
+ bookmark.attack_module,
114
+ bookmark.metric,
115
+ bookmark.bookmark_time,
116
+ )
117
+ try:
118
+ results = Storage.create_database_record(
119
+ self.db_instance, data, Bookmark.sql_insert_bookmark_record
120
+ )
121
+ if results is not None:
122
+ return {"success": True, "message": "Bookmark added successfully."}
123
+ else:
124
+ raise Exception("Error inserting record into database.")
125
+ except Exception as e:
126
+ error_message = f"Failed to add bookmark record: {e}"
127
+ return {"success": False, "message": error_message}
128
+
129
+ def get_all_bookmarks(self) -> list[dict]:
130
+ """
131
+ Retrieve all bookmarks from the database.
132
+
133
+ Returns:
134
+ list[dict]: A list of all bookmarks as dictionaries.
135
+ """
136
+ list_of_bookmarks_tuples = Storage.read_database_records(
137
+ self.db_instance,
138
+ Bookmark.sql_select_bookmarks_record,
139
+ )
140
+ if list_of_bookmarks_tuples:
141
+ list_of_bookmarks = [
142
+ BookmarkArguments.from_tuple_to_dict(bookmark_tuple)
143
+ for bookmark_tuple in list_of_bookmarks_tuples
144
+ ]
145
+ else:
146
+ list_of_bookmarks = []
147
+ return list_of_bookmarks
148
+
149
+ def get_bookmark(self, bookmark_name: str) -> dict:
150
+ """
151
+ Retrieve a bookmark by its unique name.
152
+
153
+ Args:
154
+ bookmark_name (int): The unique name for the bookmark.
155
+
156
+ Returns:
157
+ dict: The bookmark information as a dictionary.
158
+
159
+ Raises:
160
+ RuntimeError: If the bookmark cannot be found.
161
+ """
162
+ if bookmark_name is not None:
163
+ bookmark_info = Storage.read_database_record(
164
+ self.db_instance, (bookmark_name,), Bookmark.sql_select_bookmark_record
165
+ )
166
+ if bookmark_info is not None:
167
+ return BookmarkArguments.from_tuple_to_dict(bookmark_info)
168
+ else:
169
+ raise RuntimeError(
170
+ f"[Bookmark] No record found for bookmark name {bookmark_name}"
171
+ )
172
+ else:
173
+ raise RuntimeError(f"[Bookmark] Invalid bookmark name: {bookmark_name}")
174
+
175
+ def delete_bookmark(self, bookmark_name: str) -> dict:
176
+ """
177
+ Delete a bookmark by its unique name.
178
+
179
+ Args:
180
+ bookmark_name (str): The unique name for the bookmark to be deleted.
181
+ """
182
+ if bookmark_name is not None:
183
+ try:
184
+ sql_delete_bookmark_record = f"""
185
+ DELETE FROM bookmark WHERE name = '{bookmark_name}';
186
+ """
187
+ Storage.delete_database_record_in_table(
188
+ self.db_instance, sql_delete_bookmark_record
189
+ )
190
+ return {"success": True, "message": "Bookmark record deleted."}
191
+ except Exception as e:
192
+ error_message = f"Failed to delete bookmark record: {e}"
193
+ return {"success": False, "message": error_message}
194
+ else:
195
+ error_message = f"[Bookmark] Invalid bookmark name: {bookmark_name}"
196
+ return {"success": False, "message": error_message}
197
+
198
+ def delete_all_bookmark(self) -> dict:
199
+ """
200
+ Delete all bookmarks from the database and return the operation result.
201
+
202
+ Returns:
203
+ dict: A dictionary with 'success' status and 'message' containing an error message if failed.
204
+ """
205
+ try:
206
+ Storage.delete_database_record_in_table(
207
+ self.db_instance, Bookmark.sql_delete_bookmark_records
208
+ )
209
+ return {"success": True, "message": "All bookmark records deleted."}
210
+ except Exception as e:
211
+ error_message = f"Failed to delete all bookmark records: {e}"
212
+ return {"success": False, "message": error_message}
213
+
214
+ def export_bookmarks(self, export_file_name: str = "bookmarks") -> str:
215
+ """
216
+ Export all bookmarks to a JSON file.
217
+
218
+ This method retrieves all bookmarks from the database, converts them to a JSON format,
219
+ and writes them to a file in the 'moonshot-data/bookmark' directory with the provided file name.
220
+
221
+ Args:
222
+ export_file_name (str): The base name of the file to export the bookmarks to.
223
+ The '.json' extension will be appended to this base name.
224
+
225
+ Returns:
226
+ str: The path to the exported JSON file containing the bookmarks.
227
+ """
228
+ list_of_bookmarks_tuples = Storage.read_database_records(
229
+ self.db_instance,
230
+ Bookmark.sql_select_bookmarks_record,
231
+ )
232
+
233
+ if list_of_bookmarks_tuples is not None:
234
+ bookmarks_json = [
235
+ BookmarkArguments.from_tuple_to_dict(bookmark_tuple)
236
+ for bookmark_tuple in list_of_bookmarks_tuples
237
+ ]
238
+ else:
239
+ bookmarks_json = []
240
+
241
+ try:
242
+ return Storage.create_object(
243
+ EnvVariables.BOOKMARKS.name,
244
+ export_file_name,
245
+ {"bookmarks": bookmarks_json},
246
+ "json",
247
+ )
248
+ except Exception as e:
249
+ logger.error(f"Failed to export bookmarks - {str(e)}.")
250
+ raise e
251
+
252
+ def close(self) -> None:
253
+ """
254
+ Close the database connection.
255
+ """
256
+ if self.db_instance:
257
+ Storage.close_database_connection(self.db_instance)
@@ -0,0 +1,38 @@
1
+ from __future__ import annotations
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ class BookmarkArguments(BaseModel):
7
+ name: str = Field(min_length=1)
8
+ prompt: str = Field(min_length=1)
9
+ prepared_prompt: str = Field(min_length=1)
10
+ response: str = Field(min_length=1)
11
+ context_strategy: str
12
+ prompt_template: str
13
+ attack_module: str
14
+ metric: str
15
+ bookmark_time: str
16
+
17
+ @classmethod
18
+ def from_tuple_to_dict(cls, values: tuple) -> dict:
19
+ """
20
+ Creates a dictionary from a tuple of values representing BookmarkArguments fields.
21
+
22
+ Args:
23
+ values (tuple): A tuple containing the fields of BookmarkArguments in order.
24
+
25
+ Returns:
26
+ dict: A dictionary representing the BookmarkArguments.
27
+ """
28
+ return {
29
+ "name": values[1],
30
+ "prompt": values[2],
31
+ "prepared_prompt": values[3],
32
+ "response": values[4],
33
+ "context_strategy": values[5],
34
+ "prompt_template": values[6],
35
+ "attack_module": values[7],
36
+ "metric": values[8],
37
+ "bookmark_time": values[9],
38
+ }
@@ -2,11 +2,17 @@ import importlib.resources
2
2
  from enum import Enum
3
3
  from pathlib import Path
4
4
 
5
+ from moonshot.src.utils.log import configure_logger
6
+
7
+ # Create a logger for this module
8
+ logger = configure_logger(__name__)
9
+
5
10
  __app_name__ = "moonshot"
6
11
 
7
12
 
8
13
  class EnvVariables(Enum):
9
14
  ATTACK_MODULES = "ATTACK_MODULES"
15
+ BOOKMARKS = "BOOKMARKS"
10
16
  CONNECTORS = "CONNECTORS"
11
17
  CONNECTORS_ENDPOINTS = "CONNECTORS_ENDPOINTS"
12
18
  CONTEXT_STRATEGY = "CONTEXT_STRATEGY"
@@ -31,6 +37,10 @@ class EnvironmentVars:
31
37
  env_vars.get(EnvVariables.ATTACK_MODULES.value),
32
38
  str(importlib.resources.files(__app_name__).joinpath("data/attack-modules")),
33
39
  ]
40
+ BOOKMARKS = [
41
+ env_vars.get(EnvVariables.BOOKMARKS.value),
42
+ str(importlib.resources.files(__app_name__).joinpath("data/generated-outputs/bookmarks")),
43
+ ]
34
44
  CONNECTORS = [
35
45
  env_vars.get(EnvVariables.CONNECTORS.value),
36
46
  str(importlib.resources.files(__app_name__).joinpath("data/connectors")),
@@ -133,14 +143,14 @@ class EnvironmentVars:
133
143
  if given_path.exists():
134
144
  EnvironmentVars.__dict__[key][0] = str(given_path)
135
145
  else:
136
- print(
146
+ logger.warning(
137
147
  f"Unable to set {key}. The provided path {given_path} does not exist. ",
138
148
  "The stock set will be used.",
139
149
  )
140
150
  else:
141
151
  unset_keys.append(key)
142
152
  if unset_keys:
143
- print(
153
+ logger.warning(
144
154
  f"Unable to retrieve the following environment variables: {unset_keys}. The stock set will be used."
145
155
  )
146
156
 
@@ -15,6 +15,10 @@ from moonshot.src.connectors_endpoints.connector_endpoint_arguments import (
15
15
  )
16
16
  from moonshot.src.storage.storage import Storage
17
17
  from moonshot.src.utils.import_modules import get_instance
18
+ from moonshot.src.utils.log import configure_logger
19
+
20
+ # Create a logger for this module
21
+ logger = configure_logger(__name__)
18
22
 
19
23
 
20
24
  def perform_retry(func):
@@ -42,13 +46,15 @@ def perform_retry(func):
42
46
  try:
43
47
  return await func(self, *args, **kwargs)
44
48
  except Exception as exc:
45
- print(f"Operation failed. {str(exc)} - Retrying...")
49
+ logger.warning(f"Operation failed. {str(exc)} - Retrying...")
46
50
 
47
51
  # Perform retry
48
52
  retry_count += 1
49
53
  if retry_count <= self.retries_times:
50
54
  delay = base_delay * (2**retry_count)
51
- print(f"Attempt {retry_count}, Retrying in {delay} seconds...")
55
+ logger.warning(
56
+ f"Attempt {retry_count}, Retrying in {delay} seconds..."
57
+ )
52
58
  await sleep(delay)
53
59
  # Raise an exception
54
60
  raise ConnectionError("Failed to get response.")
@@ -228,7 +234,7 @@ class Connector:
228
234
  return Connector.load(ep_args)
229
235
 
230
236
  except Exception as e:
231
- print(f"Failed to create connector: {str(e)}")
237
+ logger.error(f"Failed to create connector: {str(e)}")
232
238
  raise e
233
239
 
234
240
  @staticmethod
@@ -255,7 +261,7 @@ class Connector:
255
261
  ]
256
262
 
257
263
  except Exception as e:
258
- print(f"Failed to get available connectors: {str(e)}")
264
+ logger.error(f"Failed to get available connectors: {str(e)}")
259
265
  raise e
260
266
 
261
267
  @staticmethod
@@ -292,14 +298,16 @@ class Connector:
292
298
  Exception: If there is an error during prediction.
293
299
  """
294
300
  try:
295
- print(f"Predicting prompt {generated_prompt.prompt_index} [{connector.id}]")
301
+ logger.info(
302
+ f"Predicting prompt {generated_prompt.prompt_index} [{connector.id}]"
303
+ )
296
304
 
297
305
  start_time = time.perf_counter()
298
306
  generated_prompt.predicted_results = await connector.get_response(
299
307
  generated_prompt.prompt
300
308
  )
301
309
  generated_prompt.duration = time.perf_counter() - start_time
302
- print(
310
+ logger.debug(
303
311
  f"[Prompt {generated_prompt.prompt_index}] took {generated_prompt.duration:.4f}s"
304
312
  )
305
313
 
@@ -311,7 +319,7 @@ class Connector:
311
319
  return generated_prompt
312
320
 
313
321
  except Exception as e:
314
- print(f"Failed to get prediction: {str(e)}")
322
+ logger.error(f"Failed to get prediction: {str(e)}")
315
323
  raise e
316
324
 
317
325
  def set_system_prompt(self, system_prompt: str) -> None:
@@ -8,33 +8,39 @@ from moonshot.src.connectors_endpoints.connector_endpoint_arguments import (
8
8
  ConnectorEndpointArguments,
9
9
  )
10
10
  from moonshot.src.storage.storage import Storage
11
+ from moonshot.src.utils.log import configure_logger
12
+
13
+ # Create a logger for this module
14
+ logger = configure_logger(__name__)
11
15
 
12
16
 
13
17
  class ConnectorEndpoint:
14
18
  @staticmethod
15
19
  def create(ep_args: ConnectorEndpointArguments) -> str:
16
20
  """
17
- Creates a new connector endpoint.
21
+ Creates a new connector endpoint and stores its details as a JSON object.
22
+
23
+ This method accepts a ConnectorEndpointArguments object, generates a unique slugified ID from the endpoint's
24
+ name, and stores the endpoint's details in a JSON file within a specified directory.
18
25
 
19
- This method takes a ConnectorEndpointArguments object as input, generates a unique slugified ID based on the
20
- endpoint's name, and then creates a new endpoint with the provided details. The endpoint information is stored
21
- as a JSON object in the directory specified by `EnvVariables.CONNECTORS_ENDPOINTS`. If the operation is
22
- successful, the unique ID of the new endpoint is returned. If any error arises during the process, an exception
23
- is raised and the error message is logged.
26
+ The directory path is determined by the `EnvVariables.CONNECTORS_ENDPOINTS` environment variable.
27
+ Upon successful creation, the method returns the unique ID of the endpoint.
28
+ If an error occurs during the creation process, the method raises an exception and logs the error message.
24
29
 
25
30
  Args:
26
- ep_args (ConnectorEndpointArguments): An object containing the details of the endpoint to be created.
31
+ ep_args (ConnectorEndpointArguments): The details of the endpoint to be created,
32
+ encapsulated in a ConnectorEndpointArguments object.
27
33
 
28
34
  Returns:
29
- str: The unique ID of the newly created endpoint.
35
+ str: The unique ID of the newly created endpoint, derived from slugifying the endpoint's name.
30
36
 
31
37
  Raises:
32
- Exception: If there's an error during the endpoint creation process.
38
+ Exception: If an error occurs during the creation process, including issues with storing the endpoint's
39
+ details.
33
40
  """
34
41
  try:
35
42
  ep_id = slugify(ep_args.name, lowercase=True)
36
43
  ep_info = {
37
- "id": ep_id,
38
44
  "name": ep_args.name,
39
45
  "connector_type": ep_args.connector_type,
40
46
  "uri": ep_args.uri,
@@ -51,59 +57,63 @@ class ConnectorEndpoint:
51
57
  return ep_id
52
58
 
53
59
  except Exception as e:
54
- print(f"Failed to create endpoint: {str(e)}")
60
+ logger.error(f"Failed to create endpoint: {str(e)}")
55
61
  raise e
56
62
 
57
63
  @staticmethod
58
64
  @validate_call
59
65
  def read(ep_id: str) -> ConnectorEndpointArguments:
60
66
  """
61
- Fetches the details of a given endpoint.
67
+ Retrieves the details of a specified endpoint by its ID.
62
68
 
63
- This method takes an endpoint ID as input, finds the corresponding JSON file in the directory
64
- specified by `EnvironmentVars.CONNECTORS_ENDPOINTS`, and returns a ConnectorEndpointArguments object
65
- that contains the endpoint's details. If any error arises during the process, an exception is raised and the
66
- error message is logged.
69
+ This method searches for the endpoint's corresponding JSON file within the directory defined by the
70
+ `EnvVariables.CONNECTORS_ENDPOINTS` environment variable. It then constructs and returns a
71
+ ConnectorEndpointArguments object populated with the endpoint's details. If the endpoint ID is not found or
72
+ any other error occurs, an exception is raised with an appropriate error message.
67
73
 
68
74
  Args:
69
- ep_id (str): The unique ID of the endpoint to be fetched.
75
+ ep_id (str): The unique identifier of the endpoint whose details are to be retrieved.
70
76
 
71
77
  Returns:
72
- ConnectorEndpointArguments: An object encapsulating the details of the fetched endpoint.
78
+ ConnectorEndpointArguments: An instance filled with the endpoint's details.
73
79
 
74
80
  Raises:
75
- Exception: If there's an error during the file reading process or any other operation within the method.
81
+ RuntimeError: If the endpoint ID is empty or the specified endpoint does not exist.
82
+ Exception: For any issues encountered during the file reading or data parsing process.
76
83
  """
77
84
  try:
78
- if ep_id:
79
- return ConnectorEndpointArguments(
80
- **ConnectorEndpoint._read_endpoint(ep_id)
81
- )
82
- else:
83
- raise RuntimeError("Connector Endpoint ID is empty")
85
+ if not ep_id:
86
+ raise RuntimeError("Connector Endpoint ID is empty.")
87
+
88
+ endpoint_details = ConnectorEndpoint._read_endpoint(ep_id)
89
+ if not endpoint_details:
90
+ raise RuntimeError(f"Endpoint with ID '{ep_id}' does not exist.")
91
+
92
+ return ConnectorEndpointArguments(**endpoint_details)
84
93
 
85
94
  except Exception as e:
86
- print(f"Failed to read endpoint: {str(e)}")
95
+ logger.error(f"Failed to read endpoint: {str(e)}")
87
96
  raise e
88
97
 
89
98
  @staticmethod
90
99
  def _read_endpoint(ep_id: str) -> dict:
91
100
  """
92
- Reads the endpoint information from a JSON file and adds the creation datetime.
101
+ Retrieves the endpoint's information from a JSON file, including its creation datetime.
93
102
 
94
- This method accepts an endpoint ID as an argument, locates the corresponding JSON file in the directory
95
- defined by `EnvironmentVars.CONNECTORS_ENDPOINTS`, and returns a dictionary that encapsulates the endpoint's
96
- details along with its creation datetime. If any error occurs during the process, it is handled by the calling
97
- method.
103
+ This internal method is designed to fetch the details of a specific endpoint by its ID. It searches for the
104
+ corresponding JSON file within the directory specified by `EnvVariables.CONNECTORS_ENDPOINTS`. The method
105
+ returns a dictionary containing the endpoint's information, enriched with the creation datetime. Errors
106
+ encountered during this process are managed by the method that invokes this one.
98
107
 
99
108
  Args:
100
- ep_id (str): The unique identifier of the endpoint to be retrieved.
109
+ ep_id (str): The unique identifier of the endpoint whose information is being retrieved.
101
110
 
102
111
  Returns:
103
- dict: A dictionary containing the details of the retrieved endpoint along with its creation datetime.
112
+ dict: A dictionary with the endpoint's information, including its creation datetime.
104
113
  """
105
- connector_endpoint_info = Storage.read_object(
106
- EnvVariables.CONNECTORS_ENDPOINTS.name, ep_id, "json"
114
+ connector_endpoint_info = {"id": ep_id}
115
+ connector_endpoint_info.update(
116
+ Storage.read_object(EnvVariables.CONNECTORS_ENDPOINTS.name, ep_id, "json")
107
117
  )
108
118
  creation_datetime = Storage.get_creation_datetime(
109
119
  EnvVariables.CONNECTORS_ENDPOINTS.name, ep_id, "json"
@@ -116,35 +126,41 @@ class ConnectorEndpoint:
116
126
  @staticmethod
117
127
  def update(ep_args: ConnectorEndpointArguments) -> bool:
118
128
  """
119
- Updates the endpoint information based on the provided arguments.
129
+ Updates the endpoint information in the storage based on the provided ConnectorEndpointArguments object.
130
+
131
+ This method serializes the provided ConnectorEndpointArguments object into a dictionary, excluding the 'id' and
132
+ 'created_date' keys. It then persists the updated information to the corresponding JSON file within the
133
+ directory defined by `EnvVariables.CONNECTORS_ENDPOINTS`.
120
134
 
121
- This method takes a ConnectorEndpointArguments object, converts it to a dictionary, and removes the
122
- 'created_date' key if it exists. It then writes the updated information to the corresponding JSON file
123
- in the directory specified by `EnvVariables.CONNECTORS_ENDPOINTS`.
135
+ This operation ensures that the endpoint's mutable attributes are updated according to the provided arguments.
124
136
 
125
137
  Args:
126
- ep_args (ConnectorEndpointArguments): An object containing the updated details of the endpoint.
138
+ ep_args (ConnectorEndpointArguments): The object encapsulating the updated attributes of the endpoint.
127
139
 
128
140
  Returns:
129
- bool: True if the update operation was successful.
141
+ bool: Indicates whether the update operation was successful. Returns True if the update was successfully
142
+ persisted to the storage; otherwise, an exception is raised.
130
143
 
131
144
  Raises:
132
- Exception: If there's an error during the update process.
145
+ Exception: Signifies a failure in the update process, potentially due to issues with data serialization or
146
+ storage access.
133
147
  """
134
148
  try:
135
- # Convert the endpoint arguments to a dictionary
136
- # Remove created_date if it exists
149
+ # Serialize the ConnectorEndpointArguments object to a dictionary and remove derived properties
137
150
  ep_info = ep_args.to_dict()
138
- ep_info.pop("created_date", None)
151
+ ep_info.pop("id", None) # The 'id' is derived and should not be written
152
+ ep_info.pop(
153
+ "created_date", None
154
+ ) # The 'created_date' is derived and should not be written
139
155
 
140
- # Write the updated endpoint information to the file
156
+ # Write the updated endpoint information to the storage
141
157
  Storage.create_object(
142
158
  EnvVariables.CONNECTORS_ENDPOINTS.name, ep_args.id, ep_info, "json"
143
159
  )
144
160
  return True
145
161
 
146
162
  except Exception as e:
147
- print(f"Failed to update endpoint: {str(e)}")
163
+ logger.error(f"Failed to update endpoint: {str(e)}")
148
164
  raise e
149
165
 
150
166
  @staticmethod
@@ -171,7 +187,7 @@ class ConnectorEndpoint:
171
187
  return True
172
188
 
173
189
  except Exception as e:
174
- print(f"Failed to delete endpoint: {str(e)}")
190
+ logger.error(f"Failed to delete endpoint: {str(e)}")
175
191
  raise e
176
192
 
177
193
  @staticmethod
@@ -207,5 +223,5 @@ class ConnectorEndpoint:
207
223
  return retn_eps_ids, retn_eps
208
224
 
209
225
  except Exception as e:
210
- print(f"Failed to get available endpoints: {str(e)}")
226
+ logger.error(f"Failed to get available endpoints: {str(e)}")
211
227
  raise e