pyegeria 5.4.8__py3-none-any.whl → 5.4.8.3__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 (31) hide show
  1. md_processing/__init__.py +2 -1
  2. md_processing/data/commands.json +59579 -52198
  3. md_processing/dr_egeria.py +7 -5
  4. md_processing/md_commands/solution_architect_commands.py +54 -10
  5. md_processing/md_processing_utils/common_md_proc_utils.py +8 -4
  6. md_processing/md_processing_utils/common_md_utils.py +41 -2
  7. pyegeria/_base_client.py +1 -17
  8. pyegeria/_client_new.py +1008 -323
  9. pyegeria/_client_new_backup.py +5359 -0
  10. pyegeria/_exceptions_new.py +6 -1
  11. pyegeria/base_report_formats.py +31 -2
  12. pyegeria/classification_manager.py +1430 -357
  13. pyegeria/collection_manager.py +52 -54
  14. pyegeria/config.py +1 -0
  15. pyegeria/data_designer.py +41 -41
  16. pyegeria/external_links.py +26 -26
  17. pyegeria/feedback_manager_omvs.py +13 -31
  18. pyegeria/glossary_manager.py +32 -35
  19. pyegeria/governance_officer.py +31 -31
  20. pyegeria/output_formatter.py +36 -11
  21. pyegeria/output_formatter_with_machine_keys.py +1127 -0
  22. pyegeria/project_manager.py +21 -21
  23. pyegeria/reference_data.py +2 -2
  24. pyegeria/solution_architect.py +112 -91
  25. {pyegeria-5.4.8.dist-info → pyegeria-5.4.8.3.dist-info}/METADATA +6 -5
  26. {pyegeria-5.4.8.dist-info → pyegeria-5.4.8.3.dist-info}/RECORD +30 -29
  27. pyegeria/md_processing_utils_orig.py +0 -1103
  28. {pyegeria-5.4.8.dist-info → pyegeria-5.4.8.3.dist-info}/WHEEL +0 -0
  29. {pyegeria-5.4.8.dist-info → pyegeria-5.4.8.3.dist-info}/entry_points.txt +0 -0
  30. {pyegeria-5.4.8.dist-info → pyegeria-5.4.8.3.dist-info}/licenses/LICENSE +0 -0
  31. {pyegeria-5.4.8.dist-info → pyegeria-5.4.8.3.dist-info}/top_level.txt +0 -0
pyegeria/_client_new.py CHANGED
@@ -12,6 +12,7 @@ import os
12
12
  import re
13
13
  import time
14
14
  from collections.abc import Callable
15
+ from datetime import datetime
15
16
  from typing import Any
16
17
 
17
18
  from httpx import Response
@@ -28,11 +29,12 @@ from pyegeria.base_report_formats import select_report_spec
28
29
  from pyegeria.models import (SearchStringRequestBody, FilterRequestBody, GetRequestBody, NewElementRequestBody,
29
30
  TemplateRequestBody, UpdateStatusRequestBody, UpdateElementRequestBody,
30
31
  NewRelationshipRequestBody,
31
- DeleteRequestBody, UpdateRelationshipRequestBody, ResultsRequestBody,
32
+ UpdateRelationshipRequestBody, ResultsRequestBody,
32
33
  NewClassificationRequestBody,
33
34
  DeleteElementRequestBody, DeleteRelationshipRequestBody, DeleteClassificationRequestBody,
34
35
  LevelIdentifierQueryBody)
35
- from pyegeria.output_formatter import populate_common_columns, resolve_output_formats, generate_output
36
+ from pyegeria.output_formatter import populate_common_columns, resolve_output_formats, generate_output, \
37
+ overlay_additional_values
36
38
  from pyegeria.utils import body_slimmer, dynamic_catch
37
39
 
38
40
  ...
@@ -102,7 +104,6 @@ class Client2(BaseClient):
102
104
  self._update_status_request_adapter = TypeAdapter(UpdateStatusRequestBody)
103
105
  self._new_relationship_request_adapter = TypeAdapter(NewRelationshipRequestBody)
104
106
  self._new_classification_request_adapter = TypeAdapter(NewClassificationRequestBody)
105
- self._delete_request_adapter = TypeAdapter(DeleteRequestBody)
106
107
  self._delete_element_request_adapter = TypeAdapter(DeleteElementRequestBody)
107
108
  self._delete_relationship_request_adapter = TypeAdapter(DeleteRelationshipRequestBody)
108
109
  self._delete_classification_request_adapter = TypeAdapter(DeleteClassificationRequestBody)
@@ -511,7 +512,7 @@ class Client2(BaseClient):
511
512
  - Normally false. Set true when the caller is part of a deduplication function
512
513
  start_from: int, default = 0
513
514
  - index of the list to start from (0 for start).
514
- page_size
515
+ page_size: int, default = 0
515
516
  - maximum number of elements to return.
516
517
  time_out: int, default = default_time_out
517
518
  - http request timeout for this request
@@ -536,7 +537,7 @@ class Client2(BaseClient):
536
537
 
537
538
  async def _async_get_guid_for_name(
538
539
  self, name: str, property_name: list[str] = ["qualifiedName", "displayName"],
539
- type_name: str = "ValidMetadataValue"
540
+ type_name: str = None
540
541
 
541
542
  ) -> list | str:
542
543
  """
@@ -548,7 +549,7 @@ class Client2(BaseClient):
548
549
  name: str
549
550
  - element name to be searched.
550
551
  property_name: [str], default = ["qualifiedName","displayName"]
551
- - propertys to search in.
552
+ - properties to search in.
552
553
  type_name: str, default = "ValidMetadataValue"
553
554
  - metadata element type name to be used to restrict the search
554
555
  Returns
@@ -570,6 +571,8 @@ class Client2(BaseClient):
570
571
  raise PyegeriaException(context={"issue": "Multiple elements found for supplied name!"})
571
572
  elif len(elements) == 1:
572
573
  return elements[0]["elementHeader"]["guid"]
574
+ else:
575
+ return NO_ELEMENTS_FOUND
573
576
  return elements
574
577
 
575
578
  def get_guid_for_name(
@@ -585,7 +588,7 @@ class Client2(BaseClient):
585
588
  name: str
586
589
  - element name to be searched.
587
590
  property_name: [str], default = ["qualifiedName","displayName"]
588
- - propertys to search in.
591
+ - properties to search in.
589
592
  type_name: str, default = "ValidMetadataValue"
590
593
  - metadata element type name to be used to restrict the search
591
594
  Returns
@@ -595,7 +598,7 @@ class Client2(BaseClient):
595
598
 
596
599
  Raises
597
600
  ------
598
- PyegeriaExeception
601
+ PyegeriaException
599
602
  """
600
603
 
601
604
  loop = asyncio.get_event_loop()
@@ -742,7 +745,7 @@ class Client2(BaseClient):
742
745
  relationship_type="RegisteredIntegrationConnector",
743
746
  property_names=["connectorName"],
744
747
  property_value=connector_name,
745
- )
748
+ )
746
749
  if rel == "No elements found":
747
750
  logger.error(f"\n\n===> No connector found with name '{connector_name}'\n\n")
748
751
  return "No connector found"
@@ -771,12 +774,12 @@ class Client2(BaseClient):
771
774
  return result
772
775
 
773
776
  async def _async_add_archive_file(
774
- self,
775
- archive_file: str,
776
- server_guid: str = None,
777
- display_name: str = None,
778
- qualified_name: str = None,
779
- time_out: int = 120,
777
+ self,
778
+ archive_file: str,
779
+ server_guid: str = None,
780
+ display_name: str = None,
781
+ qualified_name: str = None,
782
+ time_out: int = 120,
780
783
  ) -> None:
781
784
  """Add a new open metadata archive to running OMAG Server's repository.
782
785
  An open metadata archive contains metadata types and instances. This operation loads an open metadata archive
@@ -826,12 +829,12 @@ class Client2(BaseClient):
826
829
  return
827
830
 
828
831
  def add_archive_file(
829
- self,
830
- archive_file: str,
831
- server_guid: str = None,
832
- display_name: str = None,
833
- qualified_name: str = None,
834
- time_out: int = 120,
832
+ self,
833
+ archive_file: str,
834
+ server_guid: str = None,
835
+ display_name: str = None,
836
+ qualified_name: str = None,
837
+ time_out: int = 120,
835
838
  ) -> None:
836
839
  """Add a new open metadata archive to running OMAG Server's repository.
837
840
  An open metadata archive contains metadata types and instances. This operation loads an open metadata archive
@@ -872,7 +875,6 @@ class Client2(BaseClient):
872
875
  )
873
876
  return
874
877
 
875
-
876
878
  #
877
879
  # Common feedback commands
878
880
  #
@@ -919,7 +921,7 @@ class Client2(BaseClient):
919
921
  """
920
922
  if body is None:
921
923
  body = {
922
- "class": "NewFeedbackRequestBody",
924
+ "class": "NewAttachmentRequestBody",
923
925
  "properties": {
924
926
  "class": "CommentProperties",
925
927
  "qualifiedName": self.make_feedback_qn("Reply", comment_guid),
@@ -1004,7 +1006,7 @@ class Client2(BaseClient):
1004
1006
  """
1005
1007
  if body is None:
1006
1008
  body = {
1007
- "class": "NewFeedbackRequestBody",
1009
+ "class": "NewAttachmentRequestBody",
1008
1010
  "properties": {
1009
1011
  "class": "CommentProperties",
1010
1012
  "qualifiedName": self.make_feedback_qn("Comment", element_guid),
@@ -1217,11 +1219,10 @@ class Client2(BaseClient):
1217
1219
 
1218
1220
  ) -> None:
1219
1221
  """
1220
- Link a comment that contains the best answer to a question posed in another comment. Async version.
1222
+ Remove the accepted-answer link between a question comment and its answer. Async version.
1221
1223
 
1222
1224
  Parameters
1223
1225
  ----------
1224
-
1225
1226
  question_comment_guid: str
1226
1227
  - unique id for the question comment.
1227
1228
  answer_comment_guid: str
@@ -1234,7 +1235,6 @@ class Client2(BaseClient):
1234
1235
  Raises
1235
1236
  ------
1236
1237
  PyEgeriaException
1237
-
1238
1238
  """
1239
1239
 
1240
1240
  url = f"{self.command_root}feedback-manager/comments/questions/{question_comment_guid}/answers/{answer_comment_guid}/remove"
@@ -1247,11 +1247,10 @@ class Client2(BaseClient):
1247
1247
 
1248
1248
  ) -> None:
1249
1249
  """
1250
- Link a comment that contains the best answer to a question posed in another comment.
1250
+ Remove the accepted-answer link between a question comment and its answer.
1251
1251
 
1252
1252
  Parameters
1253
1253
  ----------
1254
-
1255
1254
  question_comment_guid: str
1256
1255
  - unique id for the question comment.
1257
1256
  answer_comment_guid: str
@@ -1264,7 +1263,6 @@ class Client2(BaseClient):
1264
1263
  Raises
1265
1264
  ------
1266
1265
  PyEgeriaException
1267
-
1268
1266
  """
