pyegeria 5.3.10__py3-none-any.whl → 5.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. commands/cat/debug_log +2806 -0
  2. commands/cat/debug_log.2025-07-15_14-28-38_087378.zip +0 -0
  3. commands/cat/debug_log.2025-07-16_15-48-50_037087.zip +0 -0
  4. commands/cat/dr_egeria_command_help.py +273 -0
  5. commands/cat/dr_egeria_md.py +90 -20
  6. commands/cat/glossary_actions.py +2 -2
  7. commands/cat/list_collections.py +24 -10
  8. commands/cat/list_data_designer.py +183 -0
  9. md_processing/__init__.py +28 -5
  10. md_processing/data/commands.json +31474 -1096
  11. md_processing/dr_egeria_outbox-pycharm/.obsidian/app.json +1 -0
  12. md_processing/dr_egeria_outbox-pycharm/.obsidian/appearance.json +1 -0
  13. md_processing/dr_egeria_outbox-pycharm/.obsidian/core-plugins.json +31 -0
  14. md_processing/dr_egeria_outbox-pycharm/.obsidian/workspace.json +177 -0
  15. md_processing/dr_egeria_outbox-pycharm/monday/processed-2025-07-14 12:38-data_designer_out.md +663 -0
  16. md_processing/dr_egeria_outbox-pycharm/thursday/processed-2025-07-17 15:00-Derive-Dr-Gov-Defs.md +719 -0
  17. md_processing/dr_egeria_outbox-pycharm/thursday/processed-2025-07-17 20:13-Derive-Dr-Gov-Defs.md +41 -0
  18. md_processing/dr_egeria_outbox-pycharm/thursday/processed-2025-07-17 20:14-Derive-Dr-Gov-Defs.md +33 -0
  19. md_processing/dr_egeria_outbox-pycharm/thursday/processed-2025-07-17 20:50-Derive-Dr-Gov-Defs.md +192 -0
  20. md_processing/dr_egeria_outbox-pycharm/tuesday/processed-2025-07-16 19:15-gov_def2.md +527 -0
  21. md_processing/dr_egeria_outbox-pycharm/tuesday/processed-2025-07-17 12:08-gov_def2.md +527 -0
  22. md_processing/dr_egeria_outbox-pycharm/tuesday/processed-2025-07-17 14:27-gov_def2.md +474 -0
  23. md_processing/family_docs/Data Designer/Create_Data_Class.md +164 -0
  24. md_processing/family_docs/Data Designer/Create_Data_Dictionary.md +30 -0
  25. md_processing/family_docs/Data Designer/Create_Data_Field.md +162 -0
  26. md_processing/family_docs/Data Designer/Create_Data_Specification.md +36 -0
  27. md_processing/family_docs/Data Designer/Create_Data_Structure.md +38 -0
  28. md_processing/family_docs/Data Designer/View_Data_Classes.md +78 -0
  29. md_processing/family_docs/Data Designer/View_Data_Dictionaries.md +78 -0
  30. md_processing/family_docs/Data Designer/View_Data_Fields.md +78 -0
  31. md_processing/family_docs/Data Designer/View_Data_Specifications.md +78 -0
  32. md_processing/family_docs/Data Designer/View_Data_Structures.md +78 -0
  33. md_processing/family_docs/Data Designer.md +842 -0
  34. md_processing/family_docs/Digital Product Manager/Add_Member->Collection.md +42 -0
  35. md_processing/family_docs/Digital Product Manager/Attach_Collection->Resource.md +36 -0
  36. md_processing/family_docs/Digital Product Manager/Create_Agreement.md +96 -0
  37. md_processing/family_docs/Digital Product Manager/Create_Data_Sharing_Agreement.md +72 -0
  38. md_processing/family_docs/Digital Product Manager/Create_DigitalSubscription.md +102 -0
  39. md_processing/family_docs/Digital Product Manager/Create_Digital_Product.md +134 -0
  40. md_processing/family_docs/Digital Product Manager/Link_Agreement_Items.md +60 -0
  41. md_processing/family_docs/Digital Product Manager/Link_Contracts.md +26 -0
  42. md_processing/family_docs/Digital Product Manager/Link_Digital_Product_-_Digital_Product.md +30 -0
  43. md_processing/family_docs/Digital Product Manager/Link_Subscribers.md +48 -0
  44. md_processing/family_docs/Digital Product Manager.md +668 -0
  45. md_processing/family_docs/Glossary/Attach_Category_Parent.md +18 -0
  46. md_processing/family_docs/Glossary/Attach_Term-Term_Relationship.md +26 -0
  47. md_processing/family_docs/Glossary/Create_Category.md +38 -0
  48. md_processing/family_docs/Glossary/Create_Glossary.md +42 -0
  49. md_processing/family_docs/Glossary/Create_Term.md +70 -0
  50. md_processing/family_docs/Glossary.md +206 -0
  51. md_processing/family_docs/Governance Officer/Create_Business_Imperative.md +106 -0
  52. md_processing/family_docs/Governance Officer/Create_Certification_Type.md +112 -0
  53. md_processing/family_docs/Governance Officer/Create_Governance_Approach.md +114 -0
  54. md_processing/family_docs/Governance Officer/Create_Governance_Obligation.md +114 -0
  55. md_processing/family_docs/Governance Officer/Create_Governance_Principle.md +114 -0
  56. md_processing/family_docs/Governance Officer/Create_Governance_Procedure.md +128 -0
  57. md_processing/family_docs/Governance Officer/Create_Governance_Process.md +122 -0
  58. md_processing/family_docs/Governance Officer/Create_Governance_Processing_Purpose.md +106 -0
  59. md_processing/family_docs/Governance Officer/Create_Governance_Responsibility.md +122 -0
  60. md_processing/family_docs/Governance Officer/Create_Governance_Rule.md +122 -0
  61. md_processing/family_docs/Governance Officer/Create_Governance_Strategy.md +106 -0
  62. md_processing/family_docs/Governance Officer/Create_License_Type.md +112 -0
  63. md_processing/family_docs/Governance Officer/Create_Naming_Standard_Rule.md +122 -0
  64. md_processing/family_docs/Governance Officer/Create_Regulation_Article.md +106 -0
  65. md_processing/family_docs/Governance Officer/Create_Regulation_Definition.md +118 -0
  66. md_processing/family_docs/Governance Officer/Create_Security_Access_Control.md +114 -0
  67. md_processing/family_docs/Governance Officer/Create_Security_Group.md +120 -0
  68. md_processing/family_docs/Governance Officer/Create_Service_Level_Objectives.md +122 -0
  69. md_processing/family_docs/Governance Officer/Create_Threat_Definition.md +106 -0
  70. md_processing/family_docs/Governance Officer/Link_Governance_Controls.md +32 -0
  71. md_processing/family_docs/Governance Officer/Link_Governance_Drivers.md +32 -0
  72. md_processing/family_docs/Governance Officer/Link_Governance_Policies.md +32 -0
  73. md_processing/family_docs/Governance Officer/View_Governance_Definitions.md +82 -0
  74. md_processing/family_docs/Governance Officer.md +2412 -0
  75. md_processing/family_docs/Solution Architect/Create_Information_Supply_Chain.md +70 -0
  76. md_processing/family_docs/Solution Architect/Create_Solution_Blueprint.md +44 -0
  77. md_processing/family_docs/Solution Architect/Create_Solution_Component.md +96 -0
  78. md_processing/family_docs/Solution Architect/Create_Solution_Role.md +66 -0
  79. md_processing/family_docs/Solution Architect/Link_Information_Supply_Chain_Peers.md +32 -0
  80. md_processing/family_docs/Solution Architect/Link_Solution_Component_Peers.md +32 -0
  81. md_processing/family_docs/Solution Architect/View_Information_Supply_Chains.md +32 -0
  82. md_processing/family_docs/Solution Architect/View_Solution_Blueprints.md +32 -0
  83. md_processing/family_docs/Solution Architect/View_Solution_Components.md +32 -0
  84. md_processing/family_docs/Solution Architect/View_Solution_Roles.md +32 -0
  85. md_processing/family_docs/Solution Architect.md +490 -0
  86. md_processing/md_commands/data_designer_commands.py +1192 -710
  87. md_processing/md_commands/glossary_commands.py +19 -32
  88. md_processing/md_commands/governance_officer_commands.py +420 -0
  89. md_processing/md_commands/product_manager_commands.py +1180 -0
  90. md_processing/md_commands/project_commands.py +5 -2
  91. md_processing/md_commands/solution_architect_commands.py +1140 -0
  92. md_processing/md_processing_utils/common_md_proc_utils.py +288 -96
  93. md_processing/md_processing_utils/common_md_utils.py +205 -6
  94. md_processing/md_processing_utils/debug_log +574 -0
  95. md_processing/md_processing_utils/dr-egeria-help-2025-07-17T17:22:09.md +2065 -0
  96. md_processing/md_processing_utils/extraction_utils.py +1 -1
  97. md_processing/md_processing_utils/generate_dr_help.py +165 -0
  98. md_processing/md_processing_utils/generate_md_cmd_templates.py +143 -0
  99. md_processing/md_processing_utils/generate_md_templates.py +92 -0
  100. md_processing/md_processing_utils/generated_help_terms.md +842 -0
  101. md_processing/md_processing_utils/md_processing_constants.py +94 -17
  102. pyegeria/__init__.py +1 -0
  103. pyegeria/_client.py +39 -1
  104. pyegeria/classification_manager_omvs.py +1 -1
  105. pyegeria/collection_manager_omvs.py +4667 -1178
  106. pyegeria/data_designer_omvs.py +348 -31
  107. pyegeria/egeria_tech_client.py +9 -25
  108. pyegeria/glossary_browser_omvs.py +5 -6
  109. pyegeria/glossary_manager_omvs.py +2 -2
  110. pyegeria/governance_officer_omvs.py +2367 -0
  111. pyegeria/output_formatter.py +157 -32
  112. pyegeria/solution_architect_omvs.py +5063 -1110
  113. pyegeria/utils.py +22 -2
  114. {pyegeria-5.3.10.dist-info → pyegeria-5.4.0.dist-info}/METADATA +3 -1
  115. pyegeria-5.4.0.dist-info/RECORD +243 -0
  116. {pyegeria-5.3.10.dist-info → pyegeria-5.4.0.dist-info}/entry_points.txt +5 -0
  117. commands/cat/.DS_Store +0 -0
  118. md_processing/dr_egeria_inbox/archive/dr_egeria_intro.md +0 -254
  119. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_more_terms.md +0 -696
  120. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part1.md +0 -254
  121. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part2.md +0 -298
  122. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part3.md +0 -608
  123. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part4.md +0 -94
  124. md_processing/dr_egeria_inbox/archive/freddie_intro.md +0 -284
  125. md_processing/dr_egeria_inbox/archive/freddie_intro_orig.md +0 -275
  126. md_processing/dr_egeria_inbox/archive/test-term.md +0 -110
  127. md_processing/dr_egeria_inbox/cat_test.md +0 -100
  128. md_processing/dr_egeria_inbox/data_field.md +0 -54
  129. md_processing/dr_egeria_inbox/data_spec.md +0 -77
  130. md_processing/dr_egeria_inbox/data_spec_test.md +0 -2406
  131. md_processing/dr_egeria_inbox/data_test.md +0 -86
  132. md_processing/dr_egeria_inbox/dr_egeria_intro_categories.md +0 -168
  133. md_processing/dr_egeria_inbox/dr_egeria_intro_part1.md +0 -280
  134. md_processing/dr_egeria_inbox/dr_egeria_intro_part2.md +0 -313
  135. md_processing/dr_egeria_inbox/dr_egeria_intro_part3.md +0 -1073
  136. md_processing/dr_egeria_inbox/dr_egeria_isc1.md +0 -44
  137. md_processing/dr_egeria_inbox/glossary_test1.md +0 -324
  138. md_processing/dr_egeria_inbox/rel.md +0 -8
  139. md_processing/dr_egeria_inbox/sb.md +0 -119
  140. md_processing/dr_egeria_inbox/search_test.md +0 -39
  141. md_processing/dr_egeria_inbox/solution-components.md +0 -154
  142. md_processing/dr_egeria_inbox/solution_blueprints.md +0 -118
  143. md_processing/dr_egeria_inbox/synonym_test.md +0 -42
  144. md_processing/dr_egeria_inbox/t1.md +0 -0
  145. md_processing/dr_egeria_inbox/t2.md +0 -268
  146. md_processing/dr_egeria_outbox/processed-2025-05-15 19:52-data_test.md +0 -94
  147. md_processing/dr_egeria_outbox/processed-2025-05-16 07:39-data_test.md +0 -88
  148. md_processing/dr_egeria_outbox/processed-2025-05-17 16:01-data_field.md +0 -56
  149. md_processing/dr_egeria_outbox/processed-2025-05-18 15:51-data_test.md +0 -103
  150. md_processing/dr_egeria_outbox/processed-2025-05-18 16:47-data_test.md +0 -94
  151. md_processing/dr_egeria_outbox/processed-2025-05-19 07:14-data_test.md +0 -96
  152. md_processing/dr_egeria_outbox/processed-2025-05-19 07:20-data_test.md +0 -100
  153. md_processing/dr_egeria_outbox/processed-2025-05-19 07:22-data_test.md +0 -88
  154. md_processing/dr_egeria_outbox/processed-2025-05-19 09:26-data_test.md +0 -91
  155. md_processing/dr_egeria_outbox/processed-2025-05-19 10:27-data_test.md +0 -91
  156. md_processing/dr_egeria_outbox/processed-2025-05-19 14:04-data_test.md +0 -91
  157. md_processing/md_commands/blueprint_commands.py +0 -303
  158. pyegeria/.DS_Store +0 -0
  159. pyegeria/m_test.py +0 -118
  160. pyegeria-5.3.10.dist-info/RECORD +0 -196
  161. /commands/cat/{list_data_structures.py → list_data_structures_full.py} +0 -0
  162. {pyegeria-5.3.10.dist-info → pyegeria-5.4.0.dist-info}/LICENSE +0 -0
  163. {pyegeria-5.3.10.dist-info → pyegeria-5.4.0.dist-info}/WHEEL +0 -0
@@ -3,100 +3,409 @@ This file contains term-related object_action functions for processing Egeria Ma
3
3
  """
4
4
  import json
5
5
  import os
6
+ import sys
6
7
  from typing import Optional
7
8
 
9
+ from loguru import logger
8
10
  from rich import print
9
11
  from rich.console import Console
10
12
  from rich.markdown import Markdown
11
13
 
12
- from md_processing.md_processing_utils.common_md_proc_utils import (parse_user_command, sync_data_dict_membership,
13
- sync_data_spec_membership, sync_data_structure_membership, sync_term_links, sync_parent_data_field)
14
-
15
- from md_processing.md_processing_utils.common_md_utils import print_msg, update_element_dictionary
16
- from md_processing.md_processing_utils.extraction_utils import (extract_command, extract_command_plus, update_a_command)
14
+ from md_processing.md_processing_utils.common_md_proc_utils import (parse_upsert_command, parse_view_command)
15
+ from md_processing.md_processing_utils.common_md_utils import update_element_dictionary, setup_log
16
+ from md_processing.md_processing_utils.extraction_utils import (extract_command_plus, update_a_command)
17
17
  from md_processing.md_processing_utils.md_processing_constants import (load_commands, ERROR)
18
18
  from pyegeria import DEBUG_LEVEL, body_slimmer
19
19
  from pyegeria.egeria_tech_client import EgeriaTech
20
- from pyegeria.md_processing_utils import ALWAYS, INFO
21
20
 
21
+ GERIA_METADATA_STORE = os.environ.get("EGERIA_METADATA_STORE", "active-metadata-store")
22
+ EGERIA_KAFKA_ENDPOINT = os.environ.get("KAFKA_ENDPOINT", "localhost:9092")
23
+ EGERIA_PLATFORM_URL = os.environ.get("EGERIA_PLATFORM_URL", "https://localhost:9443")
24
+ EGERIA_VIEW_SERVER = os.environ.get("EGERIA_VIEW_SERVER", "view-server")
25
+ EGERIA_VIEW_SERVER_URL = os.environ.get("EGERIA_VIEW_SERVER_URL", "https://localhost:9443")
26
+ EGERIA_INTEGRATION_DAEMON = os.environ.get("EGERIA_INTEGRATION_DAEMON", "integration-daemon")
27
+ EGERIA_INTEGRATION_DAEMON_URL = os.environ.get("EGERIA_INTEGRATION_DAEMON_URL", "https://localhost:9443")
28
+ EGERIA_ADMIN_USER = os.environ.get("ADMIN_USER", "garygeeke")
29
+ EGERIA_ADMIN_PASSWORD = os.environ.get("ADMIN_PASSWORD", "secret")
30
+ EGERIA_USER = os.environ.get("EGERIA_USER", "erinoverview")
31
+ EGERIA_USER_PASSWORD = os.environ.get("EGERIA_USER_PASSWORD", "secret")
32
+ EGERIA_WIDTH = os.environ.get("EGERIA_WIDTH", 220)
33
+ EGERIA_JUPYTER = os.environ.get("EGERIA_JUPYTER", False)
34
+ EGERIA_HOME_GLOSSARY_GUID = os.environ.get("EGERIA_HOME_GLOSSARY_GUID", None)
35
+ EGERIA_GLOSSARY_PATH = os.environ.get("EGERIA_GLOSSARY_PATH", None)
36
+ EGERIA_ROOT_PATH = os.environ.get("EGERIA_ROOT_PATH", "../../")
37
+ EGERIA_INBOX_PATH = os.environ.get("EGERIA_INBOX_PATH", "md_processing/dr_egeria_inbox")
38
+ EGERIA_OUTBOX_PATH = os.environ.get("EGERIA_OUTBOX_PATH", "md_processing/dr_egeria_outbox")
22
39
 
23
40
  load_commands('commands.json')
24
41
  debug_level = DEBUG_LEVEL
25
42
 
26
43
  console = Console(width=int(200))
44
+ setup_log()
45
+
27
46
 
28
- def add_member_to_data_collections(egeria_client: EgeriaTech, in_data_collection:dict, display_name: str, guid:str )-> bool:
47
+ #
48
+ # Helper functions for the data designer commands
49
+ #
50
+ @logger.catch
51
+ def add_member_to_data_collections(egeria_client: EgeriaTech, collection_list: list, display_name: str,
52
+ guid: str) -> None:
29
53
  """
30
54
  Add member to data dictionaries and data specifications.
31
55
  """
56
+ body = {
57
+ "class": "RelationshipRequestBody", "properties": {
58
+ "class": "CollectionMembershipProperties", "membershipRationale": "User Specified",
59
+ "notes": "Added by Dr.Egeria"
60
+ }
61
+ }
62
+ try:
63
+ if collection_list is not None:
64
+ for collection in collection_list:
65
+ egeria_client.add_to_collection(collection, guid, body)
66
+ msg = f"Added `{display_name}` member to `{collection}`"
67
+ logger.info(msg)
68
+ else:
69
+ logger.info("There were no data collections to add.")
70
+ return
71
+
72
+ except Exception as e:
73
+ console.print_exception()
74
+
75
+
76
+ @logger.catch
77
+ def remove_member_from_data_collections(egeria_client: EgeriaTech, collection_list: list, display_name: str,
78
+ guid: str) -> None:
32
79
  try:
33
- for collection in in_data_collection.keys():
34
- collection_name = collection
35
- collection_valid = in_data_collection[collection].get('el_valid', False)
36
- collection_guid = in_data_collection[collection].get('guid', None)
37
- if collection_guid and collection_valid:
38
- egeria_client.add_to_collection(collection_guid, guid)
39
- msg = f"Added `{display_name}` member to `{collection_name}`"
40
- print_msg(INFO, msg, debug_level)
41
- return True
80
+ for collection in collection_list:
81
+ egeria_client.remove_from_collection(collection, guid)
82
+ msg = f"Removed `{display_name}` member from `{collection}`"
83
+ logger.info(msg)
84
+ return
42
85
 
43
86
  except Exception as e:
44
87
  console.print_exception()
45
88
 
46
89
 
47
- def find_memberships_in_collection_type(egeria_client: EgeriaTech, collection_type: str, guid: str) -> list:
48
- """ Find the collections of a particular type that the element is a member of"""
49
- collection_guid_list = []
50
- collections = egeria_client.get_related_elements(guid, "CollectionMembership", "Collection")
51
- for collection in collections:
52
- print(collection["relationshipHeader"]['guid'])
53
- related_el_guid = collection["relatedElement"]['elementHeader']["guid"]
54
- coll_type = collection["relatedElement"]['properties'].get('collectionType', None)
55
- print(coll_type)
56
- if coll_type:
57
- if coll_type == collection_type:
58
- collection_guid_list.append(related_el_guid)
59
- print(collection_guid_list)
60
- return collection_guid_list
90
+ @logger.catch
91
+ def update_data_collection_memberships(egeria_client: EgeriaTech, entity_type: str, guid_list: list,
92
+ collection_class: str, guid: str, display_name: str,
93
+ replace_all_props: bool = True) -> None:
94
+ """ update the collection membership of the element
95
+
96
+ If replace_all_props is set to True, all existing memberships are removed and new memberships are added.
97
+ If replace_all_props is set to False, only the new memberships are added.
98
+ """
61
99
 
100
+ if replace_all_props:
101
+ match entity_type:
102
+ case "Data Specification":
103
+ get_command = egeria_client.get_collection_by_guid
104
+ case "Data Structure":
105
+ get_command = egeria_client.get_data_structure_by_guid
106
+ case "Data Field":
107
+ get_command = egeria_client.get_data_field_by_guid
108
+ case "Data Class":
109
+ get_command = egeria_client.get_data_class_by_guid
110
+
111
+ coll_list = egeria_client.get_data_memberships(get_command, guid)
112
+ if coll_list is None:
113
+ logger.warning("Unexpected -> the collection list was None - assigning empty dict")
114
+ coll_list = {}
115
+ # compare the existing collections to desired collections
116
+ if collection_class == "DataDictionary":
117
+ as_is = set(coll_list.get("DictList", {}))
118
+ elif collection_class == "DataSpec":
119
+ as_is = set(coll_list.get("SpecList", {}))
120
+
121
+ dict_set = set(coll_list.get("DictList", {}))
122
+ spec_set = set(coll_list.get("SpecList", {}))
123
+ to_be_set = set(guid_list) if guid_list is not None else set()
124
+ logger.debug(f"as_is: {as_is}")
125
+ logger.debug(f"to_be_set: {to_be_set}")
126
+
127
+ # Remove membership for collections that are in the as-is but not in the to-be
128
+ to_remove = as_is - to_be_set
129
+ logger.debug(f"to_remove: {to_remove}")
130
+ if len(to_remove) > 0:
131
+ remove_member_from_data_collections(egeria_client, to_remove, display_name, guid)
132
+
133
+ # add membership for collections that are in the to-be but are not in the as-is
134
+ to_add = to_be_set - as_is
135
+ logger.debug(f"to_add: {to_add}")
136
+ if len(to_add) > 0:
137
+ add_member_to_data_collections(egeria_client, to_add, display_name, guid)
138
+ else:
139
+ add_member_to_data_collections(egeria_client, guid_list, display_name, guid)
62
140
 
63
141
 
142
+ # @logger.catch
64
143
 
65
- def update_data_collection_memberships(egeria_client: EgeriaTech, in_data_collection:dict, guid: str, replace_all_props:bool = False) -> bool:
66
- """ update the collection membership of the element """
67
- pass
68
144
 
145
+ @logger.catch
146
+ def add_field_to_data_structures(egeria_client: EgeriaTech, display_name: str, struct_list: list, guid) -> None:
147
+ """
148
+ Add data field to data structures.
149
+ """
69
150
 
70
- # def update_term_categories(egeria_client: EgeriaTech, term_guid: str, current_categories: List[str],
71
- # new_categories: List[str]) -> None:
72
- # """
73
- # Updates the categories of a term.
74
- #
75
- # Args:
76
- # egeria_client: The Egeria client to use for the update.
77
- # term_guid: The GUID of the term to update.
78
- # current_categories: The current categories of the term.
79
- # new_categories: The new categories of the term.
80
- # """
81
- # if new_categories: # If categories are specified, add them
82
- # for cat in new_categories:
83
- # if cat not in current_categories:
84
- # egeria_client.add_term_to_category(term_guid, cat)
85
- # msg = f"Added term {term_guid} to category {cat}"
86
- # print_msg("DEBUG-INFO", msg, debug_level)
87
- # # Remove any categories that are not in the new list
88
- # for cat in current_categories:
89
- # if cat not in new_categories:
90
- # egeria_client.remove_term_from_category(term_guid, cat)
91
- # msg = f"Removed term {term_guid} from category {cat}"
92
- # print_msg("DEBUG-INFO", msg, debug_level)
93
- # else: # No categories specified - so remove any categories a term is in
94
- # for cat in current_categories:
95
- # egeria_client.remove_term_from_category(term_guid, cat)
96
- # msg = f"Removed term {term_guid} from category {cat}"
97
- # print_msg("DEBUG-INFO", msg, debug_level)
151
+ try:
152
+ for structure_guid in struct_list:
153
+ egeria_client.link_member_data_field(structure_guid, guid, None)
154
+ msg = f"Added `{display_name}` to structure `{structure_guid}`"
155
+ logger.info(msg)
156
+ return
157
+
158
+ except Exception as e:
159
+ console.print_exception()
160
+
161
+
162
+ @logger.catch
163
+ def remove_field_from_data_structures(egeria_client: EgeriaTech, display_name: str, struct_list: list,
164
+ guid: str) -> None:
165
+ """Remove a data field from a list of data structures."""
166
+ try:
167
+ for structure_guid in struct_list:
168
+ egeria_client.detach_member_data_field(structure_guid, guid, None)
169
+ msg = f"Removed `{display_name}` from structure `{structure_guid}`"
170
+ logger.info(msg)
171
+ return
172
+
173
+ except Exception as e:
174
+ console.print_exception()
175
+
176
+
177
+ @logger.catch
178
+ def sync_data_field_rel_elements(egeria_client: EgeriaTech, structure_list: list, parent_field_list: list, terms: list,
179
+ data_class_guid: str, guid: str, display_name: str,
180
+ replace_all_props: bool = True) -> None:
181
+ """Sync a field's related elements.
98
182
 
183
+ TODO: Need to add data class support when ready and may need to revisit bodies.
184
+
185
+ """
186
+ if terms:
187
+ terms = [terms]
188
+
189
+ if replace_all_props:
190
+ rel_el_list = egeria_client.get_data_field_rel_elements(guid)
191
+ # should I throw an exception if empty?
192
+ if rel_el_list is None:
193
+ logger.warning("Unexpected -> the list was None - assigning empty list")
194
+ rel_el_list = {}
195
+
196
+ as_is_data_structs = set(rel_el_list.get("data_structure_guids", []))
197
+ as_is_parent_fields = set(rel_el_list.get("parent_guids", []))
198
+ as_is_assigned_meanings = set(rel_el_list.get("assigned_meanings_guids", []))
199
+ as_is_data_classes = set(rel_el_list.get("data_class_guids", []))
200
+
201
+ to_be_data_structs = set(structure_list) if structure_list is not None else set()
202
+ to_be_parent_fields = set(parent_field_list) if parent_field_list is not None else set()
203
+ to_be_assigned_meanings = set(terms) if terms is not None else set()
204
+ to_be_data_classes = set([data_class_guid]) if data_class_guid is not None else set()
205
+
206
+ logger.trace(f"as_is_data_structs: {list(as_is_data_structs)} to_be_data_struct: {list(to_be_data_structs)}")
207
+ logger.trace(
208
+ f"as_is_parent_fields: {list(as_is_parent_fields)} to_be_parent_fields: {list(to_be_parent_fields)}")
209
+ logger.trace(f"as_is_assigned_meanings: {list(as_is_assigned_meanings)} to_be_assigned_meanings: "
210
+ f"{list(to_be_assigned_meanings)}")
211
+ logger.trace(f"as_is_data_classes: {list(as_is_data_classes)} to_be_assigned_data_classes: "
212
+ f"{list(to_be_data_classes)}")
213
+
214
+ data_struct_to_remove = as_is_data_structs - to_be_data_structs
215
+ logger.trace(f"data_struct_to_remove: {list(data_struct_to_remove)}")
216
+ if len(data_struct_to_remove) > 0:
217
+ for ds in data_struct_to_remove:
218
+ egeria_client.detach_member_data_field(ds, guid, None)
219
+ msg = f"Removed `{display_name}` from structure `{ds}`"
220
+ logger.trace(msg)
221
+ data_struct_to_add = to_be_data_structs - as_is_data_structs
222
+ logger.trace(f"data_struct_to_add: {list(data_struct_to_add)}")
223
+ if len(data_struct_to_add) > 0:
224
+ for ds in data_struct_to_add:
225
+ egeria_client.link_member_data_field(ds, guid, None)
226
+ msg = f"Added `{display_name}` to structure `{ds}`"
227
+ logger.trace(msg)
228
+
229
+ parent_field_to_remove = to_be_parent_fields - as_is_parent_fields
230
+ logger.trace(f"parent_field_to_remove: {list(parent_field_to_remove)}")
231
+ if len(parent_field_to_remove) > 0:
232
+ for field in parent_field_to_remove:
233
+ egeria_client.detach_nested_data_field(field, guid, None)
234
+ msg = f"Removed `{display_name}` from field `{field}`"
235
+ logger.trace(msg)
236
+ parent_field_to_add = to_be_parent_fields - as_is_parent_fields
237
+ logger.trace(f"parent_field_to_add: {list(parent_field_to_add)}")
238
+ if len(parent_field_to_add) > 0:
239
+ for field in parent_field_to_add:
240
+ egeria_client.link_nested_data_field(field, guid, None)
241
+ msg = f"Added `{display_name}` to field `{field}`"
242
+ logger.trace(msg)
243
+
244
+ terms_to_remove = as_is_assigned_meanings - to_be_assigned_meanings
245
+ logger.trace(f"terms_to_remove: {list(terms_to_remove)}")
246
+ if terms:
247
+ for term in terms_to_remove:
248
+ egeria_client.detach_semantic_definition(guid, term, None)
249
+ msg = f"Removed `{term}` from `{display_name}`"
250
+ logger.trace(msg)
251
+ terms_to_add = to_be_assigned_meanings - as_is_assigned_meanings
252
+ logger.trace(f"terms_to_add: {list(terms_to_add)}")
253
+ if len(terms_to_add) > 0:
254
+ for term in terms_to_add:
255
+ egeria_client.link_semantic_definition(guid, term, None)
256
+ msg = f"Added `{term}` to`{display_name}`"
257
+ logger.trace(msg)
258
+
259
+ classes_to_remove = as_is_data_classes - to_be_data_classes
260
+ logger.trace(f"classes_to_remove: {list(classes_to_remove)}")
261
+ if len(terms_to_remove) > 0:
262
+ for dc in classes_to_remove:
263
+ body = {
264
+ "class": "MetadataSourceRequestBody", "forLineage": False, "forDuplicateProcessing": False
265
+ }
266
+ egeria_client.detach_data_class_definition(guid, dc, body)
267
+ msg = f"Removed `{dc}` from `{display_name}`"
268
+ logger.trace(msg)
269
+ classes_to_add = to_be_data_classes - as_is_data_classes
270
+ logger.trace(f"classes_to_add: {list(classes_to_add)}")
271
+ if len(terms_to_add) > 0:
272
+ for dc in classes_to_add:
273
+ body = {
274
+ "class": "RelationshipRequestBody", "forLineage": False, "forDuplicateProcessing": False
275
+ }
276
+ egeria_client.link_data_class_definition(guid, dc, body)
277
+ msg = f"Added `{dc}` to`{display_name}`"
278
+ logger.trace(msg)
279
+
280
+
281
+ else: # merge - add field to related elements
282
+ if structure_list:
283
+ add_field_to_data_structures(egeria_client, display_name, structure_list, guid)
284
+ msg = f"Added `{display_name}` to `{structure_list}`"
285
+ logger.trace(msg)
286
+
287
+ if parent_field_list:
288
+ for field in parent_field_list:
289
+ egeria_client.link_nested_data_field(field, guid, None)
290
+ msg = f"Added `{display_name}` to `{field}`"
291
+ logger.trace(msg)
292
+ if terms:
293
+ for term in terms:
294
+ egeria_client.link_semantic_definition(guid, term, None)
295
+ msg = f"Added `{term}` to `{display_name}`"
296
+ logger.trace(msg)
297
+
298
+ if data_class_guid:
299
+ egeria_client.link_data_class_definition(guid, data_class_guid)
300
+ msg = f"Added `{data_class_guid}` to `{display_name}`"
301
+ logger.trace(msg)
302
+
303
+
304
+ @logger.catch
305
+ def sync_data_class_rel_elements(egeria_client: EgeriaTech, containing_data_class_guids: list, terms: list,
306
+ specializes_data_classes: list, guid: str, display_name: str,
307
+ replace_all_props: bool = True) -> None:
308
+ """Sync a data class' related elements.
99
309
 
310
+ """
311
+ if terms:
312
+ terms = [terms]
313
+
314
+ if replace_all_props:
315
+ rel_el_list = egeria_client.get_data_class_rel_elements(guid)
316
+ if rel_el_list is None:
317
+ logger.warning("Unexpected -> the list was None - assigning empty list")
318
+ rel_el_list = {}
319
+ if terms:
320
+ terms = [terms]
321
+
322
+ as_is_nested_classes = set(rel_el_list.get("nested_data_class_guids", []))
323
+ as_is_assigned_meanings = set(rel_el_list.get("assigned_meanings_guids", []))
324
+ as_is_specialized_classes = set(rel_el_list.get("specialized_data_class_guids", []))
325
+
326
+ to_be_nested_classes = set(containing_data_class_guids) if containing_data_class_guids is not None else set()
327
+ to_be_assigned_meanings = set(terms) if terms is not None else set()
328
+ to_be_specialized_classes = set([specializes_data_classes]) if specializes_data_classes is not None else set()
329
+
330
+ logger.trace(
331
+ f"as_is_nested_classes: {list(as_is_nested_classes)} to_be_nested_classes: {list(to_be_nested_classes)}")
332
+ logger.trace(f"as_is_assigned_meanings: {list(as_is_assigned_meanings)} to_be_assigned_meanings: "
333
+ f"{list(to_be_assigned_meanings)}")
334
+ logger.trace(f"as_is_specialized_classes: {list(as_is_specialized_classes)} to_be_specizialized_data_classes: "
335
+ f"{list(to_be_specialized_classes)}")
336
+
337
+ nested_classes_to_remove = to_be_nested_classes - as_is_nested_classes
338
+ logger.trace(f"nested_classes_to_remove: {list(nested_classes_to_remove)}")
339
+ if len(nested_classes_to_remove) > 0:
340
+ for field in nested_classes_to_remove:
341
+ egeria_client.detach_nested_data_class(field, guid, None)
342
+ msg = f"Removed `{display_name}` from field `{field}`"
343
+ logger.trace(msg)
344
+ nested_classes_to_add = to_be_nested_classes - as_is_nested_classes
345
+ logger.trace(f"nested_classes_to_add: {list(nested_classes_to_add)}")
346
+ if len(nested_classes_to_add) > 0:
347
+ for field in nested_classes_to_add:
348
+ egeria_client.link_nested_data_class(field, guid, None)
349
+ msg = f"Added `{display_name}` to field `{field}`"
350
+ logger.trace(msg)
351
+
352
+ terms_to_remove = as_is_assigned_meanings - to_be_assigned_meanings
353
+ logger.trace(f"terms_to_remove: {list(terms_to_remove)}")
354
+ if len(terms_to_remove) > 0:
355
+ for term in terms_to_remove:
356
+ egeria_client.detach_semantic_definition(guid, term, None)
357
+ msg = f"Removed `{term}` from `{display_name}`"
358
+ logger.trace(msg)
359
+ terms_to_add = to_be_assigned_meanings - as_is_assigned_meanings
360
+ logger.trace(f"terms_to_add: {list(terms_to_add)}")
361
+ if len(terms_to_add) > 0:
362
+ for term in terms_to_add:
363
+ egeria_client.link_semantic_definition(guid, term, None)
364
+ msg = f"Added `{term}` to`{display_name}`"
365
+ logger.trace(msg)
366
+
367
+ specialized_classes_to_remove = as_is_specialized_classes - to_be_specialized_classes
368
+ logger.trace(f"classes_to_remove: {list(specialized_classes_to_remove)}")
369
+ if len(terms_to_remove) > 0:
370
+ for dc in specialized_classes_to_remove:
371
+ body = {
372
+ "class": "MetadataSourceRequestBody", "forLineage": False, "forDuplicateProcessing": False
373
+ }
374
+ egeria_client.detach_specialist_data_class(guid, dc, body)
375
+ msg = f"Removed `{dc}` from `{display_name}`"
376
+ logger.trace(msg)
377
+ specialized_classes_to_add = to_be_specialized_classes - as_is_specialized_classes
378
+ logger.trace(f"classes_to_add: {list(specialized_classes_to_add)}")
379
+ if len(specialized_classes_to_add) > 0:
380
+ for dc in specialized_classes_to_add:
381
+ body = {
382
+ "class": "RelationshipRequestBody", "forLineage": False, "forDuplicateProcessing": False
383
+ }
384
+ egeria_client.link_specialist_data_class(guid, dc, body)
385
+ msg = f"Added `{dc}` to`{display_name}`"
386
+ logger.trace(msg)
387
+
388
+
389
+ else: # merge - add field to related elements
390
+ if containing_data_class_guids:
391
+ for field in containing_data_class_guids:
392
+ egeria_client.link_nested_data_class(field, guid, None)
393
+ msg = f"Added `{display_name}` to `{field}`"
394
+ logger.trace(msg)
395
+
396
+ if terms:
397
+ for term in terms:
398
+ egeria_client.link_semantic_definition(guid, term, None)
399
+ msg = f"Added `{term}` to `{display_name}`"
400
+ logger.trace(msg)
401
+ if specializes_data_classes:
402
+ for el in specializes_data_classes:
403
+ egeria_client.link_specialist_data_class(guid, el)
404
+ msg = f"Linked `{el}` to `{display_name}`"
405
+ logger.trace(msg)
406
+
407
+
408
+ @logger.catch
100
409
  def process_data_spec_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
101
410
  """
102
411
  Processes a data specification create or update object_action by extracting key attributes such as
@@ -107,13 +416,10 @@ def process_data_spec_upsert_command(egeria_client: EgeriaTech, txt: str, direct
107
416
  :param directive: an optional string indicating the directive to be used - display, validate or execute
108
417
  :return: A string summarizing the outcome of the processing.
109
418
  """
110
- from md_processing.md_processing_utils.common_md_utils import set_debug_level
111
-
112
- set_debug_level(directive)
113
419
 
114
420
  command, object_type, object_action = extract_command_plus(txt)
115
421
 
116
- parsed_output = parse_user_command(egeria_client, object_type, object_action, txt, directive)
422
+ parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
117
423
 
118
424
  valid = parsed_output['valid']
119
425
  exists = parsed_output['exists']
@@ -123,21 +429,31 @@ def process_data_spec_upsert_command(egeria_client: EgeriaTech, txt: str, direct
123
429
 
124
430
  print(Markdown(parsed_output['display']))
125
431
 
126
- print(json.dumps(parsed_output, indent=4))
432
+ logger.debug(json.dumps(parsed_output, indent=4))
127
433
 
128
434
  attributes = parsed_output['attributes']
129
435
  description = attributes['Description'].get('value', None)
130
436
  display_name = attributes['Display Name'].get('value', None)
131
437
  anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
132
438
  parent_guid = attributes.get('Parent ID', {}).get('guid', None)
133
- parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value', "CollectionMembership")
439
+ parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value',
440
+ "CollectionMembership")
134
441
  parent_at_end1 = attributes.get('Parent at End1', {}).get('value', True)
135
442
 
136
443
  anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
137
444
  is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', True)
138
- collection_ordering = "NAME"
139
- order_property_name = "Something"
140
- collection_type = object_type
445
+ if parent_guid is None:
446
+ is_own_anchor = True
447
+
448
+ collection_type = attributes.get('Collection Type', {}).get('value', None)
449
+
450
+ replace_all_props = not attributes.get('Merge Update', {}).get('value', True)
451
+
452
+ additional_prop = attributes.get('Additional Properties', {}).get('value', None)
453
+ additional_properties = json.loads(additional_prop) if additional_prop is not None else None
454
+ extended_prop = attributes.get('Extended Properties', {}).get('value', None)
455
+ extended_properties = json.loads(extended_prop) if extended_prop is not None else None
456
+
141
457
  replace_all_props = not attributes.get('Merge Update', {}).get('value', True)
142
458
  in_data_spec_list = attributes.get('In Data Specification', {}).get('value', None)
143
459
  in_data_spec_valid = attributes.get('In Data Specification', {}).get('valid', None)
@@ -154,16 +470,12 @@ def process_data_spec_upsert_command(egeria_client: EgeriaTech, txt: str, direct
154
470
  return valid
155
471
 
156
472
  elif directive == "process":
157
-
158
-
159
-
160
-
161
473
  try:
162
474
  if object_action == "Update":
163
475
  if not exists:
164
476
  msg = (f" Element `{display_name}` does not exist! Updating result document with Create "
165
- f"object_action\n")
166
- print_msg(ERROR, msg, debug_level)
477
+ f"object_action\n")
478
+ logger.error(msg)
167
479
  return update_a_command(txt, object_action, object_type, qualified_name, guid)
168
480
  elif not valid:
169
481
  return None
@@ -172,48 +484,54 @@ def process_data_spec_upsert_command(egeria_client: EgeriaTech, txt: str, direct
172
484
  f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
173
485
 
174
486
  egeria_client.update_collection(guid, qualified_name, display_name, description, collection_type,
175
- collection_ordering, order_property_name, replace_all_props)
176
- print_msg(ALWAYS, f"Updated {object_type} `{display_name}` with GUID {guid}", debug_level)
487
+ additional_properties,
488
+ extended_properties, replace_all_props)
489
+ logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}\n\n___")
177
490
  update_element_dictionary(qualified_name, {
178
491
  'guid': guid, 'display_name': display_name
179
492
  })
180
- return egeria_client.get_collection_by_guid(guid, output_format='FORM')
493
+ return egeria_client.get_collection_by_guid(guid, collection_type='Data Specification',
494
+ output_format='MD')
181
495
 
182
496
 
183
497
  elif object_action == "Create":
184
498
  if valid is False and exists:
185
499
  msg = (f" Data Specification `{display_name}` already exists and result document updated changing "
186
- f"`Create` to `Update` in processed output\n")
187
- print_msg(ERROR, msg, debug_level)
500
+ f"`Create` to `Update` in processed output\n\n___")
501
+ logger.error(msg)
188
502
  return update_a_command(txt, object_action, object_type, qualified_name, guid)
189
503
  elif valid is False and in_data_spec_valid is False:
190
504
  msg = (f" Invalid data specification(s) `{in_data_spec_list}` "
191
- f" perhaps they don't yet exist? - Correct and try again")
192
- print_msg(ERROR, msg, debug_level)
505
+ f" invalid data? - Correct and try again\n\n___")
506
+ logger.error(msg)
507
+ return None
193
508
  else:
194
- guid = egeria_client.create_data_spec_collection(anchor_guid, parent_guid,
509
+ guid = egeria_client.create_data_spec_collection(display_name, description, qualified_name,
510
+ is_own_anchor, anchor_guid, parent_guid,
195
511
  parent_relationship_type_name, parent_at_end1,
196
- display_name, description, collection_type,
197
- anchor_scope_guid, is_own_anchor,
198
- collection_ordering, order_property_name,
199
- qualified_name)
512
+ collection_type, anchor_scope_guid,
513
+ additional_properties, extended_properties)
200
514
  if guid:
201
-
202
- print_msg(ALWAYS, f"Created Element `{display_name}` with GUID {guid}", debug_level)
203
-
204
- return egeria_client.get_collection_by_guid(guid, output_format='FORM')
515
+ update_element_dictionary(qualified_name, {
516
+ 'guid': guid, 'display_name': display_name
517
+ })
518
+ msg = f"Created Element `{display_name}` with GUID {guid}\n\n___"
519
+ logger.success(msg)
520
+ return egeria_client.get_collection_by_guid(guid, collection_type='Data Specification',
521
+ output_format='MD')
205
522
  else:
206
- print_msg(ERROR, f"Failed to create Term `{display_name}`", debug_level)
523
+ msg = f"Failed to create element `{display_name}` with GUID {guid}\n\n___"
524
+ logger.error(msg)
207
525
  return None
208
526
 
209
527
  except Exception as e:
210
- print(f"{ERROR}Error performing {command}: {e}")
211
- Console().print_exception(show_locals=True)
528
+ logger.error(f"Error performing {command}: {e}")
212
529
  return None
213
530
  else:
214
531
  return None
215
532
 
216
533
 
534
+ @logger.catch
217
535
  def process_data_dict_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
218
536
  """
219
537
  Processes a data dictionary create or update object_action by extracting key attributes such as
@@ -224,13 +542,10 @@ def process_data_dict_upsert_command(egeria_client: EgeriaTech, txt: str, direct
224
542
  :param directive: an optional string indicating the directive to be used - display, validate or execute
225
543
  :return: A string summarizing the outcome of the processing.
226
544
  """
227
- from md_processing.md_processing_utils.common_md_utils import set_debug_level
228
-
229
- set_debug_level(directive)
230
545
 
231
546
  command, object_type, object_action = extract_command_plus(txt)
232
547
 
233
- parsed_output = parse_user_command(egeria_client, object_type, object_action, txt, directive)
548
+ parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
234
549
 
235
550
  valid = parsed_output['valid']
236
551
  exists = parsed_output['exists']
@@ -239,9 +554,31 @@ def process_data_dict_upsert_command(egeria_client: EgeriaTech, txt: str, direct
239
554
  guid = parsed_output.get('guid', None)
240
555
 
241
556
  print(Markdown(parsed_output['display']))
557
+ logger.debug(json.dumps(parsed_output, indent=4))
242
558
 
243
- if directive == "display":
559
+ attributes = parsed_output['attributes']
560
+ description = attributes['Description'].get('value', None)
561
+ display_name = attributes.get('Display Name', {}).get('value', "None Found")
562
+ display_name = display_name if display_name is not None else "None Found"
563
+ anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
564
+ parent_guid = attributes.get('Parent ID', {}).get('guid', None)
565
+ parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value',
566
+ "CollectionMembership")
567
+ parent_at_end1 = attributes.get('Parent at End1', {}).get('value', True)
568
+
569
+ anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
570
+ is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', True)
571
+ if parent_guid is None:
572
+ is_own_anchor = True
573
+ collection_type = attributes.get('Collection Type', {}).get('value', None)
574
+ replace_all_props = not attributes.get('Merge Update', {}).get('value', True)
575
+
576
+ additional_prop = attributes.get('Additional Properties', {}).get('value', None)
577
+ additional_properties = json.loads(additional_prop) if additional_prop is not None else None
578
+ extended_prop = attributes.get('Extended Properties', {}).get('value', None)
579
+ extended_properties = json.loads(extended_prop) if extended_prop is not None else None
244
580
 
581
+ if directive == "display":
245
582
  return None
246
583
  elif directive == "validate":
247
584
  if valid:
@@ -251,79 +588,67 @@ def process_data_dict_upsert_command(egeria_client: EgeriaTech, txt: str, direct
251
588
  return valid
252
589
 
253
590
  elif directive == "process":
254
- print(json.dumps(parsed_output, indent=4))
255
-
256
- attributes = parsed_output['attributes']
257
- description = attributes['Description'].get('value', None)
258
- display_name = attributes['Display Name'].get('value', None)
259
- anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
260
- parent_guid = attributes.get('Parent ID', {}).get('guid', None)
261
- parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value',
262
- "CollectionMembership")
263
- parent_at_end1 = attributes.get('Parent at End1', {}).get('value', True)
264
-
265
- anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
266
- is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', True)
267
- if parent_guid is None:
268
- is_own_anchor = True
269
- collection_ordering = "NAME"
270
- order_property_name = "Something"
271
- collection_type = object_type
272
- replace_all_props = not attributes.get('Merge Update', {}).get('value', True)
273
-
274
591
 
275
592
  try:
276
593
  if object_action == "Update":
277
594
 
278
595
  if not exists:
279
- print(f"\n{ERROR}Element `{display_name}` does not exist! Updating result document with Create "
280
- f"object_action\n")
596
+ logger.error(f"Element `{display_name}` does not exist! Updating result document with Create "
597
+ f"object_action\n\n___")
281
598
  return update_a_command(txt, object_action, object_type, qualified_name, guid)
282
599
  elif not valid:
600
+ logger.error(f"Element `{display_name}` does not have a valid specification? Review..\n\n___ ")
283
601
  return None
284
602
  else:
285
603
  print(Markdown(
286
- f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
604
+ f"==> Validation of {command} completed successfully! Proceeding to apply the changes."))
287
605
 
288
606
  egeria_client.update_collection(guid, qualified_name, display_name, description, collection_type,
289
- collection_ordering, order_property_name, replace_all_props)
290
- print_msg(ALWAYS, f"Updated {object_type} `{display_name}` with GUID {guid}", debug_level)
607
+ additional_properties,
608
+ extended_properties, replace_all_props)
609
+ logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}\n\n___")
291
610
  update_element_dictionary(qualified_name, {
292
611
  'guid': guid, 'display_name': display_name
293
612
  })
294
- return egeria_client.get_collection_by_guid(guid, output_format='FORM')
613
+ return egeria_client.get_collection_by_guid(guid, collection_type='Data Dictionary', output_format='MD')
295
614
 
296
615
  elif object_action == "Create":
297
616
  if valid is False and exists:
298
- print(f"\nElement `{display_name}` already exists and result document updated changing "
299
- f"`Create` to `Update` in processed output\n")
617
+ logger.error(f"\nElement `{display_name}` already exists and result document updated changing "
618
+ f"`Create` to `Update` in processed output\n\n___")
300
619
  return update_a_command(txt, object_action, object_type, qualified_name, guid)
301
620
  else:
302
- guid = egeria_client.create_data_dictionary_collection(anchor_guid, parent_guid,
621
+ guid = egeria_client.create_data_dictionary_collection(display_name, description, qualified_name,
622
+ is_own_anchor, anchor_guid, parent_guid,
303
623
  parent_relationship_type_name,
304
- parent_at_end1, display_name, description,
305
- collection_type, anchor_scope_guid,
306
- is_own_anchor, collection_ordering,
307
- order_property_name, qualified_name)
624
+ parent_at_end1, collection_type,
625
+ anchor_scope_guid, additional_properties,
626
+ extended_properties)
308
627
  if guid:
309
- print_msg(ALWAYS, f"Created Element `{display_name}` with GUID {guid}", debug_level)
628
+ update_element_dictionary(qualified_name, {
629
+ 'guid': guid, 'display_name': display_name
630
+ })
631
+ logger.success(f"Created Element `{display_name}` with GUID {guid}\n\n___")
310
632
 
311
- return egeria_client.get_collection_by_guid(guid, output_format='FORM')
633
+ return egeria_client.get_collection_by_guid(guid, collection_type='Data Dictionary',
634
+ output_format='MD')
312
635
  else:
313
- print_msg(ERROR, f"Failed to create Term `{display_name}`", debug_level)
636
+ logger.error(f"Failed to create Term `{display_name}`\n\n___")
314
637
  return None
315
638
 
316
639
  except Exception as e:
317
- print(f"{ERROR}Error performing {command}: {e}")
640
+ logger.error(f"{ERROR}Error performing {command}: {e}")
318
641
  Console().print_exception(show_locals=True)
319
642
  return None
320
643
  else:
321
644
  return None
322
645
 
323
646
 
324
- def process_data_field_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
647
+ @logger.catch
648
+ def process_data_structure_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[
649
+ str]:
325
650
  """
326
- Processes a data dictionary create or update object_action by extracting key attributes such as
651
+ Processes a data structure create or update object_action by extracting key attributes such as
327
652
  spec name, parent_guid, parent_relationship_type, parent_at_end_1, collection_type
328
653
 
329
654
  :param txt: A string representing the input cell to be processed for
@@ -336,8 +661,9 @@ def process_data_field_upsert_command(egeria_client: EgeriaTech, txt: str, direc
336
661
  set_debug_level(directive)
337
662
 
338
663
  command, object_type, object_action = extract_command_plus(txt)
664
+ print(Markdown(f"# {command}\n"))
339
665
 
340
- parsed_output = parse_user_command(egeria_client, object_type, object_action, txt, directive)
666
+ parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
341
667
 
342
668
  valid = parsed_output['valid']
343
669
  exists = parsed_output['exists']
@@ -348,8 +674,8 @@ def process_data_field_upsert_command(egeria_client: EgeriaTech, txt: str, direc
348
674
  print(Markdown(parsed_output['display']))
349
675
 
350
676
  if directive == "display":
351
-
352
677
  return None
678
+
353
679
  elif directive == "validate":
354
680
  if valid:
355
681
  print(Markdown(f"==> Validation of {command} completed successfully!\n"))
@@ -358,7 +684,7 @@ def process_data_field_upsert_command(egeria_client: EgeriaTech, txt: str, direc
358
684
  return valid
359
685
 
360
686
  elif directive == "process":
361
- print(json.dumps(parsed_output, indent=4))
687
+ logger.debug(json.dumps(parsed_output, indent=4))
362
688
  attributes = parsed_output['attributes']
363
689
 
364
690
  external_source_guid = attributes.get('External Source Name', {}).get('guid', None)
@@ -368,16 +694,16 @@ def process_data_field_upsert_command(egeria_client: EgeriaTech, txt: str, direc
368
694
  for_duplicate_processing = attributes.get('For Duplicate Processing', {}).get('value', None)
369
695
  anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
370
696
  is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', None)
371
- # parent_id = attributes.get('Parent ID', {}).get('value', None)
372
- # parent_guid = attributes['Parent ID'].get('guid', None)
373
- # parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value', None)
374
- # parent_relationship_properties = attributes.get('Parent Relationship Properties',{}).get('value', None)
375
- # parent_at_end1 = attributes.get('Parent at End1', {}).get('value', None)
697
+ parent_id = attributes.get('Parent ID', {}).get('value', None)
698
+ parent_guid = attributes.get('Parent ID', {}).get('guid', None)
699
+ parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value', None)
700
+ parent_relationship_properties = attributes.get('Parent Relationship Properties', {}).get('value', None)
701
+ parent_at_end1 = attributes.get('Parent at End1', {}).get('value', None)
376
702
 
377
703
  display_name = attributes['Display Name'].get('value', None)
378
704
 
379
- namespace = attributes.get('Namespace',{}).get('value', None)
380
- description = attributes.get('Description',{}).get('value', None)
705
+ namespace = attributes.get('Namespace', {}).get('value', None)
706
+ description = attributes.get('Description', {}).get('value', None)
381
707
  version_id = attributes.get('Version Identifier', {}).get('value', None)
382
708
  aliases = attributes.get('Aliases', {}).get('value', None)
383
709
  name_patterns = attributes.get('Name Patterns', {}).get('value', None)
@@ -396,215 +722,131 @@ def process_data_field_upsert_command(egeria_client: EgeriaTech, txt: str, direc
396
722
  position = attributes.get('Position', {}).get('value', None)
397
723
  min_cardinality = attributes.get('Minimum Cardinality', {}).get('value', None)
398
724
  max_cardinality = attributes.get('Maximum Cardinality', {}).get('value', None)
399
-
400
725
  in_data_structure = attributes.get('In Data Structure', {}).get('value', None)
401
- in_data_structure_names = attributes.get('In Data Structure Names', {}).get('name_list', None)
726
+ data_class = attributes.get('Data Class', {}).get('value', None)
727
+ glossary_term = attributes.get('Glossary Term', {}).get('value', None)
728
+ glossary_term_guid = attributes.get('Glossary Term', {}).get('guid', None)
402
729
 
403
- data_class = attributes['Data Class'].get('value', None)
730
+ # name_details_list = attributes.get("dict_list", None)
404
731
 
405
- glossary_term = attributes['Glossary Term'].get('value', None)
406
- glossary_term_guid = attributes['Glossary Term'].get('guid', None)
732
+ data_spec_name_list = attributes.get("In Data Specification", {}).get("name_list", "")
733
+ data_spec_value = attributes.get("In Data Specification", {}).get("value", None)
734
+ data_spec_guid_list = attributes.get("In Data Specification", {}).get("guid_list", None)
407
735
 
408
- in_data_dictionary = attributes.get('In Data Dictionary', {}).get('value', None)
409
- in_data_dictionary_names = attributes.get('In Data Dictionary Names', {}).get('name_list', None)
736
+ in_data_dictionary = attributes.get('In Data Dictionary', {}).get('dict_list', None)
737
+ data_dict_name_list = attributes.get('In Data Dictionary', {}).get('name_list', "")
738
+ data_dict_value_list = attributes.get('In Data Dictionary', {}).get('value', None)
739
+ data_dict_guid_list = attributes.get("In Data Dictionary", {}).get("guid_list", None)
410
740
 
411
741
  parent_data_field = attributes.get('Parent Data Field', {}).get('value', None)
412
742
  parent_data_field_guid = attributes.get('Parent Data Field', {}).get('guid', None)
413
743
 
414
744
  anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
415
745
 
416
- merge_update = attributes.get('Merge Update', {}).get('value', None)
417
-
418
-
419
- collection_ordering = "NAME"
420
- order_property_name = "Something"
421
746
  collection_type = object_type
422
747
  replace_all_props = True
423
-
424
748
  if not valid:
425
749
  if exists and object_action == "Create":
426
750
  msg = (f"Create failed because Element `{display_name}` exists - changing `Create` to `Update` in "
427
- f"processed output \n")
428
- print_msg(ERROR, msg, debug_level)
751
+ f"processed output \n\n___")
752
+ logger.error(msg)
429
753
  return update_a_command(txt, object_action, object_type, qualified_name, guid)
430
754
  else:
431
755
  return None
756
+ elif object_action == "Update" and not exists:
757
+ logger.error(f"Element `{display_name}` does not exist! Updating result document with Create "
758
+ f"object_action\n\n___")
759
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
760
+
432
761
  else:
433
762
  print(Markdown(f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
434
763
 
435
764
  try:
436
765
  if object_action == "Update":
437
- if not exists:
438
- print(f"\n{ERROR}Element `{display_name}` does not exist! Updating result document with Create "
439
- f"object_action\n")
440
- return update_a_command(txt, object_action, object_type, qualified_name, guid)
441
-
442
766
  body = {
443
- "class": "UpdateDataFieldRequestBody",
444
- "externalSourceGUID": external_source_guid,
445
- "externalSourceName": external_source_name,
446
- "effectiveTime": None,
447
- "forLineage": False,
448
- "forDuplicateProcessing": False,
449
- "properties": {
450
- "class": "DataFieldProperties",
451
- "qualifiedName": qualified_name,
452
- "displayName": display_name,
453
- "namespace": namespace,
454
- "description": description,
455
- "versionIdentifier": version_id,
456
- "aliases": aliases,
457
- "namePatterns": name_patterns,
458
- "isDeprecated": False,
459
- "isNullable": is_nullable,
460
- "defaultValue": default_value,
461
- "dataType": data_type,
462
- "minimumLength": min_length,
463
- "length": length,
464
- "precision": precision,
465
- "orderedValues": ordered_values,
466
- "sortOrder": sort_order,
467
- "additionalProperties": additional_properties,
468
- "effectiveFrom": effective_from,
469
- "effectiveTo": effective_to
767
+ "class": "UpdateElementRequestBody", "externalSourceGUID": external_source_guid,
768
+ "externalSourceName": external_source_name, "effectiveTime": effective_time,
769
+ "forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing, "properties": {
770
+ "class": "DataStructureProperties", "qualifiedName": qualified_name,
771
+ "displayName": display_name, "description": description, "namespace": namespace,
772
+ "versionIdentifier": version_id, "additionalProperties": additional_properties,
773
+ "effectiveFrom": effective_from, "effectiveTo": effective_to
470
774
  }
471
775
  }
776
+ egeria_client.update_data_structure_w_body(guid, body, replace_all_props)
777
+ logger.info(f"Updated element `{display_name}` with GUID {guid}")
778
+ core_props = egeria_client.get_data_structure_by_guid(guid, output_format='MD')
472
779
 
473
- egeria_client.update_data_field(guid, body, not merge_update)
474
- print_msg(ALWAYS, f"Updated {object_type} `{display_name}` with GUID {guid}", debug_level)
475
- # Update data dictionary membership
476
780
  update_element_dictionary(qualified_name, {
477
781
  'guid': guid, 'display_name': display_name
478
782
  })
479
- core_props = egeria_client.get_data_field_by_guid(guid, output_format='MD')
480
-
481
- existing_data_field = egeria_client.get_data_field_by_guid(guid, output_format='JSON')
482
- existing_data_field_dicts = 3
483
-
484
- # Sync membership in data dictionaries
485
- result = sync_data_dict_membership(egeria_client, in_data_dictionary_names, in_data_dictionary, guid, object_type)
486
- print_msg(ALWAYS, f"Will update data dictionary `{in_data_dictionary}`", debug_level)
487
- core_props += f"\n\n## In Data Dictionary\n\n{in_data_dictionary}\n\n"
488
-
489
- # Update data spec membership
490
- result = sync_data_spec_membership(egeria_client, in_data_dictionary_names, in_data_dictionary, guid,
491
- object_type)
492
- print_msg(ALWAYS, f"Will update data dictionary `{in_data_dictionary}`", debug_level)
493
- core_props += f"\n\n## In Data Dictionary\n\n{in_data_dictionary}\n\n"
494
-
495
- # Sync membership in data structuress
496
- result = sync_data_structure_membership(egeria_client, in_data_dictionary_names, in_data_dictionary, guid,
497
- object_type)
498
- core_props += f"\n\n## In Data Structure {in_data_structure}\n\n"
499
-
500
- # Update glossary links
501
- result = sync_term_links(egeria_client, glossary_term, glossary_term_guid, guid, object_type)
502
- print_msg(ALWAYS, f"Updating glossary term to `{glossary_term}`", debug_level)
503
-
504
- core_props += f"\n\n## Glossary Term \n\n{glossary_term}\n\n"
505
- # Update parent field
506
- result = sync_parent_data_field(egeria_client, parent_data_field, parent_data_field_guid, guid, object_type)
507
-
508
- core_props += f"\n\n## Parent Data Field\n\n{parent_data_field}\n\n"
509
-
510
- # Update data classes
511
- print_msg(ALWAYS, f"Created Element `{display_name}` ", debug_level)
512
-
513
783
 
784
+ update_data_collection_memberships(egeria_client, object_type, data_spec_guid_list, "DataSpec", guid,
785
+ display_name, replace_all_props)
786
+ core_props += f"## In Data Dictionary\n\n{data_dict_name_list}\n\n"
787
+ core_props += f"## In Data Specification\n\n{data_spec_name_list}\n\n"
788
+ logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}\n\n___")
514
789
  return core_props
515
790
 
516
-
517
791
  elif object_action == "Create":
518
- if valid is False and exists:
519
- print(f"\nData Field `{display_name}` already exists and result document updated changing `Create` "
520
- f"to `Update` in processed output\n")
792
+ if exists:
793
+ logger.warning(f"\nTerm `{display_name}` already exists and result document updated\n\n___")
521
794
  return update_a_command(txt, object_action, object_type, qualified_name, guid)
522
795
  else:
523
- # First lets create the data field
796
+
524
797
  body = {
798
+ "class": "NewElementRequestBody", "externalSourceGUID": external_source_guid,
799
+ "externalSourceName": external_source_name, "effectiveTime": effective_time,
800
+ "forLineage": False, "forDuplicateProcessing": False, "anchorGUID": anchor_guid,
801
+ "isOwnAnchor": is_own_anchor, "parentGUID": parent_guid,
802
+ "parentRelationshipTypeName": parent_relationship_type_name,
803
+ "parentRelationshipProperties": parent_relationship_properties, "parentAtEnd1": parent_at_end1,
525
804
  "properties": {
526
- "class": "DataFieldProperties", "qualifiedName": qualified_name,
527
- "displayName": display_name, "namespace": namespace, "description": description,
528
- "versionIdentifier": version_id, "aliases": aliases, "namePatterns": name_patterns,
529
- "isDeprecated": False, "isNullable": is_nullable, "defaultValue": default_value,
530
- "dataType": data_type, "minimumLength": min_length, "length": length,
531
- "precision": precision, "orderedValues": ordered_values, "sortOrder": sort_order,
532
- "additionalProperties": additional_properties
805
+ "class": "DataStructureProperties", "qualifiedName": qualified_name,
806
+ "displayName": display_name, "description": description, "namespace": namespace,
807
+ "versionIdentifier": version_id, "additionalProperties": additional_properties,
808
+ "effectiveFrom": effective_from, "effectiveTo": effective_to
533
809
  }
534
810
  }
535
- guid = egeria_client.create_data_field(body)
811
+
812
+ guid = egeria_client.create_data_structure_w_body(body_slimmer(body))
536
813
  if guid:
537
- # Now update our element dictionary with the new information
538
814
  update_element_dictionary(qualified_name, {
539
815
  'guid': guid, 'display_name': display_name
540
816
  })
541
- # Start assembling the information we will present back out
542
- core_props = egeria_client.get_data_field_by_guid(guid, output_format='MD')
543
-
544
- # Add the field to any data dictionaries
545
- if in_data_dictionary:
546
- print_msg(ALWAYS, f"Will add to data dictionary `{in_data_dictionary}`", debug_level)
547
- core_props += f"\n\n## In Data Dictionary\n\n{in_data_dictionary_names}\n\n"
548
- # Add the field to any data structures
549
- if in_data_structure:
550
- core_props += f"\n\n## In Data Structure\n\n{in_data_structure_names}\n\n"
551
- for key in in_data_structure.keys():
552
- ds_qname = in_data_structure[key].get('known_q_name', None)
553
- ds_guid = in_data_structure[key].get('known_guid', None)
554
- if ds_guid is not None:
555
- df_body = {
556
- "class": "MemberDataFieldRequestBody", "properties": {
557
- "class": "MemberDataFieldProperties", "dataFieldPosition": 0,
558
- "minCardinality": 0, "maxCardinality": -1,
559
- }
560
- }
561
817
 
562
- msg = f"Adding field to structure {ds_qname}"
563
- print_msg(INFO, msg, debug_level)
564
- egeria_client.link_member_data_field(ds_guid, guid, df_body)
565
- core_props += f"\n\n## In Data Structure {in_data_structure}\n\n"
818
+ core_props = egeria_client.get_data_structure_by_guid(guid, output_format='MD')
566
819
 
567
- if glossary_term:
568
- if glossary_term_guid:
569
- glossary_body = {
570
- "class": "MetadataSourceRequestBody", "externalSourceGUID": None,
571
- "externalSourceName": None, "effectiveTime": None, "forLineage": False,
572
- "forDuplicateProcessing": False
573
- }
574
-
575
- core_props += f"\n\n## Glossary Term \n\n{glossary_term}\n\n"
576
- egeria_client.link_semantic_definition(guid, glossary_term_guid, glossary_body)
820
+ if in_data_dictionary:
821
+ logger.info(f"Will add to data dictionary(s) `{in_data_dictionary}`")
822
+ result = add_member_to_data_collections(egeria_client, in_data_dictionary, display_name,
823
+ guid)
824
+ core_props += f"## In Data Dictionary\n\n{data_dict_name_list}\n\n"
577
825
 
578
- if parent_data_field_guid:
579
- parent_df_body = {
580
- "class": "MetadataSourceRequestBody", "externalSourceGUID": None,
581
- "externalSourceName": None, "effectiveTime": None, "forLineage": False,
582
- "forDuplicateProcessing": False
583
- }
826
+ if data_spec_guid_list:
827
+ result = add_member_to_data_collections(egeria_client, data_spec_guid_list, display_name,
828
+ guid)
829
+ core_props += f"## In Data Specifications\n\n`{data_spec_name_list}`\n\n"
584
830
 
585
- egeria_client.link_nested_data_field(parent_data_field_guid, guid, parent_df_body)
586
- core_props += f"\n\n## Parent Data Field\n\n{parent_data_field}\n\n"
831
+ logger.info(f"Created Element `{display_name}` with GUID {guid}\n\n___")
587
832
 
588
- # Link data class
589
- print_msg(ALWAYS, f"Created Element `{display_name}` ", debug_level)
590
833
  return core_props
591
-
592
834
  else:
593
- print_msg(ERROR, f"Failed to create Term `{display_name}`", debug_level)
835
+ logger.error(f"Failed to create Data Structure `{display_name}`\n\n___")
594
836
  return None
595
837
 
838
+
596
839
  except Exception as e:
597
- print(f"{ERROR}Error performing {command}: {e}")
598
- Console().print_exception(show_locals=True)
840
+ logger.error(f"Error performing {object_action}: {e}\n\n___")
599
841
  return None
600
842
  else:
601
843
  return None
602
844
 
603
845
 
604
- def process_data_structure_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[
605
- str]:
846
+ @logger.catch
847
+ def process_data_field_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
606
848
  """
607
- Processes a data structure create or update object_action by extracting key attributes such as
849
+ Processes a data field create or update object_action by extracting key attributes such as
608
850
  spec name, parent_guid, parent_relationship_type, parent_at_end_1, collection_type
609
851
 
610
852
  :param txt: A string representing the input cell to be processed for
@@ -617,30 +859,31 @@ def process_data_structure_upsert_command(egeria_client: EgeriaTech, txt: str, d
617
859
  set_debug_level(directive)
618
860
 
619
861
  command, object_type, object_action = extract_command_plus(txt)
862
+ print(Markdown(f"# {command}\n"))
620
863
 
621
- parsed_output = parse_user_command(egeria_client, object_type, object_action, txt, directive)
622
-
623
- valid = parsed_output['valid']
624
- exists = parsed_output['exists']
625
-
864
+ parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
865
+ attributes = parsed_output['attributes']
866
+ display_name = attributes['Display Name'].get('value', None)
626
867
  qualified_name = parsed_output.get('qualified_name', None)
627
868
  guid = parsed_output.get('guid', None)
869
+ valid = parsed_output['valid']
870
+ exists = parsed_output['exists']
628
871
 
629
872
  print(Markdown(parsed_output['display']))
630
873
 
631
874
  if directive == "display":
632
- return None
633
875
 
876
+ return None
634
877
  elif directive == "validate":
635
878
  if valid:
636
879
  print(Markdown(f"==> Validation of {command} completed successfully!\n"))
637
880
  else:
638
881
  msg = f"Validation failed for object_action `{command}`\n"
882
+ logger.error(msg)
639
883
  return valid
640
884
 
641
885
  elif directive == "process":
642
- print(json.dumps(parsed_output, indent=4))
643
- attributes = parsed_output['attributes']
886
+ logger.debug(json.dumps(parsed_output, indent=4))
644
887
 
645
888
  external_source_guid = attributes.get('External Source Name', {}).get('guid', None)
646
889
  external_source_name = attributes.get('External Source Name', {}).get('value', None)
@@ -649,13 +892,11 @@ def process_data_structure_upsert_command(egeria_client: EgeriaTech, txt: str, d
649
892
  for_duplicate_processing = attributes.get('For Duplicate Processing', {}).get('value', None)
650
893
  anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
651
894
  is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', None)
652
- parent_id = attributes.get('Parent ID', {}).get('value', None)
653
- parent_guid = attributes.get('Parent ID', {}).get('guid', None)
654
- parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value', None)
655
- parent_relationship_properties = attributes.get('Parent Relationship Properties', {}).get('value', None)
656
- parent_at_end1 = attributes.get('Parent at End1', {}).get('value', None)
657
-
658
- display_name = attributes['Display Name'].get('value', None)
895
+ # parent_id = attributes.get('Parent ID', {}).get('value', None)
896
+ # parent_guid = attributes['Parent ID'].get('guid', None)
897
+ # parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value', None)
898
+ # parent_relationship_properties = attributes.get('Parent Relationship Properties',{}).get('value', None)
899
+ # parent_at_end1 = attributes.get('Parent at End1', {}).get('value', None)
659
900
 
660
901
  namespace = attributes.get('Namespace', {}).get('value', None)
661
902
  description = attributes.get('Description', {}).get('value', None)
@@ -674,309 +915,468 @@ def process_data_structure_upsert_command(egeria_client: EgeriaTech, txt: str, d
674
915
  effective_from = attributes.get('Effective From', {}).get('value', None)
675
916
  effective_to = attributes.get('Effective To', {}).get('value', None)
676
917
 
918
+ glossary_term = attributes['Glossary Term'].get('value', None)
919
+ glossary_term_guid = attributes['Glossary Term'].get('guid', None)
920
+
921
+ merge_update = attributes.get('Merge Update', {}).get('value', None)
922
+
677
923
  position = attributes.get('Position', {}).get('value', None)
678
924
  min_cardinality = attributes.get('Minimum Cardinality', {}).get('value', None)
679
925
  max_cardinality = attributes.get('Maximum Cardinality', {}).get('value', None)
926
+
680
927
  in_data_structure = attributes.get('In Data Structure', {}).get('value', None)
928
+ data_structure_guid_list = attributes.get('In Data Structure', {}).get('guid_list', None)
929
+ in_data_structure_names = attributes.get('In Data Structure Names', {}).get('name_list', None)
930
+
681
931
  data_class = attributes.get('Data Class', {}).get('value', None)
682
- glossary_term = attributes.get('Glossary Term', {}).get('value', None)
932
+ data_class_guid = attributes.get('Data Class', {}).get('guid', None)
933
+
934
+ glossary_term_guid = attributes.get('Glossary Term', {}).get('guid', None)
935
+ if glossary_term_guid:
936
+ glossary_term_guid = [glossary_term_guid]
937
+
683
938
  glossary_term_guid = attributes.get('Glossary Term', {}).get('guid', None)
684
939
 
685
940
  # name_details_list = attributes.get("dict_list", None)
686
941
 
687
- in_data_spec = attributes.get("In Data Specification", {}).get("dict_list") # this is a [dict]
942
+ in_data_spec = attributes.get("In Data Specification", {}).get("value", None) # this is a [dict]
688
943
  data_spec_name_list = attributes.get("In Data Specification", {}).get("name_list", None)
689
- data_spec_value_list = attributes.get("In Data Specification", {}).get("value", None)
944
+ data_spec_guid_list = attributes.get("In Data Specification", {}).get("guid_list", None)
690
945
 
691
- in_data_dictionary = attributes.get('In Data Dictionary', {}).get('dict_list', None)
692
- data_dict_name_list = attributes.get('In Data Dictionary', {}).get('name_list', None)
693
- data_dict_value_list = attributes.get('In Data Dictionary', {}).get('value', None)
946
+ in_data_dictionary = attributes.get('In Data Dictionary', {}).get('value', None)
947
+ in_data_dictionary_names = attributes.get('In Data Dictionary', {}).get('name_list', None)
948
+ data_dict_guid_list = attributes.get("In Data Dictionary", {}).get("guid_list", None)
694
949
 
695
950
  parent_data_field = attributes.get('Parent Data Field', {}).get('value', None)
696
- parent_data_field_guid = attributes.get('Parent Data Field', {}).get('guid', None)
951
+ parent_data_field_guids = attributes.get('Parent Data Field', {}).get('guid_list', None)
952
+ parent_data_field_names = attributes.get('Parent Data Field', {}).get('name_list', None)
697
953
 
698
954
  anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
699
955
 
700
- collection_ordering = "NAME"
701
- order_property_name = "Something"
702
- collection_type = object_type
703
- replace_all_props = True
956
+ replace_all_props = not merge_update
957
+
704
958
  if not valid:
705
959
  if exists and object_action == "Create":
706
960
  msg = (f"Create failed because Element `{display_name}` exists - changing `Create` to `Update` in "
707
- f"processed output \n")
708
- print_msg(ERROR, msg, debug_level)
961
+ f"processed output\n\n___")
962
+ logger.error(msg)
709
963
  return update_a_command(txt, object_action, object_type, qualified_name, guid)
710
964
  else:
965
+ msg = f"Invalid specification - please review\n\n___"
966
+ logger.error(msg)
711
967
  return None
712
- elif object_action == "Update" and not exists:
713
- print(f"\n{ERROR}Element `{display_name}` does not exist! Updating result document with Create "
714
- f"object_action\n")
715
- return update_a_command(txt, object_action, object_type, qualified_name, guid)
716
-
717
968
  else:
718
969
  print(Markdown(f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
719
970
 
720
971
  try:
721
972
  if object_action == "Update":
973
+ if not exists:
974
+ logger.error(f"Element `{display_name}` does not exist! Updating result document with Create "
975
+ f"object_action\n\n___")
976
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
977
+
978
+ # first update the base data field
722
979
  body = {
723
- "class": "UpdateDataStructureRequestBody",
724
- "externalSourceGUID": external_source_guid,
725
- "externalSourceName": external_source_name,
726
- "effectiveTime": effective_time,
727
- "forLineage": for_lineage,
728
- "forDuplicateProcessing": for_duplicate_processing,
729
- "properties": {
730
- "class": "DataStructureProperties",
731
- "qualifiedName": qualified_name,
732
- "displayName": display_name,
733
- "description": description,
734
- "namespace": namespace,
735
- "versionIdentifier": version_id,
736
- "additionalProperties": additional_properties,
737
- "effectiveFrom": effective_from,
980
+ "class": "UpdateElementRequestBody", "externalSourceGUID": external_source_guid,
981
+ "externalSourceName": external_source_name, "effectiveTime": effective_time,
982
+ "forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing, "properties": {
983
+ "class": "DataFieldProperties", "qualifiedName": qualified_name, "displayName": display_name,
984
+ "namespace": namespace, "description": description, "versionIdentifier": version_id,
985
+ "aliases": aliases, "namePatterns": name_patterns, "isDeprecated": False,
986
+ "isNullable": is_nullable, "defaultValue": default_value, "dataType": data_type,
987
+ "minimumLength": min_length, "length": length, "precision": precision,
988
+ "orderedValues": ordered_values, "sortOrder": sort_order,
989
+ "additionalProperties": additional_properties, "effectiveFrom": effective_from,
738
990
  "effectiveTo": effective_to
739
991
  }
740
992
  }
741
- egeria_client.update_data_structure_w_body(guid, body, replace_all_props)
742
- print_msg(ALWAYS, f"Updated element `{display_name}` with GUID {guid}", debug_level)
743
- core_props = egeria_client.get_data_structure_by_guid(guid, output_format='FORM')
744
993
 
994
+ egeria_client.update_data_field(guid, body, not merge_update)
995
+ logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}")
996
+ # Update data dictionary membership
745
997
  update_element_dictionary(qualified_name, {
746
998
  'guid': guid, 'display_name': display_name
747
999
  })
748
- update_data_collection_memberships(egeria_client, in_data_spec, guid, replace_all_props)
1000
+ core_props = egeria_client.find_data_fields(qualified_name,
1001
+ output_format='MD') ## update back to by_guid?
1002
+
1003
+ # existing_data_field = egeria_client.get_data_field_by_guid(guid, output_format='JSON')
749
1004
 
750
- return egeria_client.get_data_structure_by_guid(guid, output_format='MD')
1005
+ # Sync membership in data dictionaries
1006
+ update_data_collection_memberships(egeria_client, object_type, data_dict_guid_list, "DataDictionary",
1007
+ guid, display_name, replace_all_props)
1008
+ logger.success(f"Updating data dictionaries `{in_data_dictionary_names}`")
1009
+ core_props += f"\n\n## In Data Dictionary\n\n{in_data_dictionary_names}\n\n"
1010
+
1011
+ # Sync data field related elements (data structure, parent data fields, terms, data classes
1012
+ sync_data_field_rel_elements(egeria_client, data_structure_guid_list, parent_data_field_guids,
1013
+ glossary_term_guid, data_class_guid, guid, display_name, replace_all_props)
1014
+ core_props += f"\n\n## In Data Structure {in_data_structure_names}\n\n"
1015
+ core_props += f"\n\n## Glossary Term \n\n{glossary_term}\n\n"
1016
+ core_props += f"\n\n## Parent Data Field\n\n{parent_data_field_names}\n\n"
1017
+ core_props += f"\n\n## Data Class\n\n{data_class}\n\n"
1018
+ core_props += "\n_______________________________________________________________________________\n\n"
1019
+
1020
+ # Update data classes
1021
+ logger.success(f"Updated Element `{display_name}`\n\n___")
1022
+ return core_props
751
1023
 
752
1024
  elif object_action == "Create":
753
- if exists:
754
- print(f"\nTerm `{display_name}` already exists and result document updated\n")
1025
+ if valid is False and exists:
1026
+ logger.error(
1027
+ f"\nData Field `{display_name}` already exists and result document updated changing `Create` "
1028
+ f"to `Update` in processed output\n\n___")
755
1029
  return update_a_command(txt, object_action, object_type, qualified_name, guid)
756
1030
  else:
757
-
1031
+ # First lets create the data field
758
1032
  body = {
759
- "class": "NewDataStructureRequestBody", "externalSourceGUID": external_source_guid,
760
- "externalSourceName": external_source_name, "effectiveTime": effective_time,
761
- "forLineage": False, "forDuplicateProcessing": False, "anchorGUID": anchor_guid,
762
- "isOwnAnchor": is_own_anchor, "parentGUID": parent_guid,
763
- "parentRelationshipTypeName": parent_relationship_type_name,
764
- "parentRelationshipProperties": parent_relationship_properties, "parentAtEnd1": parent_at_end1,
765
- "properties": {
766
- "class": "DataStructureProperties", "qualifiedName": qualified_name,
767
- "displayName": display_name, "description": description, "namespace": namespace,
768
- "versionIdentifier": version_id, "additionalProperties": additional_properties,
769
- "effectiveFrom": effective_from, "effectiveTo": effective_to
1033
+ "class": "NewElementRequestBody", "properties": {
1034
+ "class": "DataFieldProperties", "qualifiedName": qualified_name,
1035
+ "displayName": display_name, "namespace": namespace, "description": description,
1036
+ "versionIdentifier": version_id, "aliases": aliases, "namePatterns": name_patterns,
1037
+ "isDeprecated": False, "isNullable": is_nullable, "defaultValue": default_value,
1038
+ "dataType": data_type, "minimumLength": min_length, "length": length,
1039
+ "precision": precision, "orderedValues": ordered_values, "sortOrder": sort_order,
1040
+ "additionalProperties": additional_properties
770
1041
  }
771
1042
  }
772
-
773
- guid = egeria_client.create_data_structure_w_body(body_slimmer(body))
1043
+ guid = egeria_client.create_data_field(body)
774
1044
  if guid:
1045
+ # Now update our element dictionary with the new information
775
1046
  update_element_dictionary(qualified_name, {
776
1047
  'guid': guid, 'display_name': display_name
777
1048
  })
1049
+ # Start assembling the information we will present back out
1050
+ core_props = egeria_client.get_data_field_by_guid(guid, None, 'MD')
778
1051
 
779
- core_props = egeria_client.get_data_structure_by_guid(guid, output_format='FORM')
780
-
1052
+ # Add the field to any data dictionaries
781
1053
  if in_data_dictionary:
782
- print_msg(ALWAYS, f"Will add to data dictionary(s) `{in_data_dictionary}`", debug_level)
783
- result = add_member_to_data_collections(egeria_client, in_data_dictionary, display_name,guid )
784
- core_props += f"\n\n## In Data Dictionary\n\n{in_data_dictionary}\n\n"
785
- # ==>> update to use new function.
786
- if in_data_spec:
787
- # member_body = {
788
- # "class": "CollectionMembershipProperties",
789
- # "membershipRationale": "Adding data structure to data specification",
790
- # "expression": None, "confidence": 100, "status": None, "userDefinedStatus": None,
791
- # "steward": None, "stewardTypeName": None, "stewardPropertyName": None, "source": None,
792
- # "notes": None,
1054
+ logger.info(f"Will add to data dictionary `{in_data_dictionary}`")
1055
+ add_member_to_data_collections(egeria_client, data_dict_guid_list, display_name, guid)
1056
+ core_props += f"\n\n## In Data Dictionary\n\n{in_data_dictionary_names}\n\n"
1057
+
1058
+ # Add the field to any data structures
1059
+ if in_data_structure:
1060
+ core_props += f"\n\n## In Data Structure\n\n{in_data_structure_names}\n\n"
1061
+ for ds_guid in data_structure_guid_list:
1062
+ # todo This is too naive? - need to better accommodate the relationship
1063
+ df_body = {
1064
+ "class": "RelationshipRequestBody", "properties": {
1065
+ "class": "MemberDataFieldProperties", "dataFieldPosition": position,
1066
+ "minCardinality": min_cardinality, "maxCardinality": max_cardinality,
1067
+ }
1068
+ }
1069
+
1070
+ msg = f"Adding field to structure {ds_guid}"
1071
+ logger.info(msg)
1072
+ egeria_client.link_member_data_field(ds_guid, guid, df_body)
1073
+ core_props += f"\n\n## In Data Structure {in_data_structure_names}\n\n"
1074
+
1075
+ if glossary_term:
1076
+ if glossary_term_guid:
1077
+ glossary_body = {
1078
+ "class": "RelationshipRequestBody", "externalSourceGUID": external_source_guid,
1079
+ "externalSourceName": external_source_name, "effectiveTime": effective_time,
1080
+ "forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing
1081
+ }
1082
+ core_props += f"\n\n## Glossary Term \n\n{glossary_term}\n\n"
1083
+ egeria_client.link_semantic_definition(guid, glossary_term_guid, glossary_body)
1084
+
1085
+ if parent_data_field_guids:
1086
+ # parent_df_body = {
1087
+ # "class": "MetadataSourceRequestBody", "externalSourceGUID": external_source_guid,
1088
+ # "externalSourceName": external_source_name, "effectiveTime": effective_time,
1089
+ # "forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing
793
1090
  # }
794
- #
795
- # if data_spec_name_list is not None:
796
- # for el in data_spec_value_list:
797
- # for key in el:
798
- # ds = el[key]
799
- # ds_qname = ds.get('known_q_name', None)
800
- # ds_guid = ds.get('known_guid', None)
801
- # if ds_guid is not None:
802
- # msg = f"Adding field to Data Specification `{ds_qname}`"
803
- # egeria_client.add_to_collection(ds_guid, guid, member_body)
804
- # print_msg(INFO, msg, debug_level)
805
- result = add_member_to_data_collections(egeria_client, in_data_spec, display_name,guid )
806
-
807
- core_props += f"\n\n## In Data Specifications\n\n`{data_spec_name_list}`\n\n"
808
-
809
- print_msg(ALWAYS, f"Created Element `{display_name}` with GUID {guid}", debug_level)
810
1091
 
1092
+ # egeria_client.link_nested_data_field(parent_data_field_guid, guid, parent_df_body)
1093
+ for parent_guid in parent_data_field_guids:
1094
+ egeria_client.link_nested_data_field(parent_guid, guid)
1095
+ core_props += f"\n\n## Parent Data Field\n\n{parent_data_field_names}\n\n"
1096
+
1097
+ # Link data class
1098
+ if data_class:
1099
+ body = {
1100
+ "class": "RelationshipRequestBody", "externalSourceGUID": external_source_guid,
1101
+ "externalSourceName": external_source_name, "effectiveTime": effective_time,
1102
+ "forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing
1103
+ }
1104
+ egeria_client.link_data_class_definition(guid, data_class_guid, body)
1105
+ msg = f"Adding data class `{data_class}` to data field {display_name}"
1106
+ logger.info(msg)
1107
+
1108
+ logger.success(f"Created Element `{display_name}` with guid `{guid}`")
1109
+ logger.success("=====================================================\n\n")
1110
+ core_props += "\n___\n\n"
811
1111
  return core_props
1112
+
812
1113
  else:
813
- print_msg(ERROR, f"Failed to create Data Structure `{display_name}`", debug_level)
1114
+ logger.error(f"Failed to create Term `{display_name}`\n\n___")
814
1115
  return None
815
1116
 
816
-
817
1117
  except Exception as e:
818
- print(f"{ERROR}Error performing {object_action}: {e}")
819
- Console().print_exception(show_locals=True)
1118
+ logger.error(f"Error performing {command}: {e}\n\n___")
820
1119
  return None
821
1120
  else:
822
1121
  return None
823
1122
 
824
1123
 
825
- # def process_data_field_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[
826
- # str]:
827
- # """
828
- # Processes a data structure create or update object_action by extracting key attributes such as
829
- # spec name, parent_guid, parent_relationship_type, parent_at_end_1, collection_type
830
- #
831
- # :param txt: A string representing the input cell to be processed for
832
- # extracting glossary-related attributes.
833
- # :param directive: an optional string indicating the directive to be used - display, validate or execute
834
- # :return: A string summarizing the outcome of the processing.
835
- # """
836
- #
837
- # from md_processing.md_processing_utils.common_md_utils import set_debug_level
838
- #
839
- # valid = True
840
- #
841
- # set_debug_level(directive)
842
- # known_q_name = None
843
- # command, object_type, object_action = extract_command_plus(txt)
1124
+ @logger.catch
1125
+ def process_data_class_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1126
+ """
1127
+ Processes a data class create or update object_action by extracting key attributes such as
1128
+ spec name, parent_guid, parent_relationship_type, parent_at_end_1, collection_type
844
1129
 
845
- # object_action = extract_command(txt)
846
- # object_type = object_action.split(' ')[1].strip()
847
- # object_action = object_action.split(' ')[0].strip()
1130
+ :param txt: A string representing the input cell to be processed for
1131
+ extracting glossary-related attributes.
1132
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
1133
+ :return: A string summarizing the outcome of the processing.
1134
+ """
848
1135
 
849
- # parsed_output = parse_user_command(egeria_client, object_type, object_action, txt)
1136
+ command, object_type, object_action = extract_command_plus(txt)
1137
+ print(Markdown(f"# {command}\n"))
850
1138
 
1139
+ parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
851
1140
 
852
- # valid = True
853
- #
854
- # set_debug_level(directive)
855
- # known_q_name = None
856
- # object_action = extract_command(txt)
857
- # object_type = object_action.split(' ')[1].strip()
858
- # object_action = object_action.split(' ')[0].strip()
859
- #
860
- # display_name_label = ['Data Structure Name', 'Display Name', 'Name']
861
- #
862
- # display_name = process_simple_attribute(txt, display_name_label, ERROR)
863
- # print(Markdown(f"{pre_command} `{object_action}` for term:`{display_name}` with directive: `{directive}`"))
864
- #
865
- # description = process_simple_attribute(txt, ['Description'], INFO)
866
- # data_type = process_simple_attribute(txt, ['Data Type', "Type"], WARNING)
867
- # positoion = process_simple_attribute(txt, ['Position'], INFO)
868
- # min_cardinalityc = process_simple_attribute(txt, ['Minimum Cardinality', 'Min Cardinality'], WARNING)
869
- # max_cardinality= process_simple_attribute(txt, ['Maximum Cardinality', 'Max Cardinality'], INFO)
870
- # in_data_structure = process_simple_attribute(txt, ['In Data Structure', 'In Data Struct'], INFO)
871
- # data_class = process_simple_attribute(txt, ['Data Class','DataClass'], INFO)
872
- # glossary_term = process_simple_attribute(txt, GLOSSARY_NAME_LABELS, INFO)
873
- # namesspace= process_simple_attribute(txt, ['Namespace'], INFO)
874
- # version_id = process_simple_attribute(txt, ['Version','Version Id', 'Version Identifier'], INFO)
875
- # in_data_dict = process_simple_attribute(txt, ['In Data Dict', 'Data Dictionary', 'In Data Dictionary'], INFO)
876
- #
877
- # q_name = process_simple_attribute(txt, ['Qualified Name'], INFO)
878
- #
879
- # # validate display name and get existing qualified_name and guid if they exist
880
- # if display_name is None:
881
- # valid = False
882
- # known_q_name, known_guid, exists = None, None, False
883
- # else:
884
- # known_q_name, known_guid, valid, exists = process_element_identifiers(egeria_client, object_type,
885
- # display_name_label, txt, object_action,
886
- # None)
887
- #
888
- # if object_action == "Update": # check to see if provided information exists and is consistent with existing info
889
- # guid = process_simple_attribute(txt, GUID_LABELS)
890
- #
891
- # display = (f"\n* Command: {object_action}\n\t"
892
- # f"* Name: {display_name}\n\t* Description: {description}\n\t"
893
- # f"* Qualified Name: {q_name}\n\t* GUID: {guid}"
894
- # )
895
- #
896
- # if not exists:
897
- # msg = f"Update request invalid, Term {display_name} does not exist\n"
898
- # print_msg(ERROR, msg, debug_level)
899
- # valid = False
900
- #
901
- # elif object_action == 'Create': # if the object_action is create, check that it doesn't already exist
902
- # display = (f"\n* Command: {object_action}\n\t* Glossary: {known_q_name}\n\t"
903
- # f"* Name: {display_name}\n\t* Description: {description}\n\t"
904
- # f"* Qualified Name: {q_name}\n\t"
905
- # )
906
- # if exists:
907
- # msg = f"Element `{display_name}` cannot be created since it already exists\n"
908
- # print_msg(ERROR, msg, debug_level)
909
- # else:
910
- # msg = f"It is valid to create Element `{display_name}`"
911
- # print_msg(ALWAYS, msg, debug_level)
912
-
913
- # if directive == "display":
914
- # print(Markdown(display))
915
- # return None
916
- # elif directive == "validate":
917
- # if valid:
918
- # print(Markdown(display))
919
- # else:
920
- # msg = f"Validation failed for Term `{display_name}`\n"
921
- # print_msg(ERROR, msg, debug_level)
922
- # print(Markdown(display))
923
- # return valid
924
- #
925
- # elif directive == "process":
926
- # if valid:
927
- # print(Markdown(display))
928
- # else:
929
- # if exists and object_action == "Create":
930
- # msg = f"Create failed because Element `{display_name}` exists - changing `Create` to `Update` in
931
- # processed output \n"
932
- # print_msg(ERROR, msg, debug_level)
933
- # print(Markdown(display))
934
- # return update_a_command(txt, object_action, object_type, known_q_name, known_guid)
935
- # else:
936
- # return None
937
- #
938
- # try:
939
- # if object_action == "Update":
940
- # if not exists:
941
- # print(f"\n{ERROR}Element `{display_name}` does not exist! Updating result document with Create "
942
- # f"object_action\n")
943
- # return update_a_command(txt, object_action, object_type, known_q_name, known_guid)
944
- #
945
- # egeria_client.update_term(known_guid, body)
946
- # print_msg(ALWAYS, f"Updated Term `{term_name}` with GUID {known_guid}", debug_level)
947
- # update_element_dictionary(known_q_name, {
948
- # 'guid': known_guid, 'display_name': term_name
949
- # })
950
- #
951
- # return egeria_client.get_term_by_guid(known_guid, output_format='MD')
952
- #
953
- # elif object_action == "Create":
954
- # if exists:
955
- # print(f"\nTerm `{display_name}` already exists and result document updated\n")
956
- # return update_a_command(txt, object_action, object_type, known_q_name, known_guid)
957
- # else:
958
- # guid = egeria_client.create_data_spec_collection(None, None, None,
959
- # True, display_name, description,
960
- # collection_type, None,
961
- # True, None)
962
- # if guid:
963
- # print_msg(ALWAYS, f"Created Element `{display_name}` with GUID {guid}", debug_level)
964
- # # Add categories if specified
965
- #
966
- # return egeria_client.get_collection_by_guid(guid, output_format='FORM')
967
- # else:
968
- # print_msg(ERROR, f"Failed to create Term `{display_name}`", debug_level)
969
- # return None
970
- #
971
- # except Exception as e:
972
- # print(f"{ERROR}Error performing {object_action}: {e}")
973
- # Console().print_exception(show_locals=True)
974
- # return None
975
- # else:
976
- # return None
977
- #
978
- #
979
- def process_data_dict_list_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1141
+ attributes = parsed_output['attributes']
1142
+ display_name = attributes['Display Name'].get('value', None)
1143
+ qualified_name = parsed_output.get('qualified_name', None)
1144
+ guid = parsed_output.get('guid', None)
1145
+ valid = parsed_output['valid']
1146
+ exists = parsed_output['exists']
1147
+
1148
+ print(Markdown(parsed_output['display']))
1149
+
1150
+ if directive == "display":
1151
+
1152
+ return None
1153
+ elif directive == "validate":
1154
+ if valid:
1155
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
1156
+ else:
1157
+ msg = f"Validation failed for object_action `{command}`\n"
1158
+ logger.error(msg)
1159
+ return valid
1160
+
1161
+ elif directive == "process":
1162
+ logger.debug(json.dumps(parsed_output, indent=4))
1163
+
1164
+ external_source_guid = attributes.get('External Source Name', {}).get('guid', None)
1165
+ external_source_name = attributes.get('External Source Name', {}).get('value', None)
1166
+ effective_time = attributes.get('Effective Time', {}).get('value', None)
1167
+ for_lineage = attributes.get('For Lineage', {}).get('value', False)
1168
+ for_duplicate_processing = attributes.get('For Duplicate Processing', {}).get('value', False)
1169
+ anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
1170
+ is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', None)
1171
+ # parent_id = attributes.get('Parent ID', {}).get('value', None)
1172
+ # parent_guid = attributes['Parent ID'].get('guid', None)
1173
+ # parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value', None)
1174
+ # parent_relationship_properties = attributes.get('Parent Relationship Properties',{}).get('value', None)
1175
+ # parent_at_end1 = attributes.get('Parent at End1', {}).get('value', None)
1176
+
1177
+ namespace = attributes.get('Namespace', {}).get('value', None)
1178
+ description = attributes.get('Description', {}).get('value', None)
1179
+ version_id = attributes.get('Version Identifier', {}).get('value', None)
1180
+
1181
+ ###############
1182
+ match_property_names = attributes.get('Match Property Names', {}).get('value', [])
1183
+ specification_details = attributes.get('Specification Details', {}).get('value', {})
1184
+ match_threshold = attributes.get('Match Threshold', {}).get('value', 0)
1185
+ specification = attributes.get('Specification', {}).get('value', None)
1186
+ data_type = attributes.get('Data Type', {}).get('value', None)
1187
+ is_nullable = attributes.get('Is Nullable', {}).get('value', True)
1188
+ allow_duplicates = attributes.get('Allow Duplicates', {}).get('value', True)
1189
+ default_value = attributes.get('Default Value', {}).get('value', None)
1190
+ average_value = attributes.get('Average Value', {}).get('value', None)
1191
+ value_list = attributes.get('Value List', {}).get('value', None)
1192
+ value_range_from = attributes.get('Value Range From', {}).get('value', None)
1193
+ value_range_to = attributes.get('Value Range To', {}).get('value', None)
1194
+ sample_values = attributes.get('Sample Values', {}).get('value', [])
1195
+ data_patterns = attributes.get('Data Patterns', {}).get('value', [])
1196
+ additional_properties = attributes.get('Additional Properties', {}).get('value', {})
1197
+
1198
+ ###############
1199
+ aliases = attributes.get('Aliases', {}).get('value', None)
1200
+ name_patterns = attributes.get('Name Patterns', {}).get('value', None)
1201
+
1202
+ min_length = attributes.get('Minimum Length', {}).get('value', None)
1203
+ length = attributes.get('Length', {}).get('value', None)
1204
+ precision = attributes.get('Precision', {}).get('value', None)
1205
+ ordered_values = attributes.get('Ordered Values', {}).get('value', None)
1206
+ sort_order = attributes.get('Sort Order', {}).get('value', None)
1207
+ effective_from = attributes.get('Effective From', {}).get('value', None)
1208
+ effective_to = attributes.get('Effective To', {}).get('value', None)
1209
+
1210
+ glossary_term = attributes.get('Glossary Term', {}).get('value', None)
1211
+ glossary_term_guid = attributes.get('Glossary Term', {}).get('guid', None)
1212
+
1213
+ merge_update = attributes.get('Merge Update', {}).get('value', True)
1214
+
1215
+ position = attributes.get('Position', {}).get('value', None)
1216
+ min_cardinality = attributes.get('Minimum Cardinality', {}).get('value', None)
1217
+ max_cardinality = attributes.get('Maximum Cardinality', {}).get('value', None)
1218
+
1219
+ in_data_structure = attributes.get('In Data Structure', {}).get('value', None)
1220
+ data_structure_guid_list = attributes.get('In Data Structure', {}).get('guid_list', None)
1221
+ in_data_structure_names = attributes.get('In Data Structure Names', {}).get('name_list', None)
1222
+
1223
+ data_class = attributes.get('Data Class', {}).get('value', None)
1224
+ glossary_term = attributes.get('Glossary Term', {}).get('value', None)
1225
+
1226
+ glossary_term_guid = attributes.get('Glossary Term', {}).get('guid', None)
1227
+
1228
+ in_data_dictionary = attributes.get('In Data Dictionary', {}).get('value', None)
1229
+ in_data_dictionary_names = attributes.get('In Data Dictionary', {}).get('name_list', None)
1230
+ data_dict_guid_list = attributes.get("In Data Dictionary", {}).get("guid_list", None)
1231
+
1232
+ containing_data_class = attributes.get('Containing Data Class', {}).get('value', None)
1233
+ containing_data_class_guids = attributes.get('Containing Data Class', {}).get('guid_list', None)
1234
+ containing_data_class_names = attributes.get('Containing Data Class', {}).get('name_list', None)
1235
+
1236
+ specializes_data_class = attributes.get('Specializes Data Class', {}).get('value', None)
1237
+ specializes_data_class_guid = attributes.get('Specializes Data Class', {}).get('guid', None)
1238
+ specializes_data_class_name = attributes.get('Specializes Data Class', {}).get('name', None)
1239
+
1240
+ anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
1241
+
1242
+ replace_all_props = not merge_update
1243
+
1244
+ if not valid:
1245
+ if exists and object_action == "Create":
1246
+ msg = (f"Create failed because Element `{display_name}` exists - changing `Create` to `Update` in "
1247
+ f"processed output\n\n___")
1248
+ logger.error(msg)
1249
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
1250
+ else:
1251
+ msg = f"Invalid specification - please review\n\n___"
1252
+ return None
1253
+ else:
1254
+ print(Markdown(f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
1255
+
1256
+ try:
1257
+ if object_action == "Update":
1258
+ if not exists:
1259
+ logger.error(f"Element `{display_name}` does not exist! Updating result document with Create "
1260
+ f"object_action\n\n___")
1261
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
1262
+
1263
+ # first update the base data class
1264
+ body = {
1265
+ "class": "UpdateElementRequestBody", "externalSourceGUID": external_source_guid,
1266
+ "externalSourceName": external_source_name, "effectiveTime": effective_time,
1267
+ "forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing, "properties": {
1268
+ "class": "DataClassProperties", "qualifiedName": qualified_name, "displayName": display_name,
1269
+ "description": description, "namespace": namespace, "matchPropertyNames": match_property_names,
1270
+ "matchThreshold": match_threshold, "specification": specification,
1271
+ "specificationDetails": specification_details, "dataType": data_type,
1272
+ "allowsDuplicateValues": allow_duplicates, "isNullable": is_nullable,
1273
+ "defaultValue": default_value, "averageValue": average_value, "valueList": value_list,
1274
+ "valueRangeFrom": value_range_from, "valueRangeTo": value_range_to,
1275
+ "sampleValues": sample_values, "dataPatterns": data_patterns,
1276
+ "additionalProperties": additional_properties
1277
+ }
1278
+ }
1279
+
1280
+ egeria_client.update_data_class(guid, body, not merge_update)
1281
+ logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}")
1282
+ # Update data dictionary membership
1283
+ update_element_dictionary(qualified_name, {
1284
+ 'guid': guid, 'display_name': display_name
1285
+ })
1286
+ core_props = egeria_client.get_data_class_by_guid(guid, None, 'MD')
1287
+
1288
+ # Sync membership in data dictionaries
1289
+ update_data_collection_memberships(egeria_client, object_type, data_dict_guid_list, "DataDictionary",
1290
+ guid, display_name, replace_all_props)
1291
+ logger.success(f"Updating data dictionaries `{in_data_dictionary_names}`")
1292
+ core_props += f"\n\n## In Data Dictionary\n\n{in_data_dictionary_names}\n\n"
1293
+
1294
+ # Sync data field related elements (data structure, parent data fields, terms, data classes
1295
+ sync_data_class_rel_elements(egeria_client, containing_data_class_guids, glossary_term_guid,
1296
+ specializes_data_class_guid, guid, display_name, replace_all_props)
1297
+
1298
+ core_props += f"\n\n## Glossary Term \n\n{glossary_term}\n\n"
1299
+ core_props += f"\n\n## Containing Data Class\n\n{containing_data_class_names}\n\n"
1300
+ core_props += "\n___\n\n"
1301
+
1302
+ # Update data classes
1303
+ logger.success(f"Updated Element `{display_name}`\n\n___")
1304
+ return core_props
1305
+
1306
+ elif object_action == "Create":
1307
+ if valid is False and exists:
1308
+ logger.error(
1309
+ f"\nData Class `{display_name}` already exists and result document updated changing `Create` "
1310
+ f"to `Update` in processed output\n\n___")
1311
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
1312
+ else:
1313
+ # First lets create the data class
1314
+ body = {
1315
+ "class": "NewElementRequestBody", "properties": {
1316
+ "class": "DataClassProperties", "qualifiedName": qualified_name,
1317
+ "displayName": display_name, "description": description, "namespace": namespace,
1318
+ "matchPropertyNames": match_property_names, "matchThreshold": match_threshold,
1319
+ "specification": specification, "specificationDetails": specification_details,
1320
+ "dataType": data_type, "allowsDuplicateValues": allow_duplicates, "isNullable": is_nullable,
1321
+ "defaultValue": default_value, "averageValue": average_value, "valueList": value_list,
1322
+ "valueRangeFrom": value_range_from, "valueRangeTo": value_range_to,
1323
+ "sampleValues": sample_values, "dataPatterns": data_patterns,
1324
+ "additionalProperties": additional_properties
1325
+ }
1326
+ }
1327
+ guid = egeria_client.create_data_class(body)
1328
+ if guid:
1329
+ # Now update our element dictionary with the new information
1330
+ update_element_dictionary(qualified_name, {
1331
+ 'guid': guid, 'display_name': display_name
1332
+ })
1333
+ # Start assembling the information we will present back out
1334
+ core_props = egeria_client.get_data_class_by_guid(guid, None, 'MD')
1335
+
1336
+ # Add the field to any data dictionaries
1337
+ if in_data_dictionary:
1338
+ logger.info(f"Will add to data dictionary `{in_data_dictionary}`")
1339
+ add_member_to_data_collections(egeria_client, data_dict_guid_list, display_name, guid)
1340
+ core_props += f"\n\n## In Data Dictionary\n\n{in_data_dictionary_names}\n\n"
1341
+
1342
+ if glossary_term:
1343
+ if glossary_term_guid:
1344
+ glossary_body = {
1345
+ "class": "RelationshipRequestBody", "externalSourceGUID": external_source_guid,
1346
+ "externalSourceName": external_source_name, "effectiveTime": effective_time,
1347
+ "forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing
1348
+ }
1349
+
1350
+ core_props += f"\n\n## Glossary Term \n\n{glossary_term}\n\n"
1351
+ egeria_client.link_semantic_definition(guid, glossary_term_guid, glossary_body)
1352
+
1353
+ if containing_data_class_guids:
1354
+ for dc_guid in containing_data_class_guids:
1355
+ egeria_client.link_nested_data_class(dc_guid, guid)
1356
+ core_props += f"\n\n## Parent Data Field\n\n{containing_data_class_names}\n\n"
1357
+
1358
+ if specializes_data_class_guid:
1359
+ egeria_client.link_specialist_data_class(specializes_data_class_guid, guid)
1360
+ core_props += f"\n\n## Specialized Data Field\n\n{specializes_data_class_name}\n\n"
1361
+
1362
+ logger.success(f"Created Element `{display_name}`")
1363
+ core_props += "\n___\n\n"
1364
+ return core_props
1365
+
1366
+ else:
1367
+ logger.error(f"Failed to create Term `{display_name}`\n\n___")
1368
+ return None
1369
+
1370
+ except Exception as e:
1371
+ logger.error(f"Error performing {command}: {e}\n\n___")
1372
+ return None
1373
+ else:
1374
+ return None
1375
+
1376
+
1377
+ @logger.catch
1378
+ def process_data_collection_list_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[
1379
+ str]:
980
1380
  """
981
1381
  Processes a Data Dictionary list object_action by extracting key attributes such as
982
1382
  search string from the given text.
@@ -986,197 +1386,279 @@ def process_data_dict_list_command(egeria_client: EgeriaTech, txt: str, directiv
986
1386
  :param directive: an optional string indicating the directive to be used - display, validate or execute
987
1387
  :return: A string summarizing the outcome of the processing.
988
1388
  """
989
- from md_processing.md_processing_utils.common_md_utils import set_debug_level
1389
+ command, object_type, object_action = extract_command_plus(txt)
1390
+ print(Markdown(f"# {command}\n"))
1391
+ if object_type in ["Data Dictionary", "Data Dictionaries", "DataDict", "DataDictionary"]:
1392
+ col_type = "DataDictionary"
1393
+ elif object_type in ["Data Specification", "Data Specifications", "Data Specs"]:
1394
+ col_type = "DataSpec"
1395
+ else:
1396
+ col_type = "Collection"
990
1397
 
991
- set_debug_level(directive)
992
- known_q_name = None
1398
+ parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
1399
+
1400
+
1401
+
1402
+ valid = parsed_output['valid']
1403
+ print(Markdown(f"Performing {command}"))
1404
+ print(Markdown(parsed_output['display']))
1405
+
1406
+ attr = parsed_output.get('attributes',{})
1407
+ effective_time = attr.get('effectiveTime', {}).get('value', None)
1408
+ as_of_time = attr.get('asOfTime', {}).get('value', None)
1409
+ for_duplicate_processing = attr.get('forDuplicateProcessing', {}).get('value', False)
1410
+ for_lineage = attr.get('forLineage',{}).get('value', False)
1411
+ limit_result_by_status = attr.get('limitResultsByStatus',{}).get('value', ['ACTIVE'])
1412
+ sequencing_property = attr.get('sequencingProperty',{}).get('value',"qualifiedName" )
1413
+ sequencing_order = attr.get('sequencingOrder',{}).get('value', "PROPERTY_ASCENDING")
1414
+ search_string = attr.get('Search String', {}).get('value', '*')
1415
+ output_format = attr.get('Output Format', {}).get('value', 'LIST')
1416
+ detailed = attr.get('Detailed', {}).get('value', False)
1417
+
1418
+ if directive == "display":
1419
+ return None
1420
+ elif directive == "validate":
1421
+ if valid:
1422
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
1423
+ else:
1424
+ msg = f"Validation failed for object_action `{command}`\n"
1425
+ logger.error(msg)
1426
+ return valid
1427
+
1428
+ elif directive == "process":
1429
+ try:
1430
+ if not valid: # First validate the command before we process it
1431
+ msg = f"Validation failed for {object_action} `{object_type}`\n"
1432
+ logger.error(msg)
1433
+ return None
1434
+
1435
+ list_md = f"\n# `{col_type}` with filter: `{search_string}`\n\n"
1436
+ body = {
1437
+ "class": "FilterRequestBody",
1438
+ "asOfTime": as_of_time,
1439
+ "effectiveTime": effective_time,
1440
+ "forLineage": for_lineage,
1441
+ "forDuplicateProcessing": for_duplicate_processing,
1442
+ "limitResultsByStatus": limit_result_by_status,
1443
+ "sequencingOrder": sequencing_order,
1444
+ "sequencingProperty": sequencing_property,
1445
+ "filter": search_string,
1446
+ }
1447
+
1448
+ struct = egeria_client.find_collections_w_body(body, col_type, output_format=output_format)
1449
+ if output_format == "DICT":
1450
+ list_md += f"```\n{json.dumps(struct, indent=4)}\n```\n"
1451
+ else:
1452
+ list_md += struct
1453
+ logger.info(f"Wrote `{col_type}` for search string: `{search_string}`")
1454
+
1455
+ return list_md
1456
+
1457
+ except Exception as e:
1458
+ logger.error(f"Error performing {command}: {e}")
1459
+ console.print_exception(show_locals=True)
1460
+ return None
1461
+ else:
1462
+ return None
1463
+
1464
+
1465
+ def process_data_structure_list_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[
1466
+ str]:
1467
+ """
1468
+ Processes a Data Dictionary list object_action by extracting key attributes such as
1469
+ search string from the given text.
1470
+
1471
+ :param txt: A string representing the input cell to be processed for
1472
+ extracting term-related attributes.
1473
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
1474
+ :return: A string summarizing the outcome of the processing.
1475
+ """
993
1476
  command, object_type, object_action = extract_command_plus(txt)
1477
+ print(Markdown(f"# {command}\n"))
994
1478
 
995
- object_action = extract_command(txt)
996
- set_debug_level(directive)
1479
+ parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
997
1480
 
998
- parsed_output = parse_user_command(egeria_client, object_action, 'View', txt)
1481
+ attributes = parsed_output['attributes']
1482
+
1483
+ valid = parsed_output['valid']
1484
+ print(Markdown(f"Performing {command}"))
999
1485
  print(Markdown(parsed_output['display']))
1486
+
1487
+ if directive == "display":
1488
+ return None
1489
+ elif directive == "validate":
1490
+ if valid:
1491
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
1492
+ else:
1493
+ msg = f"Validation failed for object_action `{command}`\n"
1494
+ logger.error(msg)
1495
+ return valid
1496
+
1497
+ elif directive == "process":
1498
+ attributes = parsed_output['attributes']
1499
+ search_string = attributes.get('Search String', {}).get('value', '*')
1500
+ output_format = attributes.get('Output Format', {}).get('value', 'LIST')
1501
+ detailed = attributes.get('Detailed', {}).get('value', False)
1502
+
1503
+ try:
1504
+ if not valid: # First validate the command before we process it
1505
+ msg = f"Validation failed for {object_action} `{object_type}`\n"
1506
+ logger.error(msg)
1507
+ return None
1508
+
1509
+ list_md = f"\n# `{object_type}` with filter: `{search_string}`\n\n"
1510
+ struct = egeria_client.find_data_structures(search_string, output_format=output_format)
1511
+
1512
+ if output_format == "DICT":
1513
+ list_md += f"```\n{json.dumps(struct, indent=4)}\n```\n"
1514
+ else:
1515
+ list_md += struct
1516
+ logger.info(f"Wrote `{object_type}` for search string: `{search_string}`")
1517
+
1518
+ return list_md
1519
+
1520
+ except Exception as e:
1521
+ logger.error(f"Error performing {command}: {e}")
1522
+ console.print_exception(show_locals=True)
1523
+ return None
1524
+ else:
1525
+ return None
1526
+
1527
+
1528
+ def process_data_field_list_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1529
+ """
1530
+ Processes a Data Dictionary list object_action by extracting key attributes such as
1531
+ search string from the given text.
1532
+
1533
+ :param txt: A string representing the input cell to be processed for
1534
+ extracting term-related attributes.
1535
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
1536
+ :return: A string summarizing the outcome of the processing.
1537
+ """
1538
+ command, object_type, object_action = extract_command_plus(txt)
1539
+ print(Markdown(f"# {command}\n"))
1540
+
1541
+ parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
1542
+
1543
+ attributes = parsed_output['attributes']
1544
+
1000
1545
  valid = parsed_output['valid']
1546
+ print(Markdown(f"Performing {command}"))
1547
+ print(Markdown(parsed_output['display']))
1001
1548
 
1002
1549
  if directive == "display":
1003
1550
  return None
1004
1551
  elif directive == "validate":
1005
1552
  if valid:
1006
- msg = f"Validation passed for {object_action} `{object_type}`\n"
1553
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
1007
1554
  else:
1008
- msg = f"Validation failed for {object_action} `{object_type}`\n"
1009
- print_msg(ERROR, msg, debug_level)
1555
+ msg = f"Validation failed for object_action `{command}`\n"
1556
+ logger.error(msg)
1010
1557
  return valid
1558
+
1011
1559
  elif directive == "process":
1012
1560
  attributes = parsed_output['attributes']
1013
1561
  search_string = attributes.get('Search String', {}).get('value', '*')
1014
1562
  output_format = attributes.get('Output Format', {}).get('value', 'LIST')
1015
1563
  detailed = attributes.get('Detailed', {}).get('value', False)
1564
+ as_of_time = attributes.get('AsOfTime', {}).get('value', None)
1565
+ effective_time = attributes.get('Effective Time', {}).get('value', None)
1566
+ sort_order = attributes.get('Sort Order', {}).get('value', None)
1567
+ order_property = attributes.get('Order Property', {}).get('value', None)
1568
+ starts_with = attributes.get('Start With', {}).get('value', True)
1569
+ ends_with = attributes.get('End With', {}).get('value', False)
1570
+ ignore_case = attributes.get('Ignore Case', {}).get('value', False)
1571
+ start_from = attributes.get('Start From', {}).get('value', 0)
1572
+ page_size = attributes.get('Page Size', {}).get('value', None)
1016
1573
 
1017
1574
  try:
1018
1575
  if not valid: # First validate the command before we process it
1019
1576
  msg = f"Validation failed for {object_action} `{object_type}`\n"
1020
- print_msg(ERROR, msg, debug_level)
1577
+ logger.error(msg)
1021
1578
  return None
1022
1579
 
1023
- list_md = f"\n# Data Dictionaries with filter: `{search_string}`\n\n"
1580
+ list_md = f"\n# `{object_type}` with filter: `{search_string}`\n\n"
1581
+ body = {
1582
+ "class": "FilterRequestBody", "asOfTime": as_of_time, "effectiveTime": effective_time,
1583
+ "forLineage": False, "forDuplicateProcessing": False, "limitResultsByStatus": ["ACTIVE"],
1584
+ "sequencingOrder": sort_order, "sequencingProperty": order_property, "filter": search_string,
1585
+ }
1586
+ struct = egeria_client.find_data_fields_w_body(body, start_from, page_size, starts_with, ends_with,
1587
+ ignore_case, output_format)
1588
+
1024
1589
  if output_format == "DICT":
1025
- struct = egeria_client.get_classified_collections('DataDictionary', output_format=output_format)
1026
- list_md += f"```{json.dumps(struct, indent=4)}```\n"
1590
+ list_md += f"```\n{json.dumps(struct, indent=4)}\n```\n"
1027
1591
  else:
1028
- list_md += egeria_client.find_collections(search_string, output_format=output_format)
1029
- print_msg("ALWAYS", f"Wrote Dictionaries for search string: `{search_string}`", debug_level)
1592
+ list_md += struct
1593
+ logger.info(f"Wrote `{object_type}` for search string: `{search_string}`")
1030
1594
 
1031
1595
  return list_md
1032
1596
 
1033
1597
  except Exception as e:
1034
- print(f"{ERROR}Error performing {command}: {e}")
1598
+ logger.error(f"Error performing {command}: {e}")
1035
1599
  console.print_exception(show_locals=True)
1036
1600
  return None
1037
1601
  else:
1038
1602
  return None
1039
1603
 
1040
- # def process_term_details_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1041
- # """
1042
- # Processes a term details object_action by extracting key attributes such as
1043
- # term name and output format from the given text.
1044
- #
1045
- # :param txt: A string representing the input cell to be processed for
1046
- # extracting term-related attributes.
1047
- # :param directive: an optional string indicating the directive to be used - display, validate or execute
1048
- # :return: A string summarizing the outcome of the processing.
1049
- # """
1050
- # from md_processing.md_processing_utils.common_md_utils import set_debug_level
1051
- #
1052
- # object_action = extract_command(txt)
1053
- # set_debug_level(directive)
1054
- # print(Markdown(f"{pre_command} `{object_action}` with directive: `{directive}`"))
1055
- #
1056
- # term_name = process_simple_attribute(txt, TERM_NAME_LABELS, ERROR)
1057
- # output_format = process_simple_attribute(txt, OUTPUT_LABELS)
1058
- # output_format = output_format.upper() if output_format else "MD"
1059
- # if output_format not in ELEMENT_OUTPUT_FORMATS:
1060
- # print_msg(WARNING, f"Output format {output_format} not recognized, using MD", debug_level)
1061
- # output_format = "MD"
1062
- #
1063
- # if term_name is None:
1064
- # print_msg(ERROR, "No term name found", debug_level)
1065
- # return None
1066
- #
1067
- # known_q_name, known_guid, valid, term_exists = process_element_identifiers(egeria_client, "Term",
1068
- # TERM_NAME_LABELS, txt,
1069
- # EXISTS_REQUIRED, None)
1070
- # if not term_exists:
1071
- # print_msg(ERROR, f"Term {term_name} not found", debug_level)
1072
- # return None
1073
- #
1074
- # if directive == "display":
1075
- # print(Markdown(f"\n* Command: {object_action}\n\t* Term Name: {term_name}\n\t* Output Format: {
1076
- # output_format}"))
1077
- # return None
1078
- # elif directive == "validate":
1079
- # print(Markdown(f"\n* Command: {object_action}\n\t* Term Name: {term_name}\n\t* Output Format: {
1080
- # output_format}"))
1081
- # return True
1082
- # elif directive == "process":
1083
- # print(Markdown(f"\n* Command: {object_action}\n\t* Term Name: {term_name}\n\t* Output Format: {
1084
- # output_format}"))
1085
- # return egeria_client.get_term_by_guid(known_guid, output_format=output_format)
1086
- #
1087
- #
1088
- # def process_term_history_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1089
- # """
1090
- # Processes a term history object_action by extracting key attributes such as
1091
- # term name and output format from the given text.
1092
- #
1093
- # :param txt: A string representing the input cell to be processed for
1094
- # extracting term-related attributes.
1095
- # :param directive: an optional string indicating the directive to be used - display, validate or execute
1096
- # :return: A string summarizing the outcome of the processing.
1097
- # """
1098
- # from md_processing.md_processing_utils.common_md_utils import set_debug_level
1099
- #
1100
- # object_action = extract_command(txt)
1101
- # set_debug_level(directive)
1102
- # print(Markdown(f"{pre_command} `{object_action}` with directive: `{directive}`"))
1103
- #
1104
- # term_name = process_simple_attribute(txt, TERM_NAME_LABELS, ERROR)
1105
- # output_format = process_simple_attribute(txt, OUTPUT_LABELS)
1106
- # output_format = output_format.upper() if output_format else "MD"
1107
- # if output_format not in ELEMENT_OUTPUT_FORMATS:
1108
- # print_msg(WARNING, f"Output format {output_format} not recognized, using MD", debug_level)
1109
- # output_format = "MD"
1110
- #
1111
- # if term_name is None:
1112
- # print_msg(ERROR, "No term name found", debug_level)
1113
- # return None
1114
- #
1115
- # known_q_name, known_guid, valid, term_exists = process_element_identifiers(egeria_client, "Term",
1116
- # TERM_NAME_LABELS, txt,
1117
- # EXISTS_REQUIRED, None)
1118
- # if not term_exists:
1119
- # print_msg(ERROR, f"Term {term_name} not found", debug_level)
1120
- # return None
1121
- #
1122
- # if directive == "display":
1123
- # print(Markdown(f"\n* Command: {object_action}\n\t* Term Name: {term_name}\n\t* Output Format: {
1124
- # output_format}"))
1125
- # return None
1126
- # elif directive == "validate":
1127
- # print(Markdown(f"\n* Command: {object_action}\n\t* Term Name: {term_name}\n\t* Output Format: {
1128
- # output_format}"))
1129
- # return True
1130
- # elif directive == "process":
1131
- # print(Markdown(f"\n* Command: {object_action}\n\t* Term Name: {term_name}\n\t* Output Format: {
1132
- # output_format}"))
1133
- # return egeria_client.get_term_history(known_guid, output_format=output_format)
1134
- #
1135
- #
1136
- # def process_term_revision_history_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") ->
1137
- # Optional[str]:
1138
- # """
1139
- # Processes a term revision history object_action by extracting key attributes such as
1140
- # term name and output format from the given text.
1141
- #
1142
- # :param txt: A string representing the input cell to be processed for
1143
- # extracting term-related attributes.
1144
- # :param directive: an optional string indicating the directive to be used - display, validate or execute
1145
- # :return: A string summarizing the outcome of the processing.
1146
- # """
1147
- # from md_processing.md_processing_utils.common_md_utils import set_debug_level
1148
- #
1149
- # object_action = extract_command(txt)
1150
- # set_debug_level(directive)
1151
- # print(Markdown(f"{pre_command} `{object_action}` with directive: `{directive}`"))
1152
- #
1153
- # term_name = process_simple_attribute(txt, TERM_NAME_LABELS, ERROR)
1154
- # output_format = process_simple_attribute(txt, OUTPUT_LABELS)
1155
- # output_format = output_format.upper() if output_format else "MD"
1156
- # if output_format not in ELEMENT_OUTPUT_FORMATS:
1157
- # print_msg(WARNING, f"Output format {output_format} not recognized, using MD", debug_level)
1158
- # output_format = "MD"
1159
- #
1160
- # if term_name is None:
1161
- # print_msg(ERROR, "No term name found", debug_level)
1162
- # return None
1163
- #
1164
- # known_q_name, known_guid, valid, term_exists = process_element_identifiers(egeria_client, "Term",
1165
- # TERM_NAME_LABELS, txt,
1166
- # EXISTS_REQUIRED, None)
1167
- # if not term_exists:
1168
- # print_msg(ERROR, f"Term {term_name} not found", debug_level)
1169
- # return None
1170
- #
1171
- # if directive == "display":
1172
- # print(Markdown(f"\n* Command: {object_action}\n\t* Term Name: {term_name}\n\t* Output Format: {
1173
- # output_format}"))
1174
- # return None
1175
- # elif directive == "validate":
1176
- # print(Markdown(f"\n* Command: {object_action}\n\t* Term Name: {term_name}\n\t* Output Format: {
1177
- # output_format}"))
1178
- # return True
1179
- # elif directive == "process":
1180
- # print(Markdown(f"\n* Command: {object_action}\n\t* Term Name: {term_name}\n\t* Output Format: {
1181
- # output_format}"))
1182
- # return egeria_client.get_term_revision_history(known_guid, output_format=output_format)
1604
+
1605
+ def process_data_class_list_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1606
+ """
1607
+ Processes a Data Dictionary list object_action by extracting key attributes such as
1608
+ search string from the given text.
1609
+
1610
+ :param txt: A string representing the input cell to be processed for
1611
+ extracting term-related attributes.
1612
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
1613
+ :return: A string summarizing the outcome of the processing.
1614
+ """
1615
+ command, object_type, object_action = extract_command_plus(txt)
1616
+ print(Markdown(f"# {command}\n"))
1617
+
1618
+ parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
1619
+
1620
+ attributes = parsed_output['attributes']
1621
+
1622
+ valid = parsed_output['valid']
1623
+ print(Markdown(f"Performing {command}"))
1624
+ print(Markdown(parsed_output['display']))
1625
+
1626
+ if directive == "display":
1627
+ return None
1628
+ elif directive == "validate":
1629
+ if valid:
1630
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
1631
+ else:
1632
+ msg = f"Validation failed for object_action `{command}`\n"
1633
+ logger.error(msg)
1634
+ return valid
1635
+
1636
+ elif directive == "process":
1637
+ attributes = parsed_output['attributes']
1638
+ search_string = attributes.get('Search String', {}).get('value', '*')
1639
+ output_format = attributes.get('Output Format', {}).get('value', 'LIST')
1640
+ detailed = attributes.get('Detailed', {}).get('value', False)
1641
+
1642
+ try:
1643
+ if not valid: # First validate the command before we process it
1644
+ msg = f"Validation failed for {object_action} `{object_type}`\n"
1645
+ logger.error(msg)
1646
+ return None
1647
+
1648
+ list_md = f"\n# `{object_type}` with filter: `{search_string}`\n\n"
1649
+ struct = egeria_client.find_data_classes(search_string, output_format=output_format)
1650
+
1651
+ if output_format == "DICT":
1652
+ list_md += f"```\n{json.dumps(struct, indent=4)}\n```\n"
1653
+ else:
1654
+ list_md += struct
1655
+ logger.info(f"Wrote `{object_type}` for search string: `{search_string}`")
1656
+
1657
+ return list_md
1658
+
1659
+ except Exception as e:
1660
+ logger.error(f"Error performing {command}: {e}")
1661
+ console.print_exception(show_locals=True)
1662
+ return None
1663
+ else:
1664
+ return None