pyegeria 5.3.9.9.3__py3-none-any.whl → 5.5.3.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyegeria might be problematic. Click here for more details.

Files changed (272) hide show
  1. commands/__init__.py +24 -0
  2. commands/cat/Dr-Egeria_md-orig.py +2 -2
  3. commands/cat/__init__.py +1 -17
  4. commands/cat/collection_actions.py +197 -0
  5. commands/cat/dr_egeria_command_help.py +372 -0
  6. commands/cat/dr_egeria_jupyter.py +7 -7
  7. commands/cat/dr_egeria_md.py +27 -182
  8. commands/cat/exp_list_glossaries.py +11 -14
  9. commands/cat/get_asset_graph.py +37 -267
  10. commands/cat/{get_collection.py → get_collection_tree.py} +10 -18
  11. commands/cat/get_project_dependencies.py +14 -14
  12. commands/cat/get_project_structure.py +15 -14
  13. commands/cat/get_tech_type_elements.py +16 -116
  14. commands/cat/glossary_actions.py +145 -298
  15. commands/cat/list_assets.py +3 -11
  16. commands/cat/list_cert_types.py +17 -63
  17. commands/cat/list_collections.py +46 -138
  18. commands/cat/list_deployed_catalogs.py +15 -27
  19. commands/cat/list_deployed_database_schemas.py +27 -43
  20. commands/cat/list_deployed_databases.py +16 -31
  21. commands/cat/list_deployed_servers.py +35 -54
  22. commands/cat/list_glossaries.py +18 -17
  23. commands/cat/list_projects.py +10 -12
  24. commands/cat/list_tech_type_elements.py +21 -37
  25. commands/cat/list_tech_types.py +13 -25
  26. commands/cat/list_terms.py +38 -79
  27. commands/cat/list_todos.py +4 -11
  28. commands/cat/list_user_ids.py +3 -10
  29. commands/cat/my_reports.py +559 -0
  30. commands/cat/run_report.py +394 -0
  31. commands/cat/run_report_orig.py +528 -0
  32. commands/cli/egeria.py +222 -247
  33. commands/cli/egeria_cat.py +68 -81
  34. commands/cli/egeria_my.py +13 -0
  35. commands/cli/egeria_ops.py +69 -74
  36. commands/cli/egeria_tech.py +17 -93
  37. commands/cli/ops_config.py +3 -6
  38. commands/{cat/list_categories.py → deprecated/list_data_designer.py} +53 -64
  39. commands/{cat/list_data_structures.py → deprecated/list_data_structures_full.py} +3 -6
  40. commands/deprecated/old_get_asset_graph.py +315 -0
  41. commands/my/__init__.py +0 -2
  42. commands/my/list_my_profile.py +27 -34
  43. commands/my/list_my_roles.py +1 -7
  44. commands/my/monitor_my_todos.py +1 -7
  45. commands/my/monitor_open_todos.py +6 -7
  46. commands/my/todo_actions.py +4 -5
  47. commands/ops/__init__.py +0 -2
  48. commands/ops/gov_server_actions.py +17 -21
  49. commands/ops/list_archives.py +17 -38
  50. commands/ops/list_catalog_targets.py +33 -40
  51. commands/ops/load_archive.py +35 -26
  52. commands/ops/{monitor_engine_activity_c.py → monitor_active_engine_activity.py} +51 -82
  53. commands/ops/{monitor_integ_daemon_status.py → monitor_daemon_status.py} +35 -55
  54. commands/ops/monitor_engine_activity.py +79 -77
  55. commands/ops/{monitor_gov_eng_status.py → monitor_engine_status.py} +10 -7
  56. commands/ops/monitor_platform_status.py +38 -50
  57. commands/ops/monitor_server_startup.py +6 -11
  58. commands/ops/monitor_server_status.py +7 -11
  59. commands/ops/orig_monitor_server_list.py +8 -8
  60. commands/ops/orig_monitor_server_status.py +1 -5
  61. commands/ops/refresh_integration_daemon.py +5 -5
  62. commands/ops/restart_integration_daemon.py +5 -5
  63. commands/ops/table_integ_daemon_status.py +6 -6
  64. commands/ops/x_engine_actions.py +7 -7
  65. commands/tech/__init__.py +0 -2
  66. commands/tech/{generic_actions.py → element_actions.py} +6 -11
  67. commands/tech/get_element_info.py +20 -29
  68. commands/tech/get_guid_info.py +23 -42
  69. commands/tech/get_tech_details.py +20 -35
  70. commands/tech/get_tech_type_template.py +28 -39
  71. commands/tech/list_all_om_type_elements.py +24 -30
  72. commands/tech/list_all_om_type_elements_x.py +22 -28
  73. commands/tech/list_all_related_elements.py +19 -28
  74. commands/tech/list_anchored_elements.py +22 -30
  75. commands/tech/list_asset_types.py +19 -24
  76. commands/tech/list_elements_by_classification_by_property_value.py +26 -32
  77. commands/tech/list_elements_by_property_value.py +19 -25
  78. commands/tech/list_elements_by_property_value_x.py +20 -28
  79. commands/tech/list_elements_for_classification.py +28 -41
  80. commands/tech/list_gov_action_processes.py +16 -27
  81. commands/tech/list_information_supply_chains.py +22 -30
  82. commands/tech/list_registered_services.py +14 -26
  83. commands/tech/list_related_elements_with_prop_value.py +15 -25
  84. commands/tech/list_related_specification.py +1 -4
  85. commands/tech/list_relationship_types.py +15 -25
  86. commands/tech/list_relationships.py +20 -36
  87. commands/tech/list_solution_blueprints.py +28 -33
  88. commands/tech/list_solution_components.py +23 -29
  89. commands/tech/list_solution_roles.py +21 -32
  90. commands/tech/list_tech_templates.py +51 -54
  91. commands/tech/list_valid_metadata_values.py +5 -9
  92. commands/tech/table_tech_templates.py +2 -6
  93. commands/tech/x_list_related_elements.py +1 -4
  94. examples/GeoSpatial Products Example.py +524 -0
  95. examples/Jupyter Notebooks/P-egeria-server-config.ipynb +2137 -0
  96. examples/Jupyter Notebooks/README.md +2 -0
  97. examples/Jupyter Notebooks/common/P-environment-check.ipynb +115 -0
  98. examples/Jupyter Notebooks/common/__init__.py +14 -0
  99. examples/Jupyter Notebooks/common/common-functions.ipynb +4694 -0
  100. examples/Jupyter Notebooks/common/environment-check.ipynb +52 -0
  101. examples/Jupyter Notebooks/common/globals.ipynb +184 -0
  102. examples/Jupyter Notebooks/common/globals.py +154 -0
  103. examples/Jupyter Notebooks/common/orig_globals.py +152 -0
  104. examples/format_sets/all_format_sets.json +910 -0
  105. examples/format_sets/custom_format_sets.json +268 -0
  106. examples/format_sets/subset_format_sets.json +187 -0
  107. examples/format_sets_save_load_example.py +291 -0
  108. examples/jacquard_data_sets.py +129 -0
  109. examples/output_formats_example.py +193 -0
  110. examples/test_jacquard_data_sets.py +54 -0
  111. examples/test_jacquard_data_sets_scenarios.py +94 -0
  112. md_processing/__init__.py +90 -0
  113. md_processing/command_dispatcher.py +33 -0
  114. md_processing/command_mapping.py +221 -0
  115. md_processing/data/commands/commands_data_designer.json +537 -0
  116. md_processing/data/commands/commands_external_reference.json +733 -0
  117. md_processing/data/commands/commands_feedback.json +155 -0
  118. md_processing/data/commands/commands_general.json +204 -0
  119. md_processing/data/commands/commands_glossary.json +218 -0
  120. md_processing/data/commands/commands_governance.json +3678 -0
  121. md_processing/data/commands/commands_product_manager.json +865 -0
  122. md_processing/data/commands/commands_project.json +642 -0
  123. md_processing/data/commands/commands_solution_architect.json +366 -0
  124. md_processing/data/commands.json +17568 -0
  125. md_processing/data/commands_working.json +30641 -0
  126. md_processing/data/gened_report_specs.py +6584 -0
  127. md_processing/data/generated_format_sets.json +6533 -0
  128. md_processing/data/generated_format_sets_old.json +4137 -0
  129. md_processing/data/generated_format_sets_old.py +45 -0
  130. md_processing/dr_egeria.py +182 -0
  131. md_processing/md_commands/__init__.py +3 -0
  132. md_processing/md_commands/data_designer_commands.py +1276 -0
  133. md_processing/md_commands/ext_ref_commands.py +530 -0
  134. md_processing/md_commands/feedback_commands.py +726 -0
  135. md_processing/md_commands/glossary_commands.py +684 -0
  136. md_processing/md_commands/governance_officer_commands.py +600 -0
  137. md_processing/md_commands/product_manager_commands.py +1266 -0
  138. md_processing/md_commands/project_commands.py +383 -0
  139. md_processing/md_commands/solution_architect_commands.py +1184 -0
  140. md_processing/md_commands/view_commands.py +295 -0
  141. md_processing/md_processing_utils/__init__.py +4 -0
  142. md_processing/md_processing_utils/common_md_proc_utils.py +1249 -0
  143. md_processing/md_processing_utils/common_md_utils.py +578 -0
  144. md_processing/md_processing_utils/determine_width.py +103 -0
  145. md_processing/md_processing_utils/extraction_utils.py +547 -0
  146. md_processing/md_processing_utils/gen_report_specs.py +643 -0
  147. md_processing/md_processing_utils/generate_dr_help.py +193 -0
  148. md_processing/md_processing_utils/generate_md_cmd_templates.py +144 -0
  149. md_processing/md_processing_utils/generate_md_templates.py +83 -0
  150. md_processing/md_processing_utils/md_processing_constants.py +1228 -0
  151. md_processing/md_processing_utils/message_constants.py +19 -0
  152. pyegeria/__init__.py +201 -443
  153. pyegeria/core/__init__.py +40 -0
  154. pyegeria/core/_base_platform_client.py +574 -0
  155. pyegeria/core/_base_server_client.py +573 -0
  156. pyegeria/core/_exceptions.py +457 -0
  157. pyegeria/core/_globals.py +60 -0
  158. pyegeria/core/_server_client.py +6073 -0
  159. pyegeria/core/_validators.py +257 -0
  160. pyegeria/core/config.py +654 -0
  161. pyegeria/{create_tech_guid_lists.py → core/create_tech_guid_lists.py} +0 -1
  162. pyegeria/core/load_config.py +37 -0
  163. pyegeria/core/logging_configuration.py +207 -0
  164. pyegeria/core/mcp_adapter.py +144 -0
  165. pyegeria/core/mcp_server.py +212 -0
  166. pyegeria/core/utils.py +405 -0
  167. pyegeria/deprecated/__init__.py +0 -0
  168. pyegeria/{_client.py → deprecated/_client.py} +62 -24
  169. pyegeria/{_deprecated_gov_engine.py → deprecated/_deprecated_gov_engine.py} +16 -16
  170. pyegeria/{classification_manager_omvs.py → deprecated/classification_manager_omvs.py} +1988 -1878
  171. pyegeria/deprecated/output_formatter_with_machine_keys.py +1127 -0
  172. pyegeria/{runtime_manager_omvs.py → deprecated/runtime_manager_omvs.py} +216 -229
  173. pyegeria/{valid_metadata_omvs.py → deprecated/valid_metadata_omvs.py} +93 -93
  174. pyegeria/{x_action_author_omvs.py → deprecated/x_action_author_omvs.py} +2 -3
  175. pyegeria/egeria_cat_client.py +25 -51
  176. pyegeria/egeria_client.py +140 -98
  177. pyegeria/egeria_config_client.py +48 -24
  178. pyegeria/egeria_tech_client.py +170 -83
  179. pyegeria/models/__init__.py +150 -0
  180. pyegeria/models/collection_models.py +168 -0
  181. pyegeria/models/models.py +654 -0
  182. pyegeria/omvs/__init__.py +84 -0
  183. pyegeria/omvs/action_author.py +342 -0
  184. pyegeria/omvs/actor_manager.py +5980 -0
  185. pyegeria/omvs/asset_catalog.py +842 -0
  186. pyegeria/omvs/asset_maker.py +2736 -0
  187. pyegeria/omvs/automated_curation.py +4403 -0
  188. pyegeria/omvs/classification_manager.py +11213 -0
  189. pyegeria/omvs/collection_manager.py +5780 -0
  190. pyegeria/omvs/community_matters_omvs.py +468 -0
  191. pyegeria/{core_omag_server_config.py → omvs/core_omag_server_config.py} +157 -157
  192. pyegeria/{data_designer_omvs.py → omvs/data_designer.py} +1991 -1691
  193. pyegeria/omvs/data_discovery.py +869 -0
  194. pyegeria/omvs/data_engineer.py +372 -0
  195. pyegeria/omvs/digital_business.py +1133 -0
  196. pyegeria/omvs/external_links.py +1752 -0
  197. pyegeria/omvs/feedback_manager.py +834 -0
  198. pyegeria/{full_omag_server_config.py → omvs/full_omag_server_config.py} +73 -69
  199. pyegeria/omvs/glossary_manager.py +3231 -0
  200. pyegeria/omvs/governance_officer.py +3009 -0
  201. pyegeria/omvs/lineage_linker.py +314 -0
  202. pyegeria/omvs/location_arena.py +1525 -0
  203. pyegeria/omvs/metadata_expert.py +668 -0
  204. pyegeria/omvs/metadata_explorer_omvs.py +2943 -0
  205. pyegeria/omvs/my_profile.py +1042 -0
  206. pyegeria/omvs/notification_manager.py +358 -0
  207. pyegeria/omvs/people_organizer.py +394 -0
  208. pyegeria/{platform_services.py → omvs/platform_services.py} +113 -193
  209. pyegeria/omvs/product_manager.py +1825 -0
  210. pyegeria/omvs/project_manager.py +1907 -0
  211. pyegeria/omvs/reference_data.py +1140 -0
  212. pyegeria/omvs/registered_info.py +334 -0
  213. pyegeria/omvs/runtime_manager.py +2817 -0
  214. pyegeria/omvs/schema_maker.py +446 -0
  215. pyegeria/{server_operations.py → omvs/server_operations.py} +27 -26
  216. pyegeria/omvs/solution_architect.py +6490 -0
  217. pyegeria/omvs/specification_properties.py +37 -0
  218. pyegeria/omvs/subject_area.py +1042 -0
  219. pyegeria/omvs/template_manager_omvs.py +236 -0
  220. pyegeria/omvs/time_keeper.py +1761 -0
  221. pyegeria/omvs/valid_metadata.py +3221 -0
  222. pyegeria/omvs/valid_metadata_lists.py +37 -0
  223. pyegeria/omvs/valid_type_lists.py +37 -0
  224. pyegeria/view/__init__.py +28 -0
  225. pyegeria/view/_output_format_models.py +514 -0
  226. pyegeria/view/_output_formats.py +14 -0
  227. pyegeria/view/base_report_formats.py +2719 -0
  228. pyegeria/view/dr_egeria_reports.py +56 -0
  229. pyegeria/view/format_set_executor.py +397 -0
  230. pyegeria/{md_processing_utils.py → view/md_processing_utils.py} +5 -5
  231. pyegeria/{mermaid_utilities.py → view/mermaid_utilities.py} +2 -154
  232. pyegeria/view/output_formatter.py +1297 -0
  233. pyegeria-5.5.3.3.dist-info/METADATA +218 -0
  234. pyegeria-5.5.3.3.dist-info/RECORD +241 -0
  235. {pyegeria-5.3.9.9.3.dist-info → pyegeria-5.5.3.3.dist-info}/WHEEL +2 -1
  236. pyegeria-5.5.3.3.dist-info/entry_points.txt +103 -0
  237. pyegeria-5.5.3.3.dist-info/top_level.txt +4 -0
  238. commands/cat/.DS_Store +0 -0
  239. commands/cat/README.md +0 -16
  240. commands/cli/txt_custom_v2.tcss +0 -19
  241. commands/my/README.md +0 -17
  242. commands/ops/README.md +0 -24
  243. commands/ops/monitor_asset_events.py +0 -108
  244. commands/tech/README.md +0 -24
  245. pyegeria/.DS_Store +0 -0
  246. pyegeria/README.md +0 -35
  247. pyegeria/_globals.py +0 -47
  248. pyegeria/_validators.py +0 -385
  249. pyegeria/asset_catalog_omvs.py +0 -864
  250. pyegeria/automated_curation_omvs.py +0 -3765
  251. pyegeria/collection_manager_omvs.py +0 -2744
  252. pyegeria/dr.egeria spec.md +0 -9
  253. pyegeria/egeria_my_client.py +0 -56
  254. pyegeria/feedback_manager_omvs.py +0 -4573
  255. pyegeria/glossary_browser_omvs.py +0 -3728
  256. pyegeria/glossary_manager_omvs.py +0 -2440
  257. pyegeria/m_test.py +0 -118
  258. pyegeria/md_processing_helpers.py +0 -58
  259. pyegeria/md_processing_utils_orig.py +0 -1103
  260. pyegeria/metadata_explorer_omvs.py +0 -2326
  261. pyegeria/my_profile_omvs.py +0 -1022
  262. pyegeria/output_formatter.py +0 -389
  263. pyegeria/project_manager_omvs.py +0 -1933
  264. pyegeria/registered_info.py +0 -167
  265. pyegeria/solution_architect_omvs.py +0 -2156
  266. pyegeria/template_manager_omvs.py +0 -1414
  267. pyegeria/utils.py +0 -197
  268. pyegeria-5.3.9.9.3.dist-info/METADATA +0 -72
  269. pyegeria-5.3.9.9.3.dist-info/RECORD +0 -143
  270. pyegeria-5.3.9.9.3.dist-info/entry_points.txt +0 -99
  271. /pyegeria/{_exceptions.py → deprecated/_exceptions.py} +0 -0
  272. {pyegeria-5.3.9.9.3.dist-info → pyegeria-5.5.3.3.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,1276 @@
1
+ """PDX-License-Identifier: Apache-2.0
2
+ Copyright Contributors to the ODPi Egeria project.
3
+
4
+ This file contains term-related object_action functions for processing Egeria Markdown
5
+
6
+
7
+ """
8
+
9
+ import json
10
+ import os
11
+ from typing import Optional
12
+
13
+ from loguru import logger
14
+ from rich import print
15
+ from rich.console import Console
16
+ from rich.markdown import Markdown
17
+
18
+ from md_processing.md_processing_utils.common_md_proc_utils import (parse_upsert_command)
19
+ from md_processing.md_processing_utils.common_md_utils import (
20
+ update_element_dictionary,
21
+ set_create_body,
22
+ set_element_prop_body,
23
+ set_update_body,
24
+ set_rel_request_body,
25
+ set_rel_prop_body,
26
+ set_data_field_body,
27
+ )
28
+ # Developer note: Request bodies follow a two-layer pattern:
29
+ # - Outer: action wrapper (NewElementRequestBody/UpdateElementRequestBody/...)
30
+ # - Inner: element-specific Properties dict placed under the outer["properties"] key
31
+ # Always build inner bodies via helpers (set_element_prop_body, set_data_field_body, etc.) and assign to the outer
32
+ from md_processing.md_processing_utils.extraction_utils import (extract_command_plus, update_a_command)
33
+ from md_processing.md_processing_utils.md_processing_constants import (load_commands)
34
+ from pyegeria import DEBUG_LEVEL, body_slimmer
35
+ from pyegeria.egeria_tech_client import EgeriaTech
36
+ from pyegeria.core.utils import make_format_set_name_from_type
37
+
38
+ GERIA_METADATA_STORE = os.environ.get("EGERIA_METADATA_STORE", "active-metadata-store")
39
+ EGERIA_KAFKA_ENDPOINT = os.environ.get("KAFKA_ENDPOINT", "localhost:9092")
40
+ EGERIA_PLATFORM_URL = os.environ.get("EGERIA_PLATFORM_URL", "https://localhost:9443")
41
+ EGERIA_VIEW_SERVER = os.environ.get("EGERIA_VIEW_SERVER", "view-server")
42
+ EGERIA_VIEW_SERVER_URL = os.environ.get("EGERIA_VIEW_SERVER_URL", "https://localhost:9443")
43
+ EGERIA_INTEGRATION_DAEMON = os.environ.get("EGERIA_INTEGRATION_DAEMON", "integration-daemon")
44
+ EGERIA_INTEGRATION_DAEMON_URL = os.environ.get("EGERIA_INTEGRATION_DAEMON_URL", "https://localhost:9443")
45
+ EGERIA_ADMIN_USER = os.environ.get("ADMIN_USER", "garygeeke")
46
+ EGERIA_ADMIN_PASSWORD = os.environ.get("ADMIN_PASSWORD", "secret")
47
+ EGERIA_USER = os.environ.get("EGERIA_USER", "erinoverview")
48
+ EGERIA_USER_PASSWORD = os.environ.get("EGERIA_USER_PASSWORD", "secret")
49
+ EGERIA_WIDTH = os.environ.get("EGERIA_WIDTH", 220)
50
+ EGERIA_JUPYTER = os.environ.get("EGERIA_JUPYTER", False)
51
+ EGERIA_HOME_GLOSSARY_GUID = os.environ.get("EGERIA_HOME_GLOSSARY_GUID", None)
52
+ EGERIA_GLOSSARY_PATH = os.environ.get("EGERIA_GLOSSARY_PATH", None)
53
+ EGERIA_ROOT_PATH = os.environ.get("EGERIA_ROOT_PATH", "../../")
54
+ EGERIA_INBOX_PATH = os.environ.get("EGERIA_INBOX_PATH", "md_processing/dr_egeria_inbox")
55
+ EGERIA_OUTBOX_PATH = os.environ.get("EGERIA_OUTBOX_PATH", "md_processing/dr_egeria_outbox")
56
+
57
+ load_commands('commands.json')
58
+ debug_level = DEBUG_LEVEL
59
+
60
+ console = Console(width=int(200))
61
+
62
+
63
+ #
64
+ # Helper functions for the data designer commands
65
+ #
66
+ @logger.catch
67
+ def add_member_to_data_collections(egeria_client: EgeriaTech, collection_list: list, display_name: str,
68
+ guid: str) -> None:
69
+ """
70
+ Add member to data dictionaries and data specifications.
71
+ """
72
+ body = {
73
+ "class": "NewRelationshipRequestBody", "properties": {
74
+ "class": "CollectionMembershipProperties", "membershipRationale": "User Specified",
75
+ "notes": "Added by Dr.Egeria"
76
+ }
77
+ }
78
+ try:
79
+ if collection_list is not None:
80
+ for collection in collection_list:
81
+ egeria_client.add_to_collection(collection, guid, body)
82
+ msg = f"Added `{display_name}` member to `{collection}`"
83
+ logger.info(msg)
84
+ else:
85
+ logger.info("There were no data collections to add.")
86
+ return
87
+
88
+ except Exception as e:
89
+ console.print_exception()
90
+
91
+
92
+ @logger.catch
93
+ def remove_member_from_data_collections(egeria_client: EgeriaTech, collection_list: list, display_name: str,
94
+ guid: str) -> None:
95
+ try:
96
+ for collection in collection_list:
97
+ egeria_client.remove_from_collection(collection, guid)
98
+ msg = f"Removed `{display_name}` member from `{collection}`"
99
+ logger.info(msg)
100
+ return
101
+
102
+ except Exception as e:
103
+ console.print_exception()
104
+
105
+
106
+ @logger.catch
107
+ def update_data_collection_memberships(egeria_client: EgeriaTech, entity_type: str, guid_list: list,
108
+ collection_class: str, guid: str, display_name: str,
109
+ replace_all_props: bool = True) -> None:
110
+ """ update the collection membership of the element
111
+
112
+ If merge_update is set to True, all existing memberships are removed and new memberships are added.
113
+ If merge_update is set to False, only the new memberships are added.
114
+ """
115
+
116
+ if replace_all_props:
117
+ match entity_type:
118
+ case "Data Specification":
119
+ get_command = egeria_client.get_collection_by_guid
120
+ case "Data Structure":
121
+ get_command = egeria_client.get_data_structure_by_guid
122
+ case "Data Field":
123
+ get_command = egeria_client.get_data_field_by_guid
124
+ case "Data Class":
125
+ get_command = egeria_client.get_data_class_by_guid
126
+
127
+ coll_list = egeria_client.get_data_memberships(get_command, guid)
128
+ if coll_list is None:
129
+ logger.warning("Unexpected -> the collection list was None - assigning empty dict")
130
+ coll_list = {}
131
+ # compare the existing collections to desired collections
132
+ if collection_class == "DataDictionary":
133
+ as_is = set(coll_list.get("DictList", {}))
134
+ elif collection_class == "DataSpec":
135
+ as_is = set(coll_list.get("SpecList", {}))
136
+
137
+ dict_set = set(coll_list.get("DictList", {}))
138
+ spec_set = set(coll_list.get("SpecList", {}))
139
+ to_be_set = set(guid_list) if guid_list is not None else set()
140
+ logger.debug(f"as_is: {as_is}")
141
+ logger.debug(f"to_be_set: {to_be_set}")
142
+
143
+ # Remove membership for collections that are in the as-is but not in the to-be
144
+ to_remove = as_is - to_be_set
145
+ logger.debug(f"to_remove: {to_remove}")
146
+ if len(to_remove) > 0:
147
+ remove_member_from_data_collections(egeria_client, to_remove, display_name, guid)
148
+
149
+ # add membership for collections that are in the to-be but are not in the as-is
150
+ to_add = to_be_set - as_is
151
+ logger.debug(f"to_add: {to_add}")
152
+ if len(to_add) > 0:
153
+ add_member_to_data_collections(egeria_client, to_add, display_name, guid)
154
+ else:
155
+ add_member_to_data_collections(egeria_client, guid_list, display_name, guid)
156
+
157
+
158
+ # @logger.catch
159
+
160
+
161
+ @logger.catch
162
+ def add_field_to_data_structures(egeria_client: EgeriaTech, display_name: str, struct_list: list, guid) -> None:
163
+ """
164
+ Add data field to data structures.
165
+ """
166
+
167
+ try:
168
+ for structure_guid in struct_list:
169
+ egeria_client.link_member_data_field(structure_guid, guid, None)
170
+ msg = f"Added `{display_name}` to structure `{structure_guid}`"
171
+ logger.info(msg)
172
+ return
173
+
174
+ except Exception as e:
175
+ console.print_exception()
176
+
177
+
178
+ @logger.catch
179
+ def remove_field_from_data_structures(egeria_client: EgeriaTech, display_name: str, struct_list: list,
180
+ guid: str) -> None:
181
+ """Remove a data field from a list of data structures."""
182
+ try:
183
+ for structure_guid in struct_list:
184
+ egeria_client.detach_member_data_field(structure_guid, guid, None)
185
+ msg = f"Removed `{display_name}` from structure `{structure_guid}`"
186
+ logger.info(msg)
187
+ return
188
+
189
+ except Exception as e:
190
+ console.print_exception()
191
+
192
+
193
+ @logger.catch
194
+ def sync_data_field_rel_elements(egeria_client: EgeriaTech, structure_list: list, parent_field_list: list, terms: list,
195
+ data_class_guid: str, guid: str, display_name: str,
196
+ replace_all_props: bool = True) -> None:
197
+ """Sync a field's related elements.
198
+
199
+ TODO: Need to add data class support when ready and may need to revisit bodies.
200
+
201
+ """
202
+ if terms:
203
+ terms = [terms]
204
+
205
+ if replace_all_props:
206
+ rel_el_list = egeria_client.get_data_field_rel_elements(guid)
207
+ # should I throw an exception if empty?
208
+ if rel_el_list is None:
209
+ logger.warning("Unexpected -> the list was None - assigning empty list")
210
+ rel_el_list = {}
211
+
212
+ as_is_data_structs = set(rel_el_list.get("data_structure_guids", []))
213
+ as_is_parent_fields = set(rel_el_list.get("parent_guids", []))
214
+ as_is_assigned_meanings = set(rel_el_list.get("assigned_meanings_guids", []))
215
+ as_is_data_classes = set(rel_el_list.get("data_class_guids", []))
216
+
217
+ to_be_data_structs = set(structure_list) if structure_list is not None else set()
218
+ to_be_parent_fields = set(parent_field_list) if parent_field_list is not None else set()
219
+ to_be_assigned_meanings = set(terms) if terms is not None else set()
220
+ to_be_data_classes = set([data_class_guid]) if data_class_guid is not None else set()
221
+
222
+ logger.trace(f"as_is_data_structs: {list(as_is_data_structs)} to_be_data_struct: {list(to_be_data_structs)}")
223
+ logger.trace(
224
+ f"as_is_parent_fields: {list(as_is_parent_fields)} to_be_parent_fields: {list(to_be_parent_fields)}")
225
+ logger.trace(f"as_is_assigned_meanings: {list(as_is_assigned_meanings)} to_be_assigned_meanings: "
226
+ f"{list(to_be_assigned_meanings)}")
227
+ logger.trace(f"as_is_data_classes: {list(as_is_data_classes)} to_be_assigned_data_classes: "
228
+ f"{list(to_be_data_classes)}")
229
+
230
+ data_struct_to_remove = as_is_data_structs - to_be_data_structs
231
+ logger.trace(f"data_struct_to_remove: {list(data_struct_to_remove)}")
232
+ if len(data_struct_to_remove) > 0:
233
+ for ds in data_struct_to_remove:
234
+ egeria_client.detach_member_data_field(ds, guid, None)
235
+ msg = f"Removed `{display_name}` from structure `{ds}`"
236
+ logger.trace(msg)
237
+ data_struct_to_add = to_be_data_structs - as_is_data_structs
238
+ logger.trace(f"data_struct_to_add: {list(data_struct_to_add)}")
239
+ if len(data_struct_to_add) > 0:
240
+ for ds in data_struct_to_add:
241
+ egeria_client.link_member_data_field(ds, guid, None)
242
+ msg = f"Added `{display_name}` to structure `{ds}`"
243
+ logger.trace(msg)
244
+
245
+ parent_field_to_remove = to_be_parent_fields - as_is_parent_fields
246
+ logger.trace(f"parent_field_to_remove: {list(parent_field_to_remove)}")
247
+ if len(parent_field_to_remove) > 0:
248
+ for field in parent_field_to_remove:
249
+ egeria_client.detach_nested_data_field(field, guid, None)
250
+ msg = f"Removed `{display_name}` from field `{field}`"
251
+ logger.trace(msg)
252
+ parent_field_to_add = to_be_parent_fields - as_is_parent_fields
253
+ logger.trace(f"parent_field_to_add: {list(parent_field_to_add)}")
254
+ if len(parent_field_to_add) > 0:
255
+ for field in parent_field_to_add:
256
+ egeria_client.link_nested_data_field(field, guid, None)
257
+ msg = f"Added `{display_name}` to field `{field}`"
258
+ logger.trace(msg)
259
+
260
+ terms_to_remove = as_is_assigned_meanings - to_be_assigned_meanings
261
+ logger.trace(f"terms_to_remove: {list(terms_to_remove)}")
262
+ if terms:
263
+ for term in terms_to_remove:
264
+ egeria_client.detach_semantic_definition(guid, term, None)
265
+ msg = f"Removed `{term}` from `{display_name}`"
266
+ logger.trace(msg)
267
+ terms_to_add = to_be_assigned_meanings - as_is_assigned_meanings
268
+ logger.trace(f"terms_to_add: {list(terms_to_add)}")
269
+ if len(terms_to_add) > 0:
270
+ for term in terms_to_add:
271
+ egeria_client.link_semantic_definition(guid, term, None)
272
+ msg = f"Added `{term}` to`{display_name}`"
273
+ logger.trace(msg)
274
+
275
+ classes_to_remove = as_is_data_classes - to_be_data_classes
276
+ logger.trace(f"classes_to_remove: {list(classes_to_remove)}")
277
+ if len(terms_to_remove) > 0:
278
+ for dc in classes_to_remove:
279
+ body = {
280
+ "class": "MetadataSourceRequestBody", "forLineage": False, "forDuplicateProcessing": False
281
+ }
282
+ egeria_client.detach_data_class_definition(guid, dc, body)
283
+ msg = f"Removed `{dc}` from `{display_name}`"
284
+ logger.trace(msg)
285
+ classes_to_add = to_be_data_classes - as_is_data_classes
286
+ logger.trace(f"classes_to_add: {list(classes_to_add)}")
287
+ if len(terms_to_add) > 0:
288
+ for dc in classes_to_add:
289
+ body = {
290
+ "class": "RelationshipRequestBody", "forLineage": False, "forDuplicateProcessing": False
291
+ }
292
+ egeria_client.link_data_class_definition(guid, dc, body)
293
+ msg = f"Added `{dc}` to`{display_name}`"
294
+ logger.trace(msg)
295
+
296
+
297
+ else: # merge - add field to related elements
298
+ if structure_list:
299
+ add_field_to_data_structures(egeria_client, display_name, structure_list, guid)
300
+ msg = f"Added `{display_name}` to `{structure_list}`"
301
+ logger.trace(msg)
302
+
303
+ if parent_field_list:
304
+ for field in parent_field_list:
305
+ egeria_client.link_nested_data_field(field, guid, None)
306
+ msg = f"Added `{display_name}` to `{field}`"
307
+ logger.trace(msg)
308
+ if terms:
309
+ for term in terms:
310
+ egeria_client.link_semantic_definition(guid, term, None)
311
+ msg = f"Added `{term}` to `{display_name}`"
312
+ logger.trace(msg)
313
+
314
+ if data_class_guid:
315
+ egeria_client.link_data_class_definition(guid, data_class_guid)
316
+ msg = f"Added `{data_class_guid}` to `{display_name}`"
317
+ logger.trace(msg)
318
+
319
+
320
+ @logger.catch
321
+ def sync_data_class_rel_elements(egeria_client: EgeriaTech, containing_data_class_guids: list, terms: list,
322
+ specializes_data_classes: list, guid: str, display_name: str,
323
+ replace_all_props: bool = True) -> None:
324
+ """Sync a data class' related elements.
325
+
326
+ """
327
+ if terms:
328
+ terms = [terms]
329
+
330
+ if replace_all_props:
331
+ rel_el_list = egeria_client.get_data_class_rel_elements(guid)
332
+ if rel_el_list is None:
333
+ logger.warning("Unexpected -> the list was None - assigning empty list")
334
+ rel_el_list = {}
335
+ if terms:
336
+ terms = [terms]
337
+
338
+ as_is_nested_classes = set(rel_el_list.get("nested_data_class_guids", []))
339
+ as_is_assigned_meanings = set(rel_el_list.get("assigned_meanings_guids", []))
340
+ as_is_specialized_classes = set(rel_el_list.get("specialized_data_class_guids", []))
341
+
342
+ to_be_nested_classes = set(containing_data_class_guids) if containing_data_class_guids is not None else set()
343
+ to_be_assigned_meanings = set(terms) if terms is not None else set()
344
+ to_be_specialized_classes = set([specializes_data_classes]) if specializes_data_classes is not None else set()
345
+
346
+ logger.trace(
347
+ f"as_is_nested_classes: {list(as_is_nested_classes)} to_be_nested_classes: {list(to_be_nested_classes)}")
348
+ logger.trace(f"as_is_assigned_meanings: {list(as_is_assigned_meanings)} to_be_assigned_meanings: "
349
+ f"{list(to_be_assigned_meanings)}")
350
+ logger.trace(f"as_is_specialized_classes: {list(as_is_specialized_classes)} to_be_specizialized_data_classes: "
351
+ f"{list(to_be_specialized_classes)}")
352
+
353
+ nested_classes_to_remove = to_be_nested_classes - as_is_nested_classes
354
+ logger.trace(f"nested_classes_to_remove: {list(nested_classes_to_remove)}")
355
+ if len(nested_classes_to_remove) > 0:
356
+ for field in nested_classes_to_remove:
357
+ egeria_client.detach_nested_data_class(field, guid, None)
358
+ msg = f"Removed `{display_name}` from field `{field}`"
359
+ logger.trace(msg)
360
+ nested_classes_to_add = to_be_nested_classes - as_is_nested_classes
361
+ logger.trace(f"nested_classes_to_add: {list(nested_classes_to_add)}")
362
+ if len(nested_classes_to_add) > 0:
363
+ for field in nested_classes_to_add:
364
+ egeria_client.link_nested_data_class(field, guid, None)
365
+ msg = f"Added `{display_name}` to field `{field}`"
366
+ logger.trace(msg)
367
+
368
+ terms_to_remove = as_is_assigned_meanings - to_be_assigned_meanings
369
+ logger.trace(f"terms_to_remove: {list(terms_to_remove)}")
370
+ if len(terms_to_remove) > 0:
371
+ for term in terms_to_remove:
372
+ egeria_client.detach_semantic_definition(guid, term, None)
373
+ msg = f"Removed `{term}` from `{display_name}`"
374
+ logger.trace(msg)
375
+ terms_to_add = to_be_assigned_meanings - as_is_assigned_meanings
376
+ logger.trace(f"terms_to_add: {list(terms_to_add)}")
377
+ if len(terms_to_add) > 0:
378
+ for term in terms_to_add:
379
+ egeria_client.link_semantic_definition(guid, term, None)
380
+ msg = f"Added `{term}` to`{display_name}`"
381
+ logger.trace(msg)
382
+
383
+ specialized_classes_to_remove = as_is_specialized_classes - to_be_specialized_classes
384
+ logger.trace(f"classes_to_remove: {list(specialized_classes_to_remove)}")
385
+ if len(terms_to_remove) > 0:
386
+ for dc in specialized_classes_to_remove:
387
+ body = {
388
+ "class": "MetadataSourceRequestBody", "forLineage": False, "forDuplicateProcessing": False
389
+ }
390
+ egeria_client.detach_specialist_data_class(guid, dc, body)
391
+ msg = f"Removed `{dc}` from `{display_name}`"
392
+ logger.trace(msg)
393
+ specialized_classes_to_add = to_be_specialized_classes - as_is_specialized_classes
394
+ logger.trace(f"classes_to_add: {list(specialized_classes_to_add)}")
395
+ if len(specialized_classes_to_add) > 0:
396
+ for dc in specialized_classes_to_add:
397
+ body = {
398
+ "class": "RelationshipRequestBody", "forLineage": False, "forDuplicateProcessing": False
399
+ }
400
+ egeria_client.link_specialist_data_class(guid, dc, body)
401
+ msg = f"Added `{dc}` to`{display_name}`"
402
+ logger.trace(msg)
403
+
404
+
405
+ else: # merge - add field to related elements
406
+ if containing_data_class_guids:
407
+ for field in containing_data_class_guids:
408
+ egeria_client.link_nested_data_class(field, guid, None)
409
+ msg = f"Added `{display_name}` to `{field}`"
410
+ logger.trace(msg)
411
+
412
+ if terms:
413
+ for term in terms:
414
+ egeria_client.link_semantic_definition(guid, term, None)
415
+ msg = f"Added `{term}` to `{display_name}`"
416
+ logger.trace(msg)
417
+ if specializes_data_classes:
418
+ for el in specializes_data_classes:
419
+ egeria_client.link_specialist_data_class(guid, el)
420
+ msg = f"Linked `{el}` to `{display_name}`"
421
+ logger.trace(msg)
422
+
423
+
424
+ @logger.catch
425
+ def process_data_spec_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
426
+ """
427
+ Processes a data specification create or update object_action by extracting key attributes such as
428
+ spec name, parent_guid, parent_relationship_type, parent_at_end_1, category
429
+
430
+ :param txt: A string representing the input cell to be processed for
431
+ extracting glossary-related attributes.
432
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
433
+ :return: A string summarizing the outcome of the processing.
434
+ """
435
+
436
+ command, object_type, object_action = extract_command_plus(txt)
437
+ print(Markdown(f"# {command}\n"))
438
+
439
+ parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
440
+
441
+ valid = parsed_output['valid']
442
+ exists = parsed_output['exists']
443
+
444
+ qualified_name = parsed_output.get('qualified_name', None)
445
+ guid = parsed_output.get('guid', None)
446
+
447
+ logger.debug(json.dumps(parsed_output, indent=4))
448
+
449
+ attributes = parsed_output['attributes']
450
+ display_name = attributes.get('Display Name', {}).get('value', "None Found")
451
+ status = attributes.get('Status', {}).get('value', None)
452
+ print(Markdown(parsed_output['display']))
453
+
454
+ in_data_spec_list = attributes.get('In Data Specification', {}).get('value', None)
455
+ in_data_spec_valid = attributes.get('In Data Specification', {}).get('valid', None)
456
+ in_data_spec_exists = attributes.get('In Data Specification', {}).get('exists', None)
457
+ output_set = make_format_set_name_from_type(object_type)
458
+ object_type = "DataSpec"
459
+ print(Markdown(parsed_output['display']))
460
+
461
+ if directive == "display":
462
+
463
+ return None
464
+ elif directive == "validate":
465
+ if valid:
466
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
467
+ else:
468
+ msg = f"Validation failed for object_action `{command}`\n"
469
+ return valid
470
+
471
+ elif directive == "process":
472
+
473
+ try:
474
+ if object_action == "Update":
475
+ if not exists:
476
+ msg = (f" Element `{display_name}` does not exist! Updating result document with Create "
477
+ f"object_action\n")
478
+ logger.error(msg)
479
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
480
+ elif not valid:
481
+ return None
482
+ else:
483
+ print(Markdown(
484
+ f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
485
+
486
+ body = set_update_body(object_type, attributes)
487
+ body['properties'] = set_element_prop_body(object_type, qualified_name, attributes)
488
+
489
+ egeria_client.update_collection(guid, body)
490
+ if status:
491
+ egeria_client.update_collection_status(guid, status)
492
+
493
+ logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}\n\n___")
494
+ update_element_dictionary(qualified_name, {
495
+ 'guid': guid, 'display_name': display_name
496
+ })
497
+ return egeria_client.get_collection_by_guid(guid, element_type='Data-Specification-DrE',
498
+ output_format='MD', report_spec=output_set)
499
+
500
+ elif object_action == "Create":
501
+ if valid is False and exists:
502
+ msg = (f" Data Specification `{display_name}` already exists and result document updated changing "
503
+ f"`Create` to `Update` in processed output\n\n___")
504
+ logger.error(msg)
505
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
506
+ elif valid is False and in_data_spec_valid is False:
507
+ msg = (f" Invalid data specification(s) `{in_data_spec_list}` "
508
+ f" invalid data? - Correct and try again\n\n___")
509
+ logger.error(msg)
510
+ return None
511
+ else:
512
+ body = set_create_body(object_type, attributes)
513
+ body["properties"] = set_element_prop_body(object_type, qualified_name, attributes)
514
+ parent_guid = body.get('parentGuid', None)
515
+ if parent_guid:
516
+ body['parentRelationshipTypeName'] = "CollectionMembership"
517
+ body['parentAtEnd1'] = True
518
+
519
+ guid = egeria_client.create_collection(body=body)
520
+ if guid:
521
+ update_element_dictionary(qualified_name, {
522
+ 'guid': guid, 'display_name': display_name
523
+ })
524
+ msg = f"Created Element `{display_name}` with GUID {guid}\n\n___"
525
+ logger.success(msg)
526
+ return egeria_client.get_collection_by_guid(guid, object_type, output_format='MD', report_spec=output_set)
527
+ else:
528
+ msg = f"Failed to create element `{display_name}` with GUID {guid}\n\n___"
529
+ logger.error(msg)
530
+ return None
531
+
532
+
533
+ except Exception as e:
534
+ logger.error(f"Error performing {command}: {e}")
535
+ return None
536
+ else:
537
+ return None
538
+
539
+
540
+ @logger.catch
541
+ def process_data_dict_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
542
+ """
543
+ Processes a data dictionary create or update object_action by extracting key attributes such as
544
+ spec name, parent_guid, parent_relationship_type, parent_at_end_1, category
545
+
546
+ :param txt: A string representing the input cell to be processed for
547
+ extracting glossary-related attributes.
548
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
549
+ :return: A string summarizing the outcome of the processing.
550
+ """
551
+
552
+
553
+ command, object_type, object_action = extract_command_plus(txt)
554
+ print(Markdown(f"# {command}\n"))
555
+
556
+ parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
557
+
558
+ valid = parsed_output['valid']
559
+ exists = parsed_output['exists']
560
+
561
+ qualified_name = parsed_output.get('qualified_name', None)
562
+ guid = parsed_output.get('guid', None)
563
+
564
+ print(Markdown(parsed_output['display']))
565
+
566
+ logger.debug(json.dumps(parsed_output, indent=4))
567
+
568
+ attributes = parsed_output['attributes']
569
+ display_name = attributes.get('Display Name', {}).get('value', "None Found")
570
+ status = attributes.get('Status', {}).get('value', None)
571
+ output_set = make_format_set_name_from_type(object_type)
572
+
573
+ if directive == "display":
574
+
575
+ return None
576
+ elif directive == "validate":
577
+ if valid:
578
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
579
+ else:
580
+ msg = f"Validation failed for object_action `{command}`\n"
581
+ return valid
582
+
583
+ elif directive == "process":
584
+
585
+ try:
586
+ if object_action == "Update":
587
+ if not exists:
588
+ msg = (f" Element `{display_name}` does not exist! Updating result document with Create "
589
+ f"object_action\n")
590
+ logger.error(msg)
591
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
592
+ elif not valid:
593
+ return None
594
+ else:
595
+ print(Markdown(
596
+ f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
597
+
598
+ body = set_update_body(object_type, attributes)
599
+ body['properties'] = set_element_prop_body("Data Spec", qualified_name, attributes)
600
+
601
+ egeria_client.update_collection(guid, body)
602
+ if status:
603
+ egeria_client.update_collection_status(guid, status)
604
+
605
+ logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}\n\n___")
606
+ update_element_dictionary(qualified_name, {
607
+ 'guid': guid, 'display_name': display_name
608
+ })
609
+ return egeria_client.get_collection_by_guid(guid, element_type='Data Specification',
610
+ output_format='MD', report_spec=output_set)
611
+
612
+ elif object_action == "Create":
613
+ if valid is False and exists:
614
+ msg = (f" Data Specification `{display_name}` already exists and result document updated changing "
615
+ f"`Create` to `Update` in processed output\n\n___")
616
+ logger.error(msg)
617
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
618
+ elif valid is False :
619
+ msg = f" invalid data? - Correct and try again\n\n___"
620
+ logger.error(msg)
621
+ return None
622
+ else:
623
+ body = set_create_body(object_type, attributes)
624
+ body["properties"] = set_element_prop_body(object_type, qualified_name, attributes)
625
+ parent_guid = body.get('parentGuid', None)
626
+ if parent_guid:
627
+ body['parentRelationshipTypeName'] = "CollectionMembership"
628
+ body['parentAtEnd1'] = True
629
+
630
+ guid = egeria_client.create_collection(body=body)
631
+ if guid:
632
+ update_element_dictionary(qualified_name, {
633
+ 'guid': guid, 'display_name': display_name
634
+ })
635
+ msg = f"Created Element `{display_name}` with GUID {guid}\n\n___"
636
+ logger.success(msg)
637
+ return egeria_client.get_collection_by_guid(guid, object_type, output_format='MD', report_spec=output_set)
638
+ else:
639
+ msg = f"Failed to create element `{display_name}` with GUID {guid}\n\n___"
640
+ logger.error(msg)
641
+ return None
642
+
643
+
644
+ except Exception as e:
645
+ logger.error(f"Error performing {command}: {e}")
646
+ return None
647
+ else:
648
+ return None
649
+
650
+
651
+ @logger.catch
652
+ def process_data_structure_upsert_command(egeria_client: EgeriaTech, txt: str,
653
+ directive: str = "display") -> Optional[str]:
654
+ """
655
+ Processes a data structure create or update object_action by extracting key attributes such as
656
+ spec name, parent_guid, parent_relationship_type, parent_at_end_1, category
657
+
658
+ :param txt: A string representing the input cell to be processed for
659
+ extracting glossary-related attributes.
660
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
661
+ :return: A string summarizing the outcome of the processing.
662
+ """
663
+
664
+
665
+ command, object_type, object_action = extract_command_plus(txt)
666
+ print(Markdown(f"# {command}\n"))
667
+
668
+ parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
669
+
670
+ valid = parsed_output['valid']
671
+ exists = parsed_output['exists']
672
+
673
+ qualified_name = parsed_output.get('qualified_name', None)
674
+ guid = parsed_output.get('guid', None)
675
+ output_set = make_format_set_name_from_type(object_type)
676
+
677
+ print(Markdown(parsed_output['display']))
678
+
679
+ if directive == "display":
680
+ return None
681
+
682
+ elif directive == "validate":
683
+ if valid:
684
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
685
+ else:
686
+ msg = f"Validation failed for object_action `{command}`\n"
687
+ return valid
688
+
689
+ elif directive == "process":
690
+ logger.debug(json.dumps(parsed_output, indent=4))
691
+ attributes = parsed_output['attributes']
692
+ display_name = attributes.get('Display Name', {}).get('value', None)
693
+ qualified_name = attributes.get('Qualified Name',{}).get('value', None)
694
+ if qualified_name is None:
695
+ qualified_name = attributes.get('Display Name',{}).get('qualified_name', None)
696
+ if qualified_name is None:
697
+ logger.error(f"Element `{display_name}` does not have a valid specification? No qualified name..Review..\n\n___ ")
698
+ return None
699
+ prop_body = set_element_prop_body(object_type, qualified_name, attributes)
700
+ prop_body['namespace'] = attributes.get('Namespace', {}).get('value', None)
701
+ display_name = attributes.get('Display Name',{}).get('value', None)
702
+
703
+ data_spec_name_list = attributes.get("In Data Specification", {}).get("name_list", "")
704
+ data_spec_value = attributes.get("In Data Specification", {}).get("value", None)
705
+ data_spec_guid_list = attributes.get("In Data Specification", {}).get("guid_list", None)
706
+
707
+ in_data_dictionary = attributes.get('In Data Dictionary', {}).get('dict_list', None)
708
+ data_dict_name_list = attributes.get('In Data Dictionary', {}).get('name_list', "")
709
+ data_dict_value_list = attributes.get('In Data Dictionary', {}).get('value', None)
710
+ data_dict_guid_list = attributes.get("In Data Dictionary", {}).get("guid_list", None)
711
+ merge_update = attributes.get('Merge Update', {}).get('value', True)
712
+
713
+ try:
714
+ if object_action == "Update":
715
+ if not exists:
716
+ logger.error(f"Element `{qualified_name}` does not exist! Updating result document with Create "
717
+ f"object_action\n\n___")
718
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
719
+ elif not valid:
720
+ logger.error(f"Element `{qualified_name}` does not have a valid specification? Review..\n\n___ ")
721
+ return None
722
+ else:
723
+ update_body = set_update_body(object_type,attributes)
724
+ update_body['properties'] = prop_body
725
+ egeria_client.update_data_structure(guid, update_body)
726
+ update_element_dictionary(qualified_name, {
727
+ 'guid': guid, 'display_name': display_name
728
+ })
729
+ logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}\n\n___")
730
+
731
+ core_props = egeria_client.get_data_structure_by_guid(guid, output_format='MD', report_spec=output_set)
732
+
733
+ update_element_dictionary(qualified_name, {
734
+ 'guid': guid, 'display_name': display_name
735
+ })
736
+
737
+ update_data_collection_memberships(egeria_client, object_type, data_spec_guid_list, "DataSpec", guid,
738
+ display_name, merge_update)
739
+ update_data_collection_memberships(egeria_client, object_type, data_dict_guid_list, "DataSpec",
740
+ guid,display_name, merge_update)
741
+ core_props += f"## In Data Dictionary\n\n{data_dict_name_list}\n\n"
742
+ core_props += f"## In Data Specification\n\n{data_spec_name_list}\n\n"
743
+ logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}\n\n___")
744
+ return core_props
745
+
746
+
747
+ if not valid:
748
+ if exists and object_action == "Create":
749
+ msg = (f"Create failed because Element `{display_name}` exists - changing `Create` to `Update` in "
750
+ f"processed output \n\n___")
751
+ logger.error(msg)
752
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
753
+ else:
754
+ return None
755
+
756
+
757
+ elif object_action == "Create":
758
+ if exists:
759
+ logger.warning(f"\nTerm `{display_name}` already exists and result document updated\n\n___")
760
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
761
+ else:
762
+ body = set_create_body(object_type, attributes)
763
+ body['properties'] = prop_body
764
+ guid = egeria_client.create_data_structure(body_slimmer(body))
765
+ if guid:
766
+ update_element_dictionary(qualified_name, {
767
+ 'guid': guid, 'display_name': display_name
768
+ })
769
+
770
+ core_props = egeria_client.get_data_structure_by_guid(guid, output_format='MD', report_spec=output_set)
771
+
772
+ if in_data_dictionary:
773
+ logger.info(f"Will add to data dictionary(s) `{in_data_dictionary}`")
774
+ add_member_to_data_collections(egeria_client, data_dict_guid_list,
775
+ display_name,guid)
776
+ core_props += f"## In Data Dictionary\n\n{data_dict_name_list}\n\n"
777
+
778
+ if data_spec_guid_list:
779
+ add_member_to_data_collections(egeria_client, data_spec_guid_list,
780
+ display_name, guid)
781
+ core_props += f"## In Data Specifications\n\n`{data_spec_name_list}`\n\n"
782
+
783
+ logger.info(f"Created Element `{display_name}` with GUID {guid}\n\n___")
784
+
785
+ return core_props
786
+ else:
787
+ logger.error(f"Failed to create Data Structure `{display_name}`\n\n___")
788
+ return None
789
+
790
+ except Exception as e:
791
+ logger.error(f"Error performing {object_action}: {e}\n\n___")
792
+ return None
793
+ else:
794
+ return None
795
+
796
+
797
+ @logger.catch
798
+ def process_data_field_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
799
+ """
800
+ Processes a data field create or update object_action by extracting key attributes such as
801
+ spec name, parent_guid, parent_relationship_type, parent_at_end_1, category
802
+
803
+ :param txt: A string representing the input cell to be processed for
804
+ extracting glossary-related attributes.
805
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
806
+ :return: A string summarizing the outcome of the processing.
807
+ """
808
+ from md_processing.md_processing_utils.common_md_utils import set_debug_level
809
+
810
+ set_debug_level(directive)
811
+
812
+ command, object_type, object_action = extract_command_plus(txt)
813
+ print(Markdown(f"# {command}\n"))
814
+
815
+ parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
816
+ attributes = parsed_output['attributes']
817
+ display_name = attributes['Display Name'].get('value', None)
818
+ qualified_name = parsed_output.get('qualified_name', None)
819
+ guid = parsed_output.get('guid', None)
820
+ valid = parsed_output['valid']
821
+ exists = parsed_output['exists']
822
+ output_set = make_format_set_name_from_type(object_type)
823
+
824
+ print(Markdown(parsed_output['display']))
825
+
826
+ if directive == "display":
827
+
828
+ return None
829
+ elif directive == "validate":
830
+ if valid:
831
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
832
+ else:
833
+ msg = f"Validation failed for object_action `{command}`\n"
834
+ logger.error(msg)
835
+ return valid
836
+
837
+ elif directive == "process":
838
+ logger.debug(json.dumps(parsed_output, indent=4))
839
+
840
+
841
+ merge_update = attributes.get('Merge Update', {}).get('value', None)
842
+
843
+ position = attributes.get('Position', {}).get('value', None)
844
+ min_cardinality = attributes.get('Minimum Cardinality', {}).get('value', None)
845
+ max_cardinality = attributes.get('Maximum Cardinality', {}).get('value', None)
846
+
847
+ in_data_structure = attributes.get('In Data Structure', {}).get('value', None)
848
+ data_structure_guid_list = attributes.get('In Data Structure', {}).get('guid_list', None)
849
+ in_data_structure_names = attributes.get('In Data Structure Names', {}).get('name_list', None)
850
+
851
+ data_class = attributes.get('Data Class', {}).get('value', None)
852
+ data_class_guid = attributes.get('Data Class', {}).get('guid', None)
853
+ glossary_term = attributes.get('Glossary Term', {}).get('value', None)
854
+ glossary_term_guid = attributes.get('Glossary Term', {}).get('guid', None)
855
+ if glossary_term_guid:
856
+ glossary_term_guid = [glossary_term_guid]
857
+
858
+ # name_details_list = attributes.get("dict_list", None)
859
+
860
+ in_data_spec = attributes.get("In Data Specification", {}).get("value", None) # this is a [dict]
861
+ data_spec_name_list = attributes.get("In Data Specification", {}).get("name_list", None)
862
+ data_spec_guid_list = attributes.get("In Data Specification", {}).get("guid_list", None)
863
+
864
+ in_data_dictionary = attributes.get('In Data Dictionary', {}).get('value', None)
865
+ in_data_dictionary_names = attributes.get('In Data Dictionary', {}).get('name_list', None)
866
+ data_dict_guid_list = attributes.get("In Data Dictionary", {}).get("guid_list", None)
867
+
868
+ parent_data_field = attributes.get('Parent Data Field', {}).get('value', None)
869
+ parent_data_field_guids = attributes.get('Parent Data Field', {}).get('guid_list', None)
870
+ parent_data_field_names = attributes.get('Parent Data Field', {}).get('name_list', None)
871
+
872
+ anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
873
+
874
+ replace_all_props = not merge_update
875
+
876
+ if not valid:
877
+ if exists and object_action == "Create":
878
+ msg = (f"Create failed because Element `{display_name}` exists - changing `Create` to `Update` in "
879
+ f"processed output\n\n___")
880
+ logger.error(msg)
881
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
882
+ else:
883
+ msg = f"Invalid specification - please review\n\n___"
884
+ logger.error(msg)
885
+ return None
886
+ else:
887
+ print(Markdown(f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
888
+
889
+ props_body = set_data_field_body(object_type, qualified_name, attributes)
890
+
891
+ try:
892
+ if object_action == "Update":
893
+ if not exists:
894
+ logger.error(f"Element `{display_name}` does not exist! Updating result document with Create "
895
+ f"object_action\n\n___")
896
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
897
+
898
+ # first update the base data field
899
+ body = set_update_body(object_type, attributes)
900
+ body['properties'] = props_body
901
+ egeria_client.update_data_field(guid, body)
902
+ logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}")
903
+ # Update data dictionary membership
904
+ update_element_dictionary(qualified_name, {
905
+ 'guid': guid, 'display_name': display_name
906
+ })
907
+ core_props = egeria_client.get_data_field_by_guid(guid, output_format='MD', report_spec=output_set) ## update back to by_guid?
908
+
909
+ # existing_data_field = egeria_client.get_data_field_by_guid(guid, output_format='JSON')
910
+
911
+ # Sync membership in data dictionaries
912
+ update_data_collection_memberships(egeria_client, object_type, data_dict_guid_list, "DataDictionary",
913
+ guid, display_name, replace_all_props)
914
+ logger.success(f"Updating data dictionaries `{in_data_dictionary_names}`")
915
+ core_props += f"\n\n## In Data Dictionary\n\n{in_data_dictionary_names}\n\n"
916
+
917
+ # Sync data field related elements (data structure, parent data fields, terms, data classes
918
+ sync_data_field_rel_elements(egeria_client, data_structure_guid_list, parent_data_field_guids,
919
+ glossary_term_guid, data_class_guid, guid, display_name, replace_all_props)
920
+ core_props += f"\n\n## In Data Structure {in_data_structure_names}\n\n"
921
+ core_props += f"\n\n## Glossary Term \n\n{glossary_term}\n\n"
922
+ core_props += f"\n\n## Parent Data Field\n\n{parent_data_field_names}\n\n"
923
+ core_props += f"\n\n## Data Class\n\n{data_class}\n\n"
924
+ core_props += "\n_______________________________________________________________________________\n\n"
925
+
926
+ # Update data classes
927
+ logger.success(f"Updated Element `{display_name}`\n\n___")
928
+ return core_props
929
+
930
+ elif object_action == "Create":
931
+ if valid is False and exists:
932
+ logger.error(
933
+ f"\nData Field `{display_name}` already exists and result document updated changing `Create` "
934
+ f"to `Update` in processed output\n\n___")
935
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
936
+ else:
937
+ # First lets create the data field
938
+ body = set_create_body(object_type, attributes)
939
+ body['properties'] = props_body
940
+ parent_guid = body.get('parentGuid', None)
941
+
942
+ guid = egeria_client.create_data_field(body)
943
+ if guid:
944
+ # Now update our element dictionary with the new information
945
+ update_element_dictionary(qualified_name, {
946
+ 'guid': guid, 'display_name': display_name
947
+ })
948
+ # Start assembling the information we will present back out
949
+ core_props = egeria_client.get_data_field_by_guid(guid, 'MD', report_spec=output_set)
950
+
951
+ # Add the field to any data dictionaries
952
+ if in_data_dictionary:
953
+ logger.info(f"Will add to data dictionary `{in_data_dictionary}`")
954
+ add_member_to_data_collections(egeria_client, data_dict_guid_list, display_name, guid)
955
+ core_props += f"\n\n## In Data Dictionary\n\n{in_data_dictionary_names}\n\n"
956
+
957
+ # Add the field to any data structures
958
+ if in_data_structure:
959
+ core_props += f"\n\n## In Data Structure\n\n{in_data_structure_names}\n\n"
960
+ for ds_guid in data_structure_guid_list:
961
+ # todo This is too naive? - need to better accommodate the relationship
962
+ prop_body = set_rel_prop_body("MemberDataFieldProperties", attributes)
963
+ prop_body["position"] = position
964
+ prop_body["minimumCardinality"] = min_cardinality
965
+ prop_body["maximumCardinality"] = max_cardinality
966
+
967
+ body = set_rel_request_body(object_type, attributes)
968
+ body['properties'] = prop_body
969
+
970
+ msg = f"Adding field to structure {ds_guid}"
971
+ logger.info(msg)
972
+ egeria_client.link_member_data_field(ds_guid, guid, body)
973
+ core_props += f"\n\n## In Data Structure {in_data_structure_names}\n\n"
974
+
975
+ if glossary_term:
976
+ if glossary_term_guid:
977
+ term_body = set_rel_prop_body("GlossaryTermProperties", attributes)
978
+ body = set_rel_request_body(object_type, attributes)
979
+ body['properties'] = term_body
980
+
981
+ core_props += f"\n\n## Glossary Term \n\n{glossary_term}\n\n"
982
+ egeria_client.link_semantic_definition(guid, glossary_term_guid, term_body)
983
+
984
+ if parent_data_field_guids:
985
+ # parent_df_body = {
986
+ # "class": "MetadataSourceRequestBody", "externalSourceGUID": external_source_guid,
987
+ # "externalSourceName": external_source_name, "effectiveTime": effective_time,
988
+ # "forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing
989
+ # }
990
+
991
+ # egeria_client.link_nested_data_field(parent_data_field_guid, guid, parent_df_body)
992
+ for parent_guid in parent_data_field_guids:
993
+ egeria_client.link_nested_data_field(parent_guid, guid)
994
+ core_props += f"\n\n## Parent Data Field\n\n{parent_data_field_names}\n\n"
995
+
996
+ # Link data class
997
+ if data_class:
998
+ prop_body = set_rel_prop_body("DataClassProperties", attributes)
999
+ body = set_rel_request_body(object_type, attributes)
1000
+ body['properties'] = prop_body
1001
+
1002
+ core_props += f"\n\n## Data Class\n\n{data_class}\n\n"
1003
+ egeria_client.link_data_class_definition(guid, data_class_guid, body)
1004
+ msg = f"Adding data class `{data_class}` to data field {display_name}"
1005
+ logger.info(msg)
1006
+
1007
+ logger.success(f"Created Element `{display_name}` with guid `{guid}`")
1008
+ logger.success("=====================================================\n\n")
1009
+ core_props += "\n___\n\n"
1010
+ return core_props
1011
+
1012
+ else:
1013
+ logger.error(f"Failed to create Term `{display_name}`\n\n___")
1014
+ return None
1015
+
1016
+ except Exception as e:
1017
+ logger.error(f"Error performing {command}: {e}\n\n___")
1018
+ return None
1019
+ else:
1020
+ return None
1021
+
1022
+
1023
+ @logger.catch
1024
+ def process_data_class_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1025
+ """
1026
+ Processes a data class create or update object_action by extracting key attributes such as
1027
+ spec name, parent_guid, parent_relationship_type, parent_at_end_1, category
1028
+
1029
+ :param txt: A string representing the input cell to be processed for
1030
+ extracting glossary-related attributes.
1031
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
1032
+ :return: A string summarizing the outcome of the processing.
1033
+ """
1034
+
1035
+ command, object_type, object_action = extract_command_plus(txt)
1036
+ print(Markdown(f"# {command}\n"))
1037
+
1038
+ parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
1039
+
1040
+ attributes = parsed_output['attributes']
1041
+ display_name = attributes['Display Name'].get('value', None)
1042
+ qualified_name = parsed_output.get('qualified_name', None)
1043
+ guid = parsed_output.get('guid', None)
1044
+ valid = parsed_output['valid']
1045
+ exists = parsed_output['exists']
1046
+ output_set = make_format_set_name_from_type(object_type)
1047
+
1048
+ print(Markdown(parsed_output['display']))
1049
+
1050
+ if directive == "display":
1051
+
1052
+ return None
1053
+ elif directive == "validate":
1054
+ if valid:
1055
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
1056
+ else:
1057
+ msg = f"Validation failed for object_action `{command}`\n"
1058
+ logger.error(msg)
1059
+ return valid
1060
+
1061
+ elif directive == "process":
1062
+ logger.debug(json.dumps(parsed_output, indent=4))
1063
+
1064
+ external_source_guid = attributes.get('External Source Name', {}).get('guid', None)
1065
+ external_source_name = attributes.get('External Source Name', {}).get('value', None)
1066
+ effective_time = attributes.get('Effective Time', {}).get('value', None)
1067
+ for_lineage = attributes.get('For Lineage', {}).get('value', False)
1068
+ for_duplicate_processing = attributes.get('For Duplicate Processing', {}).get('value', False)
1069
+ anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
1070
+ is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', None)
1071
+ # parent_id = attributes.get('Parent ID', {}).get('value', None)
1072
+ # parent_guid = attributes['Parent ID'].get('guid', None)
1073
+ # parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value', None)
1074
+ # parent_relationship_properties = attributes.get('Parent Relationship Properties',{}).get('value', None)
1075
+ # parent_at_end1 = attributes.get('Parent at End1', {}).get('value', None)
1076
+
1077
+ namespace = attributes.get('Namespace', {}).get('value', None)
1078
+ description = attributes.get('Description', {}).get('value', None)
1079
+ version_id = attributes.get('Version Identifier', {}).get('value', None)
1080
+
1081
+ ###############
1082
+ match_property_names = attributes.get('Match Property Names', {}).get('value', [])
1083
+ specification_details = attributes.get('Specification Details', {}).get('value', {})
1084
+ match_threshold = attributes.get('Match Threshold', {}).get('value', 0)
1085
+ specification = attributes.get('Specification', {}).get('value', None)
1086
+ data_type = attributes.get('Data Type', {}).get('value', None)
1087
+ is_nullable = attributes.get('Is Nullable', {}).get('value', True)
1088
+ allow_duplicates = attributes.get('Allow Duplicates', {}).get('value', True)
1089
+ default_value = attributes.get('Default Value', {}).get('value', None)
1090
+ average_value = attributes.get('Average Value', {}).get('value', None)
1091
+ value_list = attributes.get('Value List', {}).get('value', None)
1092
+ value_range_from = attributes.get('Value Range From', {}).get('value', None)
1093
+ value_range_to = attributes.get('Value Range To', {}).get('value', None)
1094
+ sample_values = attributes.get('Sample Values', {}).get('value', [])
1095
+ data_patterns = attributes.get('Data Patterns', {}).get('value', [])
1096
+ additional_properties = attributes.get('Additional Properties', {}).get('value', {})
1097
+ output_set = make_format_set_name_from_type(object_type)
1098
+
1099
+ ###############
1100
+ aliases = attributes.get('Aliases', {}).get('value', None)
1101
+ name_patterns = attributes.get('Name Patterns', {}).get('value', None)
1102
+
1103
+ min_length = attributes.get('Minimum Length', {}).get('value', None)
1104
+ length = attributes.get('Length', {}).get('value', None)
1105
+ precision = attributes.get('Precision', {}).get('value', None)
1106
+ ordered_values = attributes.get('Ordered Values', {}).get('value', None)
1107
+ sort_order = attributes.get('Sort Order', {}).get('value', None)
1108
+ effective_from = attributes.get('Effective From', {}).get('value', None)
1109
+ effective_to = attributes.get('Effective To', {}).get('value', None)
1110
+
1111
+ glossary_term = attributes.get('Glossary Term', {}).get('value', None)
1112
+ glossary_term_guid = attributes.get('Glossary Term', {}).get('guid', None)
1113
+
1114
+ merge_update = attributes.get('Merge Update', {}).get('value', True)
1115
+
1116
+ position = attributes.get('Position', {}).get('value', None)
1117
+ min_cardinality = attributes.get('Minimum Cardinality', {}).get('value', None)
1118
+ max_cardinality = attributes.get('Maximum Cardinality', {}).get('value', None)
1119
+
1120
+ in_data_structure = attributes.get('In Data Structure', {}).get('value', None)
1121
+ data_structure_guid_list = attributes.get('In Data Structure', {}).get('guid_list', None)
1122
+ in_data_structure_names = attributes.get('In Data Structure Names', {}).get('name_list', None)
1123
+
1124
+ data_class = attributes.get('Data Class', {}).get('value', None)
1125
+ glossary_term = attributes.get('Glossary Term', {}).get('value', None)
1126
+
1127
+ glossary_term_guid = attributes.get('Glossary Term', {}).get('guid', None)
1128
+
1129
+ in_data_dictionary = attributes.get('In Data Dictionary', {}).get('value', None)
1130
+ in_data_dictionary_names = attributes.get('In Data Dictionary', {}).get('name_list', None)
1131
+ data_dict_guid_list = attributes.get("In Data Dictionary", {}).get("guid_list", None)
1132
+
1133
+ containing_data_class = attributes.get('Containing Data Class', {}).get('value', None)
1134
+ containing_data_class_guids = attributes.get('Containing Data Class', {}).get('guid_list', None)
1135
+ containing_data_class_names = attributes.get('Containing Data Class', {}).get('name_list', None)
1136
+
1137
+ specializes_data_class = attributes.get('Specializes Data Class', {}).get('value', None)
1138
+ specializes_data_class_guid = attributes.get('Specializes Data Class', {}).get('guid', None)
1139
+ specializes_data_class_name = attributes.get('Specializes Data Class', {}).get('name', None)
1140
+
1141
+ anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
1142
+
1143
+ replace_all_props = not merge_update
1144
+
1145
+ if not valid:
1146
+ if exists and object_action == "Create":
1147
+ msg = (f"Create failed because Element `{display_name}` exists - changing `Create` to `Update` in "
1148
+ f"processed output\n\n___")
1149
+ logger.error(msg)
1150
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
1151
+ else:
1152
+ msg = f"Invalid specification - please review\n\n___"
1153
+ return None
1154
+ else:
1155
+ print(Markdown(f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
1156
+
1157
+ try:
1158
+ if object_action == "Update":
1159
+ if not exists:
1160
+ logger.error(f"Element `{display_name}` does not exist! Updating result document with Create "
1161
+ f"object_action\n\n___")
1162
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
1163
+
1164
+ # first update the base data class
1165
+ body = {
1166
+ "class": "UpdateElementRequestBody", "externalSourceGUID": external_source_guid,
1167
+ "externalSourceName": external_source_name, "effectiveTime": effective_time,
1168
+ "forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing, "properties": {
1169
+ "class": "DataClassProperties", "qualifiedName": qualified_name, "displayName": display_name,
1170
+ "description": description, "namespace": namespace, "matchPropertyNames": match_property_names,
1171
+ "matchThreshold": match_threshold, "specification": specification,
1172
+ "specificationDetails": specification_details, "dataType": data_type,
1173
+ "allowsDuplicateValues": allow_duplicates, "isNullable": is_nullable,
1174
+ "defaultValue": default_value, "averageValue": average_value, "valueList": value_list,
1175
+ "valueRangeFrom": value_range_from, "valueRangeTo": value_range_to,
1176
+ "sampleValues": sample_values, "dataPatterns": data_patterns,
1177
+ "additionalProperties": additional_properties
1178
+ }
1179
+ }
1180
+
1181
+ egeria_client.update_data_class(guid, body, not merge_update)
1182
+ logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}")
1183
+ # Update data dictionary membership
1184
+ update_element_dictionary(qualified_name, {
1185
+ 'guid': guid, 'display_name': display_name
1186
+ })
1187
+ core_props = egeria_client.get_data_class_by_guid(guid, None, 'MD', report_spec=output_set)
1188
+
1189
+ # Sync membership in data dictionaries
1190
+ update_data_collection_memberships(egeria_client, object_type, data_dict_guid_list, "DataDictionary",
1191
+ guid, display_name, replace_all_props)
1192
+ logger.success(f"Updating data dictionaries `{in_data_dictionary_names}`")
1193
+ core_props += f"\n\n## In Data Dictionary\n\n{in_data_dictionary_names}\n\n"
1194
+
1195
+ # Sync data field related elements (data structure, parent data fields, terms, data classes
1196
+ sync_data_class_rel_elements(egeria_client, containing_data_class_guids, glossary_term_guid,
1197
+ specializes_data_class_guid, guid, display_name, replace_all_props)
1198
+
1199
+ core_props += f"\n\n## Glossary Term \n\n{glossary_term}\n\n"
1200
+ core_props += f"\n\n## Containing Data Class\n\n{containing_data_class_names}\n\n"
1201
+ core_props += "\n___\n\n"
1202
+
1203
+ # Update data classes
1204
+ logger.success(f"Updated Element `{display_name}`\n\n___")
1205
+ return core_props
1206
+
1207
+ elif object_action == "Create":
1208
+ if valid is False and exists:
1209
+ logger.error(
1210
+ f"\nData Class `{display_name}` already exists and result document updated changing `Create` "
1211
+ f"to `Update` in processed output\n\n___")
1212
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
1213
+ else:
1214
+ # First lets create the data class
1215
+ body = {
1216
+ "class": "NewElementRequestBody", "properties": {
1217
+ "class": "DataClassProperties", "qualifiedName": qualified_name,
1218
+ "displayName": display_name, "description": description, "namespace": namespace,
1219
+ "matchPropertyNames": match_property_names, "matchThreshold": match_threshold,
1220
+ "specification": specification, "specificationDetails": specification_details,
1221
+ "dataType": data_type, "allowsDuplicateValues": allow_duplicates, "isNullable": is_nullable,
1222
+ "defaultValue": default_value, "averageValue": average_value, "valueList": value_list,
1223
+ "valueRangeFrom": value_range_from, "valueRangeTo": value_range_to,
1224
+ "sampleValues": sample_values, "dataPatterns": data_patterns,
1225
+ "additionalProperties": additional_properties
1226
+ }
1227
+ }
1228
+ guid = egeria_client.create_data_class(body)
1229
+ if guid:
1230
+ # Now update our element dictionary with the new information
1231
+ update_element_dictionary(qualified_name, {
1232
+ 'guid': guid, 'display_name': display_name
1233
+ })
1234
+ # Start assembling the information we will present back out
1235
+ core_props = egeria_client.get_data_class_by_guid(guid, None, 'MD', report_spec=output_set)
1236
+
1237
+ # Add the field to any data dictionaries
1238
+ if in_data_dictionary:
1239
+ logger.info(f"Will add to data dictionary `{in_data_dictionary}`")
1240
+ add_member_to_data_collections(egeria_client, data_dict_guid_list, display_name, guid)
1241
+ core_props += f"\n\n## In Data Dictionary\n\n{in_data_dictionary_names}\n\n"
1242
+
1243
+ if glossary_term:
1244
+ if glossary_term_guid:
1245
+ glossary_body = {
1246
+ "class": "RelationshipRequestBody", "externalSourceGUID": external_source_guid,
1247
+ "externalSourceName": external_source_name, "effectiveTime": effective_time,
1248
+ "forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing
1249
+ }
1250
+
1251
+ core_props += f"\n\n## Glossary Term \n\n{glossary_term}\n\n"
1252
+ egeria_client.link_semantic_definition(guid, glossary_term_guid, glossary_body)
1253
+
1254
+ if containing_data_class_guids:
1255
+ for dc_guid in containing_data_class_guids:
1256
+ egeria_client.link_nested_data_class(dc_guid, guid)
1257
+ core_props += f"\n\n## Parent Data Field\n\n{containing_data_class_names}\n\n"
1258
+
1259
+ if specializes_data_class_guid:
1260
+ egeria_client.link_specialist_data_class(specializes_data_class_guid, guid)
1261
+ core_props += f"\n\n## Specialized Data Field\n\n{specializes_data_class_name}\n\n"
1262
+
1263
+ logger.success(f"Created Element `{display_name}`")
1264
+ core_props += "\n___\n\n"
1265
+ return core_props
1266
+
1267
+ else:
1268
+ logger.error(f"Failed to create Term `{display_name}`\n\n___")
1269
+ return None
1270
+
1271
+ except Exception as e:
1272
+ logger.error(f"Error performing {command}: {e}\n\n___")
1273
+ return None
1274
+ else:
1275
+ return None
1276
+