1269
1267
 
1270
1268
  loop = asyncio.get_event_loop()
@@ -1274,9 +1272,8 @@ class Client2(BaseClient):
1274
1272
 
1275
1273
  async def _async_remove_comment_from_element(
1276
1274
  self,
1277
- element_guid: str,
1278
1275
  comment_guid: str,
1279
- body: dict | DeleteRequestBody = None,
1276
+ body: dict | DeleteElementRequestBody = None,
1280
1277
  cascade_delete: bool = False,
1281
1278
  ) -> None:
1282
1279
  """
@@ -1296,7 +1293,7 @@ class Client2(BaseClient):
1296
1293
 
1297
1294
  Returns
1298
1295
  -------
1299
- VoidResponse
1296
+ None
1300
1297
 
1301
1298
  Raises
1302
1299
  ------
@@ -1306,34 +1303,36 @@ class Client2(BaseClient):
1306
1303
  cascade_delete ():
1307
1304
  """
1308
1305
 
1309
- url = f"{self.command_root}feedback-manager/elements/{element_guid}/comments/{comment_guid}/remove"
1306
+ url = f"{self.command_root}feedback-manager/comments/{comment_guid}/remove"
1310
1307
  await self._async_delete_element_request(url, body, cascade_delete)
1311
1308
 
1312
1309
  def remove_comment_from_element(
1313
1310
  self,
1314
1311
  element_guid: str,
1315
1312
  comment_guid: str,
1316
- body: dict | DeleteRequestBody = None,
1313
+ body: dict | DeleteElementRequestBody = None,
1317
1314
  cascade_delete: bool = False,
1318
1315
 
1319
1316
  ) -> None:
1320
1317
  """
1321
- Removes a comment added to the element by this user.
1318
+ Remove a comment from an element added by this user.
1322
1319
 
1323
1320
  This deletes the link to the comment, the comment itself and any comment replies attached to it.
1324
1321
 
1325
1322
  Parameters
1326
1323
  ----------
1327
- comment_guid
1328
- - String - unique id for the comment object
1329
- body
1330
- - containing type of comment enum and the text of the comment.
1331
- cascade_delete: bool = False
1332
-
1324
+ element_guid: str
1325
+ - unique id for the element
1326
+ comment_guid: str
1327
+ - unique id for the comment object
1328
+ body: dict | DeleteElementRequestBody, optional
1329
+ - contains comment type and text
1330
+ cascade_delete: bool, default = False
1331
+ - whether to cascade delete
1333
1332
 
1334
1333
  Returns
1335
1334
  -------
1336
- VoidResponse
1335
+ None
1337
1336
 
1338
1337
  Raises
1339
1338
  ------
@@ -1530,7 +1529,6 @@ class Client2(BaseClient):
1530
1529
  )
1531
1530
  return response
1532
1531
 
1533
-
1534
1532
  async def _async_find_comments(
1535
1533
  self,
1536
1534
  search_string: str = None,
@@ -1692,7 +1690,7 @@ class Client2(BaseClient):
1692
1690
  @dynamic_catch
1693
1691
  async def _async_create_note_log(
1694
1692
  self,
1695
- element_guid: str,
1693
+ element_guid: str = None,
1696
1694
  display_name: str = None,
1697
1695
  description: str = None,
1698
1696
  body: dict = None,
@@ -1702,8 +1700,8 @@ class Client2(BaseClient):
1702
1700
 
1703
1701
  Parameters
1704
1702
  ----------
1705
- element_guid: str
1706
- - unique identifier of the element where the note log is located
1703
+ element_guid: str, optional
1704
+ - unique identifier of the element where the note log is attached
1707
1705
  display_name: str, optional
1708
1706
  - name of the note log
1709
1707
  description: str, optional
@@ -1724,7 +1722,7 @@ class Client2(BaseClient):
1724
1722
  Sample Body:
1725
1723
 
1726
1724
  {
1727
- "class" : "NewFeedbackRequestBody",
1725
+ "class" : "NewAttachmentRequestBody",
1728
1726
  "initialClassifications": {
1729
1727
  "ZoneMembership" : {
1730
1728
  "class" : "ZoneMembershipProperties",
@@ -1745,7 +1743,7 @@ class Client2(BaseClient):
1745
1743
  """
1746
1744
  if body is None:
1747
1745
  body = {
1748
- "class": "NewFeedbackRequestBody",
1746
+ "class": "NewAttachmentRequestBody",
1749
1747
  "properties": {
1750
1748
  "class": "NoteLogProperties",
1751
1749
  "displayName": display_name,
@@ -1757,14 +1755,17 @@ class Client2(BaseClient):
1757
1755
  context = {"issue": "Invalid display name and body not provided"}
1758
1756
  raise PyegeriaInvalidParameterException(context=context)
1759
1757
 
1760
- url = f"{self.command_root}feedback-manager/elements/{element_guid}/note-logs"
1758
+ if element_guid:
1759
+ url = f"{self.command_root}feedback-manager/elements/{element_guid}/note-logs"
1760
+ else:
1761
+ url = f"{self.command_root}feedback-manager/elements/note-logs"
1761
1762
  response = await self._async_make_request("POST", url, body_slimmer(body))
1762
1763
  return response.json()
1763
1764
 
1764
1765
  @dynamic_catch
1765
1766
  def create_note_log(
1766
1767
  self,
1767
- element_guid: str,
1768
+ element_guid: str = None,
1768
1769
  display_name: str = None,
1769
1770
  description: str = None,
1770
1771
  body: dict = None,
@@ -1774,8 +1775,8 @@ class Client2(BaseClient):
1774
1775
 
1775
1776
  Parameters
1776
1777
  ----------
1777
- element_guid
1778
- - unique identifier of the element where the note log is located
1778
+ element_guid, str, optional
1779
+ - unique identifier of the element where the note log is attached
1779
1780
  display_name: str, optional
1780
1781
  - name of the note log
1781
1782
  description: str, optional
@@ -1796,7 +1797,7 @@ class Client2(BaseClient):
1796
1797
  Sample Body:
1797
1798
 
1798
1799
  {
1799
- "class" : "NewFeedbackRequestBody",
1800
+ "class" : "NewAttachmentRequestBody",
1800
1801
  "initialClassifications": {
1801
1802
  "ZoneMembership" : {
1802
1803
  "class" : "ZoneMembershipProperties",
@@ -1961,7 +1962,7 @@ class Client2(BaseClient):
1961
1962
  async def _async_remove_note_log(
1962
1963
  self,
1963
1964
  note_log_guid: str,
1964
- body: dict | DeleteRequestBody = None,
1965
+ body: dict | DeleteElementRequestBody = None,
1965
1966
  cascade_delete: bool = False,
1966
1967
  ) -> None:
1967
1968
  """
@@ -1971,14 +1972,14 @@ class Client2(BaseClient):
1971
1972
  ----------
1972
1973
  note_log_guid: str
1973
1974
  - String - unique id for the note log.
1974
- body: dict | DeleteRequestBody, optional
1975
+ body: dict | DeleteElementRequestBody, optional
1975
1976
  - containing type of comment enum and the text of the comment.
1976
1977
  cascade_delete: bool, optional
1977
1978
  - If True, deletes all comments and replies associated with the note log.
1978
1979
 
1979
1980
  Returns
1980
1981
  -------
1981
- VoidResponse
1982
+ None
1982
1983
 
1983
1984
  Raises
1984
1985
  ------
@@ -1986,34 +1987,32 @@ class Client2(BaseClient):
1986
1987
 
1987
1988
  """
1988
1989
 
1989
- url = f"{self.command_root}feedback-manager/elements/{note_log_guid}/remove"
1990
+ url = f"{self.command_root}feedback-manager/note-logs/{note_log_guid}/remove"
1990
1991
  await self._async_delete_element_request(url, body, cascade_delete)
1991
1992
 
1992
1993
  @dynamic_catch
1993
1994
  def remove_note_log(
1994
1995
  self,
1995
1996
  note_log_guid: str,
1996
- body: dict | DeleteRequestBody = None,
1997
+ body: dict | DeleteElementRequestBody = None,
1997
1998
  cascade_delete: bool = False,
1998
1999
 
1999
2000
  ) -> None:
2000
2001
  """
2001
- Removes a comment added to the element by this user.
2002
-
2003
- This deletes the link to the comment, the comment itself and any comment replies attached to it.
2002
+ Remove a note log from the repository. All relationships to referenceables are lost.
2004
2003
 
2005
2004
  Parameters
2006
2005
  ----------
2007
- note_log_guid
2008
- - String - unique id for the comment object
2009
- body
2010
- - containing type of comment enum and the text of the comment.
2011
- cascade_delete: bool = False
2012
-
2006
+ note_log_guid: str
2007
+ - unique id for the note log
2008
+ body: dict | DeleteElementRequestBody, optional
2009
+ - request body details (if provided, supersedes other parameters)
2010
+ cascade_delete: bool, default = False
2011
+ - if True, deletes all comments and replies associated with the note log
2013
2012
 
2014
2013
  Returns
2015
2014
  -------
2016
- VoidResponse
2015
+ None
2017
2016
 
2018
2017
  Raises
2019
2018
  ------
@@ -2097,7 +2096,7 @@ class Client2(BaseClient):
2097
2096
 
2098
2097
  url = f"{self.command_root}feedback-manager/note-logs/by-search-string"
2099
2098
  response = await self._async_find_request(url, _type="NoteLog",
2100
- _gen_output=self._generate_note_log_output,
2099
+ _gen_output=self._generate_feedback_output,
2101
2100
  search_string=search_string,
2102
2101
  classification_names=classification_names,
2103
2102
  metadata_element_types=metadata_element_types,
@@ -2169,7 +2168,7 @@ class Client2(BaseClient):
2169
2168
  return resp
2170
2169
 
2171
2170
  @dynamic_catch
2172
- async def _async_get_note_logs_by_gname(
2171
+ async def _async_get_note_logs_by_name(
2173
2172
  self, filter: str,
2174
2173
  element_type: str = "NoteLog",
2175
2174
  body: dict | FilterRequestBody = None,
@@ -2201,7 +2200,7 @@ class Client2(BaseClient):
2201
2200
 
2202
2201
  url = f"{self.command_root}feedback-manager/note-logs/by-name"
2203
2202
  response = await self._async_get_name_request(url, _type=element_type,
2204
- _gen_output=self._generate_note_log_output, start_from=start_from,
2203
+ _gen_output=self._generate_feedback_output, start_from=start_from,
2205
2204
  page_size=page_size, output_format=output_format,
2206
2205
  report_spec=report_spec,
2207
2206
  body=body)
@@ -2240,7 +2239,7 @@ class Client2(BaseClient):
2240
2239
  """
2241
2240
  loop = asyncio.get_event_loop()
2242
2241
  response = loop.run_until_complete(
2243
- self._async_get_note_log_by_name(filter, element_type, body, output_format, report_spec, start_from,
2242
+ self._async_get_note_logs_by_name(filter, element_type, body, output_format, report_spec, start_from,
2244
2243
  page_size)
2245
2244
  )
2246
2245
  return response
@@ -2288,7 +2287,7 @@ class Client2(BaseClient):
2288
2287
  if element == NO_ELEMENTS_FOUND:
2289
2288
  return NO_ELEMENTS_FOUND
2290
2289
  if output_format != 'JSON': # return a simplified markdown representation
2291
- return self._generate_note_log_output(element, None, output_format, report_spec)
2290
+ return self._generate_feedback_output(element, None, output_format, report_spec)
2292
2291
  return response.json().get("elements", NO_ELEMENTS_FOUND)
2293
2292
 
2294
2293
  @dynamic_catch
@@ -2505,6 +2504,183 @@ class Client2(BaseClient):
2505
2504
  )
2506
2505
  return response
2507
2506
 
2507
+ @dynamic_catch
2508
+ async def _async_add_journal_entry(self, note_log_qn: str = None, element_qn: str = None, note_log_display_name: str = None, journal_entry_display_name: str = None, journal_entry_description: str = None,
2509
+ body: dict | NewElementRequestBody = None ) -> str:
2510
+ """
2511
+ Creates a new journal entry for a note log and returns the unique identifier for it. The note_log will be
2512
+ created if it does not exist. Async version.
2513
+
2514
+ Parameters
2515
+ ----------
2516
+ note_log_qn: str = None
2517
+ - If provided, the journal entry will be attached to this note log. If not provided, a new note_log will be created.
2518
+ element_qn: str = None
2519
+ - If provided, and note log needs to be created, this will be used to define the new note log and attach it
2520
+ to the specified element.
2521
+ note_log_display_name: str = None
2522
+ - optional note log display name
2523
+ journal_entry_display_name: str = None
2524
+ - optional journal entry display name
2525
+ journal_entry_description: str = None
2526
+ - the journal entry text
2527
+
2528
+ body
2529
+ - optional body for the note - if provided, details here will supercede other parameters.
2530
+
2531
+ Returns
2532
+ -------
2533
+ GUID for the journal entry (note).
2534
+
2535
+ Raises
2536
+ ------
2537
+ PyegeriaException
2538
+
2539
+ Notes
2540
+ _____
2541
+
2542
+ Sample body (a note is an asset)
2543
+ {
2544
+ "class" : "NewElementRequestBody",
2545
+ "anchorGUID" : "{{noteLogGUID}}",
2546
+ "isOwnAnchor": false,
2547
+ "parentGUID": "{{noteLogGUID}}",
2548
+ "parentRelationshipTypeName": "AttachedNoteLogEntry",
2549
+ "parentAtEnd1": true,
2550
+ "properties": {
2551
+ "class" : "NotificationProperties",
2552
+ "typeName" : "Notification",
2553
+ "qualifiedName": "add unique name here",
2554
+ "displayName": "add short name here",
2555
+ "description": "add description here",
2556
+ "systemAction" : "add optional system action that occurred as part of this notification processing",
2557
+ "userResponse" : "add optional action that the reader should take",
2558
+ "priority" : 1,
2559
+ "activityStatus" : "FOR_INFO",
2560
+ "additionalProperties": {
2561
+ "property1" : "propertyValue1",
2562
+ "property2" : "propertyValue2"
2563
+ },
2564
+ "extendedProperties": {
2565
+ "property1" : "propertyValue1",
2566
+ "property2" : "propertyValue2"
2567
+ },
2568
+ "effectiveFrom": "{{$isoTimestamp}}",
2569
+ "effectiveTo": "{{$isoTimestamp}}"
2570
+ },
2571
+ "externalSourceGUID": "add guid here",
2572
+ "externalSourceName": "add qualified name here",
2573
+ "effectiveTime" : "{{$isoTimestamp}}",
2574
+ "forLineage" : false,
2575
+ "forDuplicateProcessing" : false
2576
+ }
2577
+
2578
+ """
2579
+ note_log_guid = None
2580
+ element_guid = None
2581
+ # If a note_log_qn has been provided, look up its GUID
2582
+ if note_log_qn:
2583
+ note_log_guid = await self._async_get_guid_for_name(note_log_qn, ["qualifiedName"],'NoteLog' ) if note_log_qn else None
2584
+
2585
+ # If we need to create a new note_log, then use the qualified name from the element_qn parameter, if provided.
2586
+ if note_log_guid is None or note_log_guid == NO_ELEMENTS_FOUND:
2587
+ if element_qn is None:
2588
+ if note_log_display_name is None:
2589
+ note_log_display_name = f"NoName-{datetime.now().strftime('%Y-%m-%d %H:%M')}"
2590
+
2591
+ else:
2592
+ element_guid = await self._async_get_guid_for_name(element_qn, ["qualifiedName"])
2593
+
2594
+ note_log = await self._async_create_note_log(element_guid = element_guid, display_name = note_log_display_name)
2595
+ note_log_guid = note_log["guid"]
2596
+
2597
+ # Create the Journal Entry (Note)
2598
+ journal_entry_guid = await self._async_create_note(note_log_guid, journal_entry_display_name,
2599
+ journal_entry_description, body)
2600
+
2601
+ return journal_entry_guid
2602
+
2603
+ @dynamic_catch
2604
+ def add_journal_entry(self, note_log_qn: str = None, element_qn: str = None,
2605
+ note_log_display_name: str = None, journal_entry_display_name: str = None,
2606
+ journal_entry_description: str = None,
2607
+ body: dict | NewElementRequestBody = None) -> str:
2608
+ """
2609
+ Creates a new journal entry for a note log and returns the unique identifier for it. The note_log will be
2610
+ created if it does not exist.
2611
+
2612
+ Parameters
2613
+ ----------
2614
+ note_log_qn: str = None
2615
+ - If provided, the journal entry will be attached to this note log. If not provided, a new note_log will be created.
2616
+ element_qn: str = None
2617
+ - If provided, and note log needs to be created, this will be used to define the new note log and attach it
2618
+ to the specified element.
2619
+ note_log_display_name: str = None
2620
+ - optional note log display name
2621
+ journal_entry_display_name: str = None
2622
+ - optional journal entry display name
2623
+ journal_entry_description: str = None
2624
+ - the journal entry text
2625
+
2626
+ body
2627
+ - optional body for the note - if provided, details here will supercede other parameters.
2628
+
2629
+ Returns
2630
+ -------
2631
+ GUID for the journal entry (note).
2632
+
2633
+ Raises
2634
+ ------
2635
+ PyegeriaException
2636
+
2637
+ Notes
2638
+ _____
2639
+
2640
+ Sample body (a note is an asset)
2641
+ {
2642
+ "class" : "NewElementRequestBody",
2643
+ "anchorGUID" : "{{noteLogGUID}}",
2644
+ "isOwnAnchor": false,
2645
+ "parentGUID": "{{noteLogGUID}}",
2646
+ "parentRelationshipTypeName": "AttachedNoteLogEntry",
2647
+ "parentAtEnd1": true,
2648
+ "properties": {
2649
+ "class" : "NotificationProperties",
2650
+ "typeName" : "Notification",
2651
+ "qualifiedName": "add unique name here",
2652
+ "displayName": "add short name here",
2653
+ "description": "add description here",
2654
+ "systemAction" : "add optional system action that occurred as part of this notification processing",
2655
+ "userResponse" : "add optional action that the reader should take",
2656
+ "priority" : 1,
2657
+ "activityStatus" : "FOR_INFO",
2658
+ "additionalProperties": {
2659
+ "property1" : "propertyValue1",
2660
+ "property2" : "propertyValue2"
2661
+ },
2662
+ "extendedProperties": {
2663
+ "property1" : "propertyValue1",
2664
+ "property2" : "propertyValue2"
2665
+ },
2666
+ "effectiveFrom": "{{$isoTimestamp}}",
2667
+ "effectiveTo": "{{$isoTimestamp}}"
2668
+ },
2669
+ "externalSourceGUID": "add guid here",
2670
+ "externalSourceName": "add qualified name here",
2671
+ "effectiveTime" : "{{$isoTimestamp}}",
2672
+ "forLineage" : false,
2673
+ "forDuplicateProcessing" : false
2674
+ }
2675
+
2676
+ """
2677
+ loop = asyncio.get_event_loop()
2678
+ response = loop.run_until_complete(
2679
+ self._async_add_journal_entry(note_log_qn, element_qn, note_log_display_name, journal_entry_display_name, journal_entry_description, body)
2680
+ )
2681
+ return response
2682
+
2683
+
2508
2684
  @dynamic_catch
2509
2685
  async def _async_update_note(self, note_guid: str, display_name: str = None, description: str = None,
2510
2686
  body: dict | UpdateElementRequestBody = None, merge_update: bool = True) -> None:
@@ -2687,7 +2863,7 @@ class Client2(BaseClient):
2687
2863
  PyegeriaException
2688
2864
  """
2689
2865
  url = f"{self.command_root}feedback-manager/assets/{note_guid}/delete"
2690
- await self._async_delete_request(url, body)
2866
+ await self._async_delete_element_request(url, body)
2691
2867
 
2692
2868
  @dynamic_catch
2693
2869
  def remove_note(
@@ -2774,19 +2950,19 @@ class Client2(BaseClient):
2774
2950
 
2775
2951
  url = f"{self.command_root}feedback-manager/assets/by-search-string"
2776
2952
  response = await self._async_find_request(url, "Notification", self._generate_feedback_output,
2777
- search_string, [], ["Notification"],
2953
+ search_string, None, ["Notification"] ,
2778
2954
  starts_with, ends_with, ignore_case,
2779
2955
  start_from, page_size, output_format, report_spec,
2780
- body, )
2956
+ body )
2781
2957
  return response
2782
2958
 
2783
2959
  @dynamic_catch
2784
2960
  def find_notes(
2785
2961
  self, search_string: str = None,
2786
2962
  body: dict | SearchStringRequestBody = None,
2787
- starts_with: bool = None,
2788
- ends_with: bool = None,
2789
- ignore_case: bool = None,
2963
+ starts_with: bool = True,
2964
+ ends_with: bool = False,
2965
+ ignore_case: bool = False,
2790
2966
  start_from: int = 0,
2791
2967
  page_size: int = 0,
2792
2968
  output_format: str = "JSON",
@@ -2936,7 +3112,7 @@ class Client2(BaseClient):
2936
3112
 
2937
3113
  """
2938
3114
 
2939
- url = f"{self.command_root}feedback-manager/note-logs/by-name"
3115
+ url = f"{self.command_root}feedback-manager/note-logs/{note_log_guid}/retrieve"
2940
3116
  response = await self._async_get_results_body_request(url, "Notification", self._generate_feedback_output,
2941
3117
  0, 0, output_format, report_spec, body)
2942
3118
  return response
@@ -2979,16 +3155,14 @@ class Client2(BaseClient):
2979
3155
  )
2980
3156
  return response
2981
3157
 
2982
-
2983
-
2984
3158
  #
2985
3159
  # Tags
2986
3160
  #
2987
3161
  @dynamic_catch
2988
3162
  async def _async_create_informal_tag(
2989
- self,
2990
- display_name: str,
2991
- description: str
3163
+ self,
3164
+ display_name: str,
3165
+ description: str
2992
3166
  ) -> str:
2993
3167
  """
2994
3168
  Creates a new informal tag and returns the unique identifier for it. Async Version.
@@ -3011,7 +3185,7 @@ class Client2(BaseClient):
3011
3185
  """
3012
3186
  url = f"{self.command_root}feedback-manager/tags"
3013
3187
  if display_name is None:
3014
- raise PyegeriaInvalidParameterException(context = {"reason": "display_name is required"})
3188
+ raise PyegeriaInvalidParameterException(context={"reason": "display_name is required"})
3015
3189
  body = {
3016
3190
  "class": "TagProperties",
3017
3191
  "displayName": display_name,
@@ -3020,7 +3194,6 @@ class Client2(BaseClient):
3020
3194
  response = await self._async_make_request("POST", url, body)
3021
3195
  return response.json()
3022
3196
 
3023
-
3024
3197
  @dynamic_catch
3025
3198
  def create_informal_tag(
3026
3199
  self,
@@ -3054,9 +3227,9 @@ class Client2(BaseClient):
3054
3227
 
3055
3228
  @dynamic_catch
3056
3229
  async def _async_update_tag_description(
3057
- self,
3058
- tag_guid: str,
3059
- description: str,
3230
+ self,
3231
+ tag_guid: str,
3232
+ description: str,
3060
3233
 
3061
3234
  ) -> None:
3062
3235
  """
@@ -3072,7 +3245,7 @@ class Client2(BaseClient):
3072
3245
 
3073
3246
  Returns
3074
3247
  -------
3075
- VoidResponse :
3248
+ None
3076
3249
 
3077
3250
  Raises
3078
3251
  ------
@@ -3089,29 +3262,28 @@ class Client2(BaseClient):
3089
3262
 
3090
3263
  @dynamic_catch
3091
3264
  def update_tag_description(
3092
- self,
3093
- tag_guid: str,
3094
- description: str,
3265
+ self,
3266
+ tag_guid: str,
3267
+ description: str,
3095
3268
 
3096
3269
  ) -> None:
3097
3270
  """
3098
- Updates the description of an existing tag. Async version.
3271
+ Update the description of an existing tag.
3099
3272
 
3100
- Parameters
3101
- ----------
3102
-
3103
- tag_guid
3104
- - unique id for the tag
3105
- description: str
3273
+ Parameters
3274
+ ----------
3275
+ tag_guid: str
3276
+ - unique id for the tag
3277
+ description: str
3106
3278
  - description of the tag
3107
3279
 
3108
- Returns
3109
- -------
3110
- VoidResponse :
3280
+ Returns
3281
+ -------
3282
+ None
3111
3283
 
3112
- Raises
3113
- ------
3114
- PyegeriaException
3284
+ Raises
3285
+ ------
3286
+ PyegeriaException
3115
3287
  """
3116
3288
  loop = asyncio.get_event_loop()
3117
3289
  response = loop.run_until_complete(
@@ -3140,7 +3312,7 @@ class Client2(BaseClient):
3140
3312
  - String - unique id for the tag.
3141
3313
  Returns
3142
3314
  -------
3143
- VOIDResponse
3315
+ None
3144
3316
 
3145
3317
  Raises
3146
3318
  ------
@@ -3181,7 +3353,6 @@ class Client2(BaseClient):
3181
3353
  self._async_delete_tag(tag_guid)
3182
3354
  )
3183
3355
 
3184
-
3185
3356
  @dynamic_catch
3186
3357
  async def _async_get_tag(
3187
3358
  self,
@@ -3224,7 +3395,6 @@ class Client2(BaseClient):
3224
3395
  output_format, report_spec, body)
3225
3396
  return response
3226
3397
 
3227
-
3228
3398
  @dynamic_catch
3229
3399
  def get_tag(
3230
3400
  self,
@@ -3232,7 +3402,7 @@ class Client2(BaseClient):
3232
3402
  body: dict | GetRequestBody = None,
3233
3403
  output_format: str = "json",
3234
3404
  report_spec: str = None,
3235
- ) -> dict | str:
3405
+ ) -> dict | str:
3236
3406
  """
3237
3407
  Return the informal tag for the supplied unique identifier (tag_guid).
3238
3408
 
@@ -3296,7 +3466,7 @@ class Client2(BaseClient):
3296
3466
 
3297
3467
  url = f"{self.command_root}feedback-manager/tags/by-name"
3298
3468
 
3299
- response = await self._async_get_name_request(url,"InformalTag", self._generate_feedback_output,
3469
+ response = await self._async_get_name_request(url, "InformalTag", self._generate_feedback_output,
3300
3470
  tag_name, [], start_from,
3301
3471
  page_size, output_format, report_spec)
3302
3472
  return response
@@ -3351,7 +3521,7 @@ class Client2(BaseClient):
3351
3521
  search_string: str = None,
3352
3522
  body: dict | SearchStringRequestBody = None,
3353
3523
  starts_with: bool = True,
3354
- ends_with: bool = False,
3524
+ ends_with: bool = False,
3355
3525
  ignore_case: bool = False,
3356
3526
  start_from: int = 0,
3357
3527
  page_size: int = max_paging_size, output_format: str = "json", report_spec: str = None,
@@ -3392,7 +3562,7 @@ class Client2(BaseClient):
3392
3562
 
3393
3563
  url = f"{self.command_root}feedback-manager/tags/by-search-string"
3394
3564
  response = await self._async_find_request(url, "InformalTag", self._generate_feedback_output,
3395
- search_string, [],[],
3565
+ search_string, [], [],
3396
3566
  starts_with, ends_with, ignore_case,
3397
3567
  start_from, page_size, output_format,
3398
3568
  report_spec, body)
@@ -3401,14 +3571,13 @@ class Client2(BaseClient):
3401
3571
  @dynamic_catch
3402
3572
  def find_tags(
3403
3573
  self,
3404
- search_string: str = None,
3574
+ search_string: str = None,
3405
3575
  body: dict | SearchStringRequestBody = None,
3406
3576
  starts_with: bool = True,
3407
3577
  ends_with: bool = False,
3408
3578
  ignore_case: bool = False,
3409
3579
  start_from: int = 0,
3410
3580
  page_size: int = max_paging_size, output_format: str = "json", report_spec: str = None,
3411
-
3412
3581
  ) -> dict | str:
3413
3582
  """
3414
3583
  Return the list of informal tags containing the supplied string in their name or description. The search string
@@ -3449,137 +3618,126 @@ class Client2(BaseClient):
3449
3618
  )
3450
3619
  return response
3451
3620
 
3621
+ async def _async_find_my_tags(
3622
+ self,
3623
+ search_string: str = None,
3624
+ body: dict | SearchStringRequestBody = None,
3625
+ starts_with: bool = None,
3626
+ ends_with: bool = None,
3627
+ ignore_case: bool = None,
3628
+ start_from: int = 0,
3629
+ page_size: int = max_paging_size,
3452
3630
 
3453
- # async def _async_find_my_tags(
3454
- # self,
3455
- # body: str,
3456
- # starts_with: bool = None,
3457
- # ends_with: bool = None,
3458
- # ignore_case: bool = None,
3459
- # start_from: int = 0,
3460
- # page_size: int = max_paging_size,
3461
- #
3462
- # ) -> dict | str:
3463
- # """
3464
- # Return the list of the calling user's private tags containing the supplied string in either the name or description. The search string is a regular expression (RegEx).
3465
- #
3466
- #
3467
- # Parameters
3468
- # ----------
3469
- #
3470
- # starts_with
3471
- # - does the value start with the supplied string?
3472
- # ends_with
3473
- # - does the value end with the supplied string?
3474
- # ignore_case
3475
- # - should the search ignore case?
3476
- # start_from
3477
- # - index of the list to start from (0 for start).
3478
- # page_size
3479
- # - maximum number of elements to return.
3480
- # view_service_url_marker
3481
- # - optional view service URL marker (overrides access_service_url_marker)
3482
- # access_service_url_marker
3483
- # - optional access service URL marker used to identify which back end service to call
3484
- # body
3485
- # - search string and effective time.
3486
- #
3487
- # Returns
3488
- # -------
3489
- # list of tag objects
3490
- #
3491
- # Raises
3492
- # ------
3493
- # InvalidParameterException
3494
- # one of the parameters is null or invalid or
3495
- # PropertyServerException
3496
- # There is a problem adding the element properties to the metadata repository or
3497
- # UserNotAuthorizedException
3498
- # the requesting user is not authorized to issue this request.
3499
- # """
3500
- #
3501
- # url = f"{self.command_root}feedback-manager/tags/update"
3502
- # response = await self._async_make_request("POST", url, body)
3503
- # return response
3504
- #
3505
- # def find_my_tags(
3506
- # self,
3507
- # body: str,
3508
- # starts_with: bool = None,
3509
- # ends_with: bool = None,
3510
- # ignore_case: bool = None,
3511
- # start_from: int = 0,
3512
- # page_size: int = max_paging_size,
3513
- #
3514
- # ) -> dict | str:
3515
- # """
3516
- # Return the list of the calling user's private tags containing the supplied string in either the name or description. The search string is a regular expression (RegEx).
3517
- #
3518
- #
3519
- # Parameters
3520
- # ----------
3521
- #
3522
- # starts_with
3523
- # - does the value start with the supplied string?
3524
- # ends_with
3525
- # - does the value end with the supplied string?
3526
- # ignore_case
3527
- # - should the search ignore case?
3528
- # start_from
3529
- # - index of the list to start from (0 for start).
3530
- # page_size
3531
- # - maximum number of elements to return.
3532
- # view_service_url_marker
3533
- # - optional view service URL marker (overrides access_service_url_marker)
3534
- # access_service_url_marker
3535
- # - optional access service URL marker used to identify which back end service to call
3536
- # body
3537
- # - search string and effective time.
3538
- #
3539
- # Returns
3540
- # -------
3541
- # list of tag objects
3542
- #
3543
- # Raises
3544
- # ------
3545
- # InvalidParameterException
3546
- # one of the parameters is null or invalid or
3547
- # PropertyServerException
3548
- # There is a problem adding the element properties to the metadata repository or
3549
- # UserNotAuthorizedException
3550
- # the requesting user is not authorized to issue this request.
3551
- # """
3552
- # loop = asyncio.get_event_loop()
3553
- # response = loop.run_until_complete(
3554
- # self._async_find_my_tags(
3555
- # body,
3556
- # starts_with=starts_with,
3557
- # ends_with=ends_with,
3558
- # ignore_case=ignore_case,
3559
- # start_from=start_from,
3560
- # page_size=page_size,
3561
- #
3562
- # )
3563
- # )
3564
- # return response
3565
-
3566
- @dynamic_catch
3567
- async def _async_add_tag_to_element(
3568
- self,
3569
- element_guid: str,
3570
- tag_guid: str,
3571
- is_public: bool = False,
3572
- body: dict| NewRelationshipRequestBody = None,
3573
-
3574
- ) -> None:
3631
+ ) -> dict | str:
3575
3632
  """
3576
- Adds an informal tag (either private of public) to an element. Async Version.
3633
+ Return the list of the calling user's private tags containing the supplied string in either the name or description.
3577
3634
 
3578
3635
  Parameters
3579
3636
  ----------
3580
-
3581
- element_guid
3582
- - unique id for the element.
3637
+ search_string: str
3638
+ - string to search for.
3639
+ body: dict | SearchStringRequestBody
3640
+ - details of the request. Supersedes other parameters if present.
3641
+ starts_with
3642
+ - does the value start with the supplied string?
3643
+ ends_with
3644
+ - does the value end with the supplied string?
3645
+ ignore_case
3646
+ - should the search ignore case?
3647
+ start_from
3648
+ - index of the list to start from (0 for start).
3649
+ page_size
3650
+ - maximum number of elements to return.
3651
+
3652
+ Returns
3653
+ -------
3654
+ list of tag objects
3655
+
3656
+ Raises
3657
+ ------
3658
+ PyegeriaException
3659
+ """
3660
+
3661
+ url = f"{self.command_root}feedback-manager/tags/update"
3662
+ response = await self._async_make_request("POST", url, body)
3663
+ return response
3664
+
3665
+ def find_my_tags(
3666
+ self,
3667
+ search_string: str = None,
3668
+ body: dict | SearchStringRequestBody = None,
3669
+ starts_with: bool = None,
3670
+ ends_with: bool = None,
3671
+ ignore_case: bool = None,
3672
+ start_from: int = 0,
3673
+ page_size: int = max_paging_size,
3674
+
3675
+ ) -> dict | str:
3676
+ """
3677
+ Return the list of the calling user's private tags containing the supplied string in either the name or description.
3678
+
3679
+ Parameters
3680
+ ----------
3681
+ search_string: str
3682
+ body: dict | SearchStringRequestBody
3683
+ - detailed request - supersedes other parameters.
3684
+ starts_with
3685
+ - does the value start with the supplied string?
3686
+ ends_with
3687
+ - does the value end with the supplied string?
3688
+ ignore_case
3689
+ - should the search ignore case?
3690
+ start_from
3691
+ - index of the list to start from (0 for start).
3692
+ page_size
3693
+ - maximum number of elements to return.
3694
+
3695
+
3696
+ Returns
3697
+ -------
3698
+ list of tag objects
3699
+
3700
+ Raises
3701
+ ------
3702
+ InvalidParameterException
3703
+ one of the parameters is null or invalid or
3704
+ PropertyServerException
3705
+ There is a problem adding the element properties to the metadata repository or
3706
+ UserNotAuthorizedException
3707
+ the requesting user is not authorized to issue this request.
3708
+ """
3709
+ loop = asyncio.get_event_loop()
3710
+ response = loop.run_until_complete(
3711
+ self._async_find_my_tags(
3712
+ search_string,
3713
+ body,
3714
+ starts_with=starts_with,
3715
+ ends_with=ends_with,
3716
+ ignore_case=ignore_case,
3717
+ start_from=start_from,
3718
+ page_size=page_size,
3719
+
3720
+ )
3721
+ )
3722
+ return response
3723
+
3724
+ @dynamic_catch
3725
+ async def _async_add_tag_to_element(
3726
+ self,
3727
+ element_guid: str,
3728
+ tag_guid: str,
3729
+ is_public: bool = False,
3730
+ body: dict | NewRelationshipRequestBody = None,
3731
+
3732
+ ) -> None:
3733
+ """
3734
+ Adds an informal tag (either private of public) to an element. Async Version.
3735
+
3736
+ Parameters
3737
+ ----------
3738
+
3739
+ element_guid
3740
+ - unique id for the element.
3583
3741
  tag_guid
3584
3742
  - unique id of the tag.
3585
3743
 
@@ -3596,11 +3754,9 @@ class Client2(BaseClient):
3596
3754
  """
3597
3755
  is_public_s = str(is_public).lower()
3598
3756
 
3599
-
3600
3757
  url = f"{self.command_root}feedback-manager/elements/{element_guid}/tags/{tag_guid}?isPublic={is_public_s}"
3601
3758
  await self._async_new_relationship_request(url, 'InformalTag', body)
3602
3759
 
3603
-
3604
3760
  @dynamic_catch
3605
3761
  def add_tag_to_element(
3606
3762
  self,
@@ -3644,12 +3800,11 @@ class Client2(BaseClient):
3644
3800
 
3645
3801
  @dynamic_catch
3646
3802
  async def _async_get_elements_by_tag(
3647
- self,
3648
- tag_guid: str,
3649
- body: dict = {},
3650
- start_from: int = 0,
3651
- page_size: int = max_paging_size,
3652
-
3803
+ self,
3804
+ tag_guid: str,
3805
+ body: dict = {},
3806
+ start_from: int = 0,
3807
+ page_size: int = max_paging_size,
3653
3808
 
3654
3809
  ) -> dict | str:
3655
3810
  """
@@ -3684,14 +3839,13 @@ class Client2(BaseClient):
3684
3839
  response = await self._async_make_request("POST", url, body)
3685
3840
  return response.json()
3686
3841
 
3687
-
3688
3842
  @dynamic_catch
3689
3843
  def get_elements_by_tag(
3690
- self,
3691
- tag_guid: str,
3692
- body: dict = {},
3693
- start_from: int = 0,
3694
- page_size: int = max_paging_size,
3844
+ self,
3845
+ tag_guid: str,
3846
+ body: dict = {},
3847
+ start_from: int = 0,
3848
+ page_size: int = 0,
3695
3849
 
3696
3850
  ) -> dict | str:
3697
3851
  """
@@ -3723,22 +3877,17 @@ class Client2(BaseClient):
3723
3877
  """
3724
3878
  loop = asyncio.get_event_loop()
3725
3879
  response = loop.run_until_complete(
3726
- self._async_get_elements_by_tag(
3727
- tag_guid,
3728
- body,
3729
- start_from,
3730
- page_size,
3731
- )
3880
+ self._async_get_elements_by_tag(tag_guid, body, start_from, page_size)
3732
3881
  )
3733
3882
  return response
3734
3883
 
3735
3884
  @dynamic_catch
3736
3885
  async def _async_get_attached_tags(
3737
- self,
3738
- element_guid: str,
3739
- body: dict = {},
3740
- start_from: int = 0,
3741
- page_size: int = max_paging_size,
3886
+ self,
3887
+ element_guid: str,
3888
+ body: dict = {},
3889
+ start_from: int = 0,
3890
+ page_size: int = max_paging_size,
3742
3891
 
3743
3892
  ) -> dict | str:
3744
3893
  """
@@ -3769,14 +3918,13 @@ class Client2(BaseClient):
3769
3918
  response = await self._async_make_request("POST", url, body)
3770
3919
  return response.json()
3771
3920
 
3772
-
3773
3921
  @dynamic_catch
3774
3922
  def get_attached_tags(
3775
- self,
3776
- element_guid: str,
3777
- body: dict = {},
3778
- start_from: int = 0,
3779
- page_size: int = max_paging_size,
3923
+ self,
3924
+ element_guid: str,
3925
+ body: dict = {},
3926
+ start_from: int = 0,
3927
+ page_size: int = max_paging_size,
3780
3928
 
3781
3929
  ) -> dict | str:
3782
3930
  """
@@ -3818,7 +3966,6 @@ class Client2(BaseClient):
3818
3966
  )
3819
3967
  return response
3820
3968
 
3821
-
3822
3969
  async def _async_remove_tag_from_element(
3823
3970
  self,
3824
3971
  element_guid: str,
@@ -3906,6 +4053,517 @@ class Client2(BaseClient):
3906
4053
  )
3907
4054
  return response
3908
4055
 
4056
+ #
4057
+ # Search Tags
4058
+ #
4059
+ @dynamic_catch
4060
+ async def _async_add_search_keyword_to_element(
4061
+ self,
4062
+ element_guid: str,
4063
+ keyword: str = None,
4064
+ body: dict = None
4065
+ ) -> str:
4066
+ """
4067
+ Creates a search keyword and attaches it to an element.
4068
+ The GUID returned is the identifier of the relationship. Async Version.
4069
+
4070
+ Parameters
4071
+ ----------
4072
+ element_guid: str
4073
+ - the identity of the element to update
4074
+ keyword: str = None
4075
+ - the name of the search keyword to add
4076
+ body: dict, optional
4077
+ - structure containing search string information - see Notes
4078
+
4079
+ Returns
4080
+ -------
4081
+ Guid of the search keyword.
4082
+
4083
+ Raises
4084
+ ------
4085
+ PyegeriaException
4086
+
4087
+ Notes
4088
+ -----
4089
+ Sample body:
4090
+ {
4091
+ "class" : "NewAttachmentRequestBody",
4092
+ "properties" : {
4093
+ "class" : "SearchKeywordProperties",
4094
+ "keyword" : "myKeyword",
4095
+ "description" : "Add search keyword text here"
4096
+ }
4097
+ }
4098
+
4099
+ """
4100
+ if body is None and keyword:
4101
+ body = {
4102
+ "class": "NewAttachmentRequestBody",
4103
+ "properties": {
4104
+ "class": "SearchKeywordProperties",
4105
+ "keyword": keyword
4106
+ }
4107
+ }
4108
+ elif body is None:
4109
+ raise PyegeriaInvalidParameterException(context={"reason": "keyword or body is required"})
4110
+
4111
+ url = f"{self.command_root}classification-manager/elements/{element_guid}/search-keywords"
4112
+
4113
+ response = await self._async_make_request("POST", url, body_slimmer(body))
4114
+ return response.json().get('guid', 'Search keyword was not created')
4115
+
4116
+ @dynamic_catch
4117
+ def add_search_keyword_to_element(
4118
+ self,
4119
+ element_guid: str,
4120
+ keyword: str = None,
4121
+ body: dict = None,
4122
+ ) -> str:
4123
+ """
4124
+ Creates a search keyword and attaches it to an element.
4125
+ The GUID returned is the identifier of the relationship.
4126
+
4127
+ Parameters
4128
+ ----------
4129
+ element_guid: str
4130
+ - the identity of the element to update
4131
+ keyword: str = None
4132
+ - the name of the search keyword to add
4133
+ body: dict, optional
4134
+ - structure containing search string information - see Notes
4135
+
4136
+ Returns
4137
+ -------
4138
+ Guid of the search keyword.
4139
+
4140
+ Raises
4141
+ ------
4142
+ PyegeriaException
4143
+
4144
+ Notes
4145
+ -----
4146
+ Sample body:
4147
+ {
4148
+ "class" : "NewAttachmentRequestBody",
4149
+ "properties" : {
4150
+ "class" : "SearchKeywordProperties",
4151
+ "keyword" : "myKeyword",
4152
+ "description" : "Add search keyword text here"
4153
+ }
4154
+ }
4155
+
4156
+ """
4157
+
4158
+ loop = asyncio.get_event_loop()
4159
+ response = loop.run_until_complete(
4160
+ self._async_add_search_keyword_to_element(element_guid, keyword, body)
4161
+ )
4162
+ return response
4163
+
4164
+
4165
+ @dynamic_catch
4166
+ async def _async_update_search_keyword(
4167
+ self,
4168
+ keyword_guid: str,
4169
+ body: dict | UpdateElementRequestBody = None,
4170
+ ) -> str:
4171
+ """
4172
+ Update the properties of a search keyword. Async Version.
4173
+
4174
+ Parameters
4175
+ ----------
4176
+ keyword_guid: str
4177
+ - identity of the keyword to update
4178
+ body: dict | UpdateElementRequestBody, optional
4179
+ - structure containing keyword information - see Notes
4180
+
4181
+ Returns
4182
+ -------
4183
+ None
4184
+
4185
+ Raises
4186
+ ------
4187
+ PyegeriaException
4188
+
4189
+ Notes
4190
+ -----
4191
+ Sample body:
4192
+ {
4193
+ "class" : "UpdateElementRequestBody",
4194
+ "mergeUpdate": true,
4195
+ "properties" : {
4196
+ "class" : "SearchKeywordProperties",
4197
+ "keyword" : "myKeyword",
4198
+ "description" : "Add search keyword text here"
4199
+ }
4200
+ }
4201
+
4202
+ """
4203
+
4204
+ url = f"{self.command_root}classification-manager/search-keywords/{keyword_guid}/update"
4205
+ await self._async_update_relationship_request(url, None, body_slimmer(body))
4206
+
4207
+ @dynamic_catch
4208
+ def update_search_keyword(
4209
+ self,
4210
+ keyword_guid: str,
4211
+ body: dict | UpdateElementRequestBody = None,
4212
+ ) -> None:
4213
+ """
4214
+ Update the properties of a search keyword.
4215
+
4216
+ Parameters
4217
+ ----------
4218
+ keyword_guid: str
4219
+ - identity of the keyword to update
4220
+ body: dict | UpdateElementRequestBody, optional
4221
+ - structure containing keyword information - see Notes
4222
+
4223
+ Returns
4224
+ -------
4225
+ None
4226
+
4227
+ Raises
4228
+ ------
4229
+ PyegeriaException
4230
+
4231
+ Notes
4232
+ -----
4233
+ Sample body:
4234
+ {
4235
+ "class" : "UpdateElementRequestBody",
4236
+ "mergeUpdate": true,
4237
+ "properties" : {
4238
+ "class" : "SearchKeywordProperties",
4239
+ "keyword" : "myKeyword",
4240
+ "description" : "Add search keyword text here"
4241
+ }
4242
+ }
4243
+
4244
+ """
4245
+
4246
+ loop = asyncio.get_event_loop()
4247
+ loop.run_until_complete(
4248
+ self._async_update_search_keyword(keyword_guid, body)
4249
+ )
4250
+
4251
+ @dynamic_catch
4252
+ async def _async_remove_search_keyword(
4253
+ self,
4254
+ keyword_guid: str
4255
+ ) -> None:
4256
+ """
4257
+ Remove the search keyword for an element. Async Version.
4258
+
4259
+ Parameters
4260
+ ----------
4261
+ keyword_guid: str
4262
+ - identity of the search keyword to remove.
4263
+
4264
+ Returns
4265
+ -------
4266
+
4267
+ Raises
4268
+ ------
4269
+ PyegeriaException
4270
+
4271
+
4272
+ """
4273
+
4274
+ url = f"{self.command_root}classification-manager/search-keywords/{keyword_guid}/remove"
4275
+ await self._async_delete_relationship_request(url = url, body = None, cascade_delete = False)
4276
+
4277
+ @dynamic_catch
4278
+ def remove_search_keyword(
4279
+ self,
4280
+ keyword_guid,
4281
+ ) -> None:
4282
+ """
4283
+ Remove the search keyword for an element.
4284
+
4285
+ Parameters
4286
+ ----------
4287
+ license_guid: str
4288
+ - identity of the license to remove
4289
+
4290
+ Returns
4291
+ -------
4292
+ None
4293
+
4294
+ Raises
4295
+ ------
4296
+ PyegeriaException
4297
+
4298
+ """
4299
+
4300
+ loop = asyncio.get_event_loop()
4301
+ loop.run_until_complete(
4302
+ self._async_remove_search_keyword(keyword_guid )
4303
+ )
4304
+
4305
+ @dynamic_catch
4306
+ async def _async_get_search_keyword_by_guid(
4307
+ self,
4308
+ keyword_guid: str,
4309
+ output_format: str | None = "JSON",
4310
+ report_spec: dict | str = None
4311
+ ) -> dict | str:
4312
+ """
4313
+ Return information about the specified search keyword.
4314
+
4315
+ Parameters
4316
+ ----------
4317
+ keyword_guid: str
4318
+ - unique identifier of tag.
4319
+ output_format: str, default "JSON"
4320
+ - output format for the response
4321
+ report_spec: str | dict, default None
4322
+ - report specification
4323
+
4324
+ Returns
4325
+ -------
4326
+ Details of the search keyword in the requested format.
4327
+
4328
+ Raises
4329
+ ------
4330
+ PyegeriaException
4331
+
4332
+ """
4333
+
4334
+ url = f"{self.command_root}classification-manager/search-keywords/{keyword_guid}"
4335
+ response = await self._async_get_guid_request(url, "SearchKeyword", self._generate_feedback_output,
4336
+ output_format, report_spec)
4337
+ return response
4338
+
4339
+ @dynamic_catch
4340
+ def get_search_keyword_by_guid(
4341
+ self,
4342
+ keyword_guid: str,
4343
+ output_format: str | None = "JSON",
4344
+ report_spec: dict | str = None
4345
+
4346
+ ) -> dict | str:
4347
+ """
4348
+ Return information about the specified search keyword.
4349
+
4350
+ Parameters
4351
+ ----------
4352
+ keyword_guid: str
4353
+ - unique identifier of tag.
4354
+ output_format: str, default "JSON"
4355
+ - output format for the response
4356
+ report_spec: str | dict, default None
4357
+ - report specification
4358
+
4359
+ Returns
4360
+ -------
4361
+ Details of the search keyword in the requested format.
4362
+
4363
+ Raises
4364
+ ------
4365
+ PyegeriaException
4366
+
4367
+ """
4368
+ loop = asyncio.get_event_loop()
4369
+ response = loop.run_until_complete(
4370
+ self._async_get_search_keyword_by_guid(keyword_guid, output_format, report_spec)
4371
+ )
4372
+ return response
4373
+
4374
+ @dynamic_catch
4375
+ async def _async_get_search_keyword_by_keyword(
4376
+ self,
4377
+ keyword: str,
4378
+ start_from: int = 0,
4379
+ page_size: int = 0,
4380
+ output_format: str | None = "JSON",
4381
+ report_spec: dict | str = None,
4382
+ body: dict | FilterRequestBody = None
4383
+ ) -> dict | str:
4384
+ """
4385
+ Return information about the specified search keyword. Async Version.
4386
+
4387
+ Parameters
4388
+ ----------
4389
+ keyword : str
4390
+ - keyword to search for.
4391
+ start_from: int, default 0
4392
+ - start index of the search keyword
4393
+ page size
4394
+ - output_format: str, default "JSON
4395
+ output_format: str, default "JSON"
4396
+ - output format for the response
4397
+ report_spec: str | dict, default None
4398
+ - report specification
4399
+ body: dict | FilterRequestBody, optional
4400
+ - structure containing detailed request information.
4401
+
4402
+ Returns
4403
+ -------
4404
+ Details of the search keyword in the requested format.
4405
+
4406
+ Raises
4407
+ ------
4408
+ PyegeriaException
4409
+
4410
+ """
4411
+ if body is None and keyword:
4412
+ body = {
4413
+ "class": "FilterRequestBody",
4414
+ "filter": filter,
4415
+ "startFrom": start_from,
4416
+ "pageSize": page_size
4417
+ }
4418
+ url = f"{self.command_root}classification-manager/search-keywords/by-keyword"
4419
+ response = await self._async_get_name_request(url, "SearchKeyword", self._generate_feedback_output,
4420
+ keyword, None, None, start_from,
4421
+ page_size, output_format, report_spec, body)
4422
+ return response
4423
+
4424
+ @dynamic_catch
4425
+ def get_search_keyword_by_keyword(
4426
+ self,
4427
+ keyword: str,
4428
+ start_from: int = 0,
4429
+ page_size: int = 0,
4430
+ output_format: str | None = "JSON",
4431
+ report_spec: dict | str = None,
4432
+ body: dict | FilterRequestBody = None
4433
+ ) -> dict | str:
4434
+ """
4435
+ Return information about the specified search keyword.
4436
+
4437
+ Parameters
4438
+ ----------
4439
+ keyword : str
4440
+ - keyword to search for.
4441
+ start_from: int, default 0
4442
+ - start index of the search keyword
4443
+ page size
4444
+ - output_format: str, default "JSON
4445
+ output_format: str, default "JSON"
4446
+ - output format for the response
4447
+ report_spec: str | dict, default None
4448
+ - report specification
4449
+ body: dict | FilterRequestBody, optional
4450
+ - structure containing detailed request information.
4451
+
4452
+ Returns
4453
+ -------
4454
+ Details of the search keyword in the requested format.
4455
+
4456
+ Raises
4457
+ ------
4458
+ PyegeriaException
4459
+
4460
+ """
4461
+ loop = asyncio.get_event_loop()
4462
+ response = loop.run_until_complete(
4463
+ self._async_find_search_keywords(keyword, start_from, page_size, output_format, report_spec, body)
4464
+ )
4465
+ return response
4466
+
4467
+ async def _async_find_search_keywords(
4468
+ self,
4469
+ search_string: str,
4470
+ start_from: int = 0,
4471
+ page_size: int = 0,
4472
+ output_format: str | None = "JSON",
4473
+ report_spec: dict | str = None,
4474
+ body: dict | SearchStringRequestBody = None
4475
+ ) -> dict | str:
4476
+ """
4477
+ Return the list of search keywords containing the supplied string. The search string is located in the request
4478
+ body and is interpreted as a plain string. The request parameters, startsWith, endsWith and ignoreCase can
4479
+ be used to allow a fuzzy search. The request body also supports the specification of an effective time to
4480
+ restrict the search to element that are/were effective at a particular time. Async Version.
4481
+
4482
+ Parameters
4483
+ ----------
4484
+ search_string : str
4485
+ - keyword to search for.
4486
+ start_from: int, default 0
4487
+ - start index of the search keyword
4488
+ page size
4489
+ - output_format: str, default "JSON
4490
+ output_format: str, default "JSON"
4491
+ - output format for the response
4492
+ report_spec: str | dict, default None
4493
+ - report specification
4494
+ body: dict | SearchStringRequestBody, optional
4495
+ - structure containing detailed request information.
4496
+
4497
+ Returns
4498
+ -------
4499
+ Details of the search keyword in the requested format.
4500
+
4501
+ Raises
4502
+ ------
4503
+ PyegeriaException
4504
+
4505
+ """
4506
+ if body is None and search_string:
4507
+ body = {
4508
+ "class": "SearchStringRequestBody",
4509
+ "filter": filter,
4510
+ "startFrom": start_from,
4511
+ "pageSize": page_size
4512
+ }
4513
+ url = f"{self.command_root}classification-manager/search-keywords/by-search-string"
4514
+ response = await self._async_find_request(url, "SearchKeyword", self._generate_feedback_output, search_string,
4515
+ None, None, True, False, False,
4516
+ start_from, page_size, output_format, report_spec, body
4517
+ )
4518
+ return response
4519
+
4520
+ @dynamic_catch
4521
+ def find_search_keywords(
4522
+ self,
4523
+ search_string: str,
4524
+ start_from: int = 0,
4525
+ page_size: int = 0,
4526
+ output_format: str | None = "JSON",
4527
+ report_spec: dict | str = None,
4528
+ body: dict | SearchStringRequestBody = None
4529
+ ) -> dict | str:
4530
+ """
4531
+ Return the list of search keywords containing the supplied string. The search string is located in the request
4532
+ body and is interpreted as a plain string. The request parameters, startsWith, endsWith and ignoreCase can
4533
+ be used to allow a fuzzy search. The request body also supports the specification of an effective time to
4534
+ restrict the search to element that are/were effective at a particular time. Async Version.
4535
+
4536
+ Parameters
4537
+ ----------
4538
+ search_string : str
4539
+ - keyword to search for.
4540
+ start_from: int, default 0
4541
+ - start index of the search keyword
4542
+ page size
4543
+ - output_format: str, default "JSON
4544
+ output_format: str, default "JSON"
4545
+ - output format for the response
4546
+ report_spec: str | dict, default None
4547
+ - report specification
4548
+ body: dict | SearchStringRequestBody, optional
4549
+ - structure containing detailed request information.
4550
+
4551
+ Returns
4552
+ -------
4553
+ Details of the search keyword in the requested format.
4554
+
4555
+ Raises
4556
+ ------
4557
+ PyegeriaException
4558
+
4559
+ """
4560
+ loop = asyncio.get_event_loop()
4561
+ response = loop.run_until_complete(
4562
+ self._async_find_search_keywords(search_string, start_from, page_size, output_format, report_spec, body)
4563
+ )
4564
+ return response
4565
+
4566
+ @dynamic_catch
3909
4567
  def _extract_comment_properties(self, element: dict, columns_struct: dict) -> dict:
3910
4568
  props = element.get('properties', {}) or {}
3911
4569
  normalized = {
@@ -3920,6 +4578,27 @@ class Client2(BaseClient):
3920
4578
  # col_data = overlay_additional_values(col_data, extra)
3921
4579
  return col_data
3922
4580
 
4581
+ def _extract_element_properties_for_keyword(self, element: dict, columns_struct: dict) -> dict:
4582
+ keyword_elements = None
4583
+ keyword_elements = element["keywordElements"]
4584
+ out_body = {}
4585
+ keyword = element["properties"].get('keyword', '')
4586
+ for el in keyword_elements:
4587
+ element = el.get("relatedElement", {})
4588
+ element_guid = element['elementHeader']['guid']
4589
+ element_type = element['elementHeader']['type']['typeName']
4590
+ element_display_name = element['properties'].get('displayName',"")
4591
+ element_description = element['properties'].get('description',"")
4592
+ element_category = element['properties'].get('category',"")
4593
+ out_body = {
4594
+ "element_display_name": element_display_name,
4595
+ "element_description": element_description,
4596
+ "element_category": element_category,
4597
+ "element_type": element_type,
4598
+ "element_guid": element_guid,
4599
+ "keyword": keyword
4600
+ }
4601
+ return out_body
3923
4602
 
3924
4603
  @dynamic_catch
3925
4604
  def _extract_feedback_properties(self, element: dict, columns_struct: dict) -> dict:
@@ -3932,10 +4611,15 @@ class Client2(BaseClient):
3932
4611
  col_data = populate_common_columns(element, columns_struct)
3933
4612
  columns_list = col_data.get('formats', {}).get('attributes', [])
3934
4613
  # Overlay extras (project roles) only where empty
3935
- # extra = self._extract_additional_project_properties(element, columns_struct)
3936
- # col_data = overlay_additional_values(col_data, extra)
4614
+ keyword_elements = element.get("keywordElements", [])
4615
+
4616
+ if keyword_elements != [] and isinstance(element['keywordElements'], list):
4617
+ extra = self._extract_element_properties_for_keyword(element, columns_struct)
4618
+ col_data = overlay_additional_values(col_data, extra)
4619
+
3937
4620
  return col_data
3938
4621
 
4622
+ @dynamic_catch
3939
4623
  def _generate_feedback_output(self, elements: dict | list[dict], search_string: str,
3940
4624
  element_type_name: str | None,
3941
4625
  output_format: str = 'DICT',
@@ -3962,12 +4646,14 @@ class Client2(BaseClient):
3962
4646
  columns_struct=output_formats,
3963
4647
  )
3964
4648
 
4649
+
3965
4650
  #
3966
4651
  # Helper functions for requests
3967
4652
  #
3968
4653
 
4654
+ @dynamic_catch
3969
4655
  def validate_new_element_request(self, body: dict | NewElementRequestBody,
3970
- prop: list[str]) -> NewElementRequestBody | None:
4656
+ prop: list[str] = None) -> NewElementRequestBody | None:
3971
4657
  if isinstance(body, NewElementRequestBody):
3972
4658
  # if body.properties.class_ in prop:
3973
4659
  validated_body = body
@@ -3985,6 +4671,7 @@ class Client2(BaseClient):
3985
4671
  return None
3986
4672
  return validated_body
3987
4673
 
4674
+ @dynamic_catch
3988
4675
  def validate_new_element_from_template_request(self, body: dict | TemplateRequestBody
3989
4676
  ) -> NewElementRequestBody | None:
3990
4677
  if isinstance(body, TemplateRequestBody):
@@ -3997,37 +4684,37 @@ class Client2(BaseClient):
3997
4684
  return None
3998
4685
  return validated_body
3999
4686
 
4687
+ @dynamic_catch
4000
4688
  def validate_new_relationship_request(self, body: dict | NewRelationshipRequestBody,
4001
4689
  prop: str = None) -> NewRelationshipRequestBody | None:
4002
4690
  if isinstance(body, NewRelationshipRequestBody):
4003
- if (prop and body.properties.class_ == prop) or (prop is None):
4691
+ if (prop and body.properties.class_ in prop) or (prop is None):
4004
4692
  validated_body = body
4005
4693
  else:
4006
4694
  raise PyegeriaInvalidParameterException(additional_info=
4007
4695
  {"reason": "unexpected property class name"})
4008
-
4009
4696
  elif isinstance(body, dict):
4010
- if body.get("properties", {}).get("class", "") == prop:
4697
+ if prop is None or body.get("properties", {}).get("class", "") == prop:
4011
4698
  validated_body = self._new_relationship_request_adapter.validate_python(body)
4012
4699
  else:
4013
4700
  raise PyegeriaInvalidParameterException(additional_info=
4014
4701
  {"reason": "unexpected property class name"})
4015
4702
  else:
4016
4703
  return None
4017
-
4018
4704
  return validated_body
4019
4705
 
4706
+ @dynamic_catch
4020
4707
  def validate_new_classification_request(self, body: dict | NewClassificationRequestBody,
4021
4708
  prop: str = None) -> NewClassificationRequestBody | None:
4022
4709
  if isinstance(body, NewClassificationRequestBody):
4023
- if (prop and body.properties.class_ == prop) or (prop is None):
4710
+ if (prop and body.properties.class_ in prop) or (prop is None):
4024
4711
  validated_body = body
4025
4712
  else:
4026
4713
  raise PyegeriaInvalidParameterException(additional_info=
4027
4714
  {"reason": "unexpected property class name"})
4028
4715
 
4029
4716
  elif isinstance(body, dict):
4030
- if body.get("properties", {}).get("class", "") == prop:
4717
+ if prop is None or body.get("properties", {}).get("class", "") == prop:
4031
4718
  validated_body = self._new_classification_request_adapter.validate_python(body)
4032
4719
  else:
4033
4720
  raise PyegeriaInvalidParameterException(additional_info=
@@ -4037,20 +4724,7 @@ class Client2(BaseClient):
4037
4724
 
4038
4725
  return validated_body
4039
4726
 
4040
- def validate_delete_request(self, body: dict | DeleteRequestBody,
4041
- cascade_delete: bool = False) -> DeleteRequestBody | None:
4042
- if isinstance(body, DeleteRequestBody):
4043
- validated_body = body
4044
- elif isinstance(body, dict):
4045
- validated_body = self._delete_request_adapter.validate_python(body)
4046
- else: # handle case where body not provided
4047
- body = {
4048
- "class": "DeleteRequestBody",
4049
- "cascadeDelete": cascade_delete
4050
- }
4051
- validated_body = DeleteRequestBody.model_validate(body)
4052
- return validated_body
4053
-
4727
+ @dynamic_catch
4054
4728
  def validate_delete_element_request(self, body: dict | DeleteElementRequestBody,
4055
4729
  cascade_delete: bool = False) -> DeleteElementRequestBody | None:
4056
4730
  if isinstance(body, DeleteElementRequestBody):
@@ -4065,6 +4739,7 @@ class Client2(BaseClient):
4065
4739
  validated_body = DeleteElementRequestBody.model_validate(body)
4066
4740
  return validated_body
4067
4741
 
4742
+ @dynamic_catch
4068
4743
  def validate_delete_relationship_request(self, body: dict | DeleteRelationshipRequestBody,
4069
4744
  cascade_delete: bool = False) -> DeleteRelationshipRequestBody | None:
4070
4745
  if isinstance(body, DeleteRelationshipRequestBody):
@@ -4072,13 +4747,15 @@ class Client2(BaseClient):
4072
4747
  elif isinstance(body, dict):
4073
4748
  validated_body = self._delete_relationship_request_adapter.validate_python(body)
4074
4749
  else: # handle case where body not provided
4075
- body = {
4076
- "class": "DeleteRelationshipRequestBody",
4077
- "cascadeDelete": cascade_delete
4078
- }
4079
- validated_body = DeleteRelationshipRequestBody.model_validate(body)
4750
+ # body = {
4751
+ # "class": "DeleteRelationshipRequestBody",
4752
+ # "cascadeDelete": cascade_delete
4753
+ # }
4754
+ # validated_body = DeleteRelationshipRequestBody.model_validate(body)
4755
+ return None
4080
4756
  return validated_body
4081
4757
 
4758
+ @dynamic_catch
4082
4759
  def validate_delete_classification_request(self, body: dict | DeleteClassificationRequestBody,
4083
4760
  cascade_delete: bool = False) -> DeleteClassificationRequestBody | None:
4084
4761
  if isinstance(body, DeleteClassificationRequestBody):
@@ -4093,10 +4770,11 @@ class Client2(BaseClient):
4093
4770
  validated_body = DeleteClassificationRequestBody.model_validate(body)
4094
4771
  return validated_body
4095
4772
 
4773
+ @dynamic_catch
4096
4774
  def validate_update_element_request(self, body: dict | UpdateElementRequestBody,
4097
- prop: list[str]) -> UpdateElementRequestBody | None:
4775
+ prop: list[str] = None) -> UpdateElementRequestBody | None:
4098
4776
  if isinstance(body, UpdateElementRequestBody):
4099
- if body.properties.class_ in prop:
4777
+ if prop is None or body.properties.class_ in prop:
4100
4778
  validated_body = body
4101
4779
  else:
4102
4780
  raise PyegeriaInvalidParameterException(additional_info=
@@ -4112,6 +4790,7 @@ class Client2(BaseClient):
4112
4790
  validated_body = None
4113
4791
  return validated_body
4114
4792
 
4793
+ @dynamic_catch
4115
4794
  def validate_update_status_request(self, status: str = None, body: dict | UpdateStatusRequestBody = None,
4116
4795
  prop: list[str] = None) -> UpdateStatusRequestBody | None:
4117
4796
  if isinstance(body, UpdateStatusRequestBody):
@@ -4131,8 +4810,9 @@ class Client2(BaseClient):
4131
4810
 
4132
4811
  return validated_body
4133
4812
 
4813
+ @dynamic_catch
4134
4814
  def validate_update_relationship_request(self, body: dict | UpdateRelationshipRequestBody,
4135
- prop: [str]) -> UpdateRelationshipRequestBody | None:
4815
+ prop: [str] = None) -> UpdateRelationshipRequestBody | None:
4136
4816
  if isinstance(body, UpdateRelationshipRequestBody):
4137
4817
  # if body.properties.class_ == prop:
4138
4818
  validated_body = body
@@ -4150,6 +4830,7 @@ class Client2(BaseClient):
4150
4830
  validated_body = None
4151
4831
  return validated_body
4152
4832
 
4833
+ @dynamic_catch
4153
4834
  async def _async_find_request(self, url: str, _type: str, _gen_output: Callable[..., Any],
4154
4835
  search_string: str = '*', classification_names: list[str] = None,
4155
4836
  metadata_element_types: list[str] = None,
@@ -4194,6 +4875,7 @@ class Client2(BaseClient):
4194
4875
  output_format, report_spec)
4195
4876
  return elements
4196
4877
 
4878
+ @dynamic_catch
4197
4879
  async def _async_get_name_request(self, url: str, _type: str, _gen_output: Callable[..., Any],
4198
4880
  filter_string: str, classification_names: list[str] = None,
4199
4881
  start_from: int = 0, page_size: int = 0, output_format: str = 'JSON',
@@ -4233,6 +4915,7 @@ class Client2(BaseClient):
4233
4915
  output_format, report_spec)
4234
4916
  return elements
4235
4917
 
4918
+ @dynamic_catch
4236
4919
  async def _async_get_guid_request(self, url: str, _type: str, _gen_output: Callable[..., Any],
4237
4920
  output_format: str = 'JSON', report_spec: str | dict = None,
4238
4921
  body: dict | GetRequestBody = None) -> Any:
@@ -4261,6 +4944,7 @@ class Client2(BaseClient):
4261
4944
  return _gen_output(elements, "GUID", _type, output_format, report_spec)
4262
4945
  return elements
4263
4946
 
4947
+ @dynamic_catch
4264
4948
  async def _async_get_results_body_request(self, url: str, _type: str, _gen_output: Callable[..., Any],
4265
4949
  start_from: int = 0, page_size: int = 0, output_format: str = 'JSON',
4266
4950
  report_spec: str | dict = None,
@@ -4294,6 +4978,7 @@ class Client2(BaseClient):
4294
4978
  output_format, report_spec)
4295
4979
  return elements
4296
4980
 
4981
+ @dynamic_catch
4297
4982
  async def _async_get_level_identifier_query_body_request(self, url: str, _gen_output: Callable[..., Any],
4298
4983
  output_format: str = 'JSON',
4299
4984
  report_spec: str | dict = None,
@@ -4322,7 +5007,8 @@ class Client2(BaseClient):
4322
5007
  output_format, report_spec)
4323
5008
  return elements
4324
5009
 
4325
- async def _async_create_element_body_request(self, url: str, prop: list[str],
5010
+ @dynamic_catch
5011
+ async def _async_create_element_body_request(self, url: str, prop: list[str] = None,
4326
5012
  body: dict | NewElementRequestBody = None) -> str:
4327
5013
  validated_body = self.validate_new_element_request(body, prop)
4328
5014
  json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
@@ -4331,6 +5017,7 @@ class Client2(BaseClient):
4331
5017
  logger.info(response.json())
4332
5018
  return response.json().get("guid", "NO_GUID_RETURNED")
4333
5019
 
5020
+ @dynamic_catch
4334
5021
  async def _async_create_element_from_template(self, url: str, body: dict | TemplateRequestBody = None) -> str:
4335
5022
  validated_body = self.validate_new_element_from_template_request(body)
4336
5023
  json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
@@ -4339,7 +5026,8 @@ class Client2(BaseClient):
4339
5026
  logger.info(response.json())
4340
5027
  return response.json().get("guid", "NO_GUID_RETURNED")
4341
5028
 
4342
- async def _async_update_element_body_request(self, url: str, prop: list[str],
5029
+ @dynamic_catch
5030
+ async def _async_update_element_body_request(self, url: str, prop: list[str] = None,
4343
5031
  body: dict | UpdateElementRequestBody = None) -> None:
4344
5032
  validated_body = self.validate_update_element_request(body, prop)
4345
5033
  json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
@@ -4347,6 +5035,7 @@ class Client2(BaseClient):
4347
5035
  response = await self._async_make_request("POST", url, json_body)
4348
5036
  logger.info(response.json())
4349
5037
 
5038
+ @dynamic_catch
4350
5039
  async def _async_update_status_request(self, url: str, status: str = None,
4351
5040
  body: dict | UpdateStatusRequestBody = None) -> None:
4352
5041
  validated_body = self.validate_update_status_request(status, body)
@@ -4355,7 +5044,8 @@ class Client2(BaseClient):
4355
5044
  response = await self._async_make_request("POST", url, json_body)
4356
5045
  logger.info(response.json())
4357
5046
 
4358
- async def _async_new_relationship_request(self, url: str, prop: list[str],
5047
+ @dynamic_catch
5048
+ async def _async_new_relationship_request(self, url: str, prop: list[str] = None,
4359
5049
  body: dict | NewRelationshipRequestBody = None) -> None:
4360
5050
  validated_body = self.validate_new_relationship_request(body, prop)
4361
5051
  if validated_body:
@@ -4365,8 +5055,9 @@ class Client2(BaseClient):
4365
5055
  else:
4366
5056
  await self._async_make_request("POST", url)
4367
5057
 
4368
- async def _async_new_classification_request(self, url: str, prop: str,
4369
- body: dict | NewRelationshipRequestBody = None) -> None:
5058
+ @dynamic_catch
5059
+ async def _async_new_classification_request(self, url: str, prop: list[str] = None,
5060
+ body: dict | NewClassificationRequestBody = None) -> None:
4370
5061
  validated_body = self.validate_new_classification_request(body, prop)
4371
5062
  if validated_body:
4372
5063
  json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
@@ -4375,16 +5066,7 @@ class Client2(BaseClient):
4375
5066
  else:
4376
5067
  await self._async_make_request("POST", url)
4377
5068
 
4378
- async def _async_delete_request(self, url: str, body: dict | DeleteRequestBody = None,
4379
- cascade_delete: bool = False) -> None:
4380
- validated_body = self.validate_delete_request(body, cascade_delete)
4381
- if validated_body:
4382
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
4383
- logger.info(json_body)
4384
- await self._async_make_request("POST", url, json_body)
4385
- else:
4386
- await self._async_make_request("POST", url)
4387
-
5069
+ @dynamic_catch
4388
5070
  async def _async_delete_element_request(self, url: str, body: dict | DeleteElementRequestBody = None,
4389
5071
  cascade_delete: bool = False) -> None:
4390
5072
  validated_body = self.validate_delete_element_request(body, cascade_delete)
@@ -4395,9 +5077,10 @@ class Client2(BaseClient):
4395
5077
  else:
4396
5078
  await self._async_make_request("POST", url)
4397
5079
 
5080
+ @dynamic_catch
4398
5081
  async def _async_delete_relationship_request(self, url: str, body: dict | DeleteRelationshipRequestBody = None,
4399
5082
  cascade_delete: bool = False) -> None:
4400
- validated_body = self.validate_delete_relationshp_request(body, cascade_delete)
5083
+ validated_body = self.validate_delete_relationship_request(body, cascade_delete)
4401
5084
  if validated_body:
4402
5085
  json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
4403
5086
  logger.info(json_body)
@@ -4405,6 +5088,7 @@ class Client2(BaseClient):
4405
5088
  else:
4406
5089
  await self._async_make_request("POST", url)
4407
5090
 
5091
+ @dynamic_catch
4408
5092
  async def _async_delete_classification_request(self, url: str, body: dict | DeleteClassificationRequestBody = None,
4409
5093
  cascade_delete: bool = False) -> None:
4410
5094
  validated_body = self.validate_delete_classification_request(body, cascade_delete)
@@ -4415,7 +5099,8 @@ class Client2(BaseClient):
4415
5099
  else:
4416
5100
  await self._async_make_request("POST", url)
4417
5101
 
4418
- async def _async_update_relationship_request(self, url: str, prop: str,
5102
+ @dynamic_catch
5103
+ async def _async_update_relationship_request(self, url: str, prop: list[str] = None,
4419
5104
  body: dict | UpdateRelationshipRequestBody = None) -> None:
4420
5105
  validated_body = self.validate_update_relationship_request(body, prop)
4421
5106
  if validated_body: