pyegeria 5.4.7.3__py3-none-any.whl → 5.4.7.5__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 (45) hide show
  1. commands/cat/dr_egeria_md.py +1 -1
  2. commands/cat/list_format_set.py +6 -1
  3. commands/ops/__init__.py +0 -2
  4. commands/ops/list_catalog_targets.py +17 -15
  5. commands/ops/load_archive.py +3 -3
  6. commands/ops/monitor_engine_activity.py +1 -1
  7. commands/ops/monitor_engine_activity_c.py +1 -1
  8. commands/tech/__init__.py +0 -2
  9. commands/tech/list_gov_action_processes.py +4 -8
  10. md_processing/dr_egeria.py +1 -1
  11. md_processing/md_commands/ext_ref_commands.py +1 -2
  12. md_processing/md_commands/glossary_commands.py +1 -2
  13. md_processing/md_commands/project_commands.py +1 -2
  14. pyegeria/__init__.py +4 -96
  15. pyegeria/_client_new.py +658 -64
  16. pyegeria/_globals.py +95 -1
  17. pyegeria/_output_formats.py +1 -1
  18. pyegeria/asset_catalog_omvs.py +1 -1
  19. pyegeria/automated_curation.py +788 -857
  20. pyegeria/classification_manager.py +7212 -0
  21. pyegeria/classification_manager_omvs.py +1989 -1853
  22. pyegeria/collection_manager.py +14 -2
  23. pyegeria/data_designer.py +1 -2
  24. pyegeria/egeria_tech_client.py +3 -0
  25. pyegeria/external_references.py +1 -1
  26. pyegeria/format_set_executor.py +8 -9
  27. pyegeria/full_omag_server_config.py +1 -1
  28. pyegeria/mcp_adapter.py +1 -1
  29. pyegeria/mcp_server.py +36 -21
  30. pyegeria/md_processing_utils.py +3 -3
  31. pyegeria/md_processing_utils_orig.py +3 -3
  32. pyegeria/mermaid_utilities.py +0 -152
  33. pyegeria/models.py +5 -0
  34. pyegeria/output_formatter.py +1 -1
  35. pyegeria/project_manager.py +8 -0
  36. pyegeria/reference_data.py +4 -0
  37. pyegeria/runtime_manager_omvs.py +1 -1
  38. pyegeria/solution_architect.py +1 -1
  39. {pyegeria-5.4.7.3.dist-info → pyegeria-5.4.7.5.dist-info}/METADATA +1 -1
  40. {pyegeria-5.4.7.3.dist-info → pyegeria-5.4.7.5.dist-info}/RECORD +44 -44
  41. pyegeria/md_processing_helpers.py +0 -58
  42. {pyegeria-5.4.7.3.dist-info → pyegeria-5.4.7.5.dist-info}/WHEEL +0 -0
  43. {pyegeria-5.4.7.3.dist-info → pyegeria-5.4.7.5.dist-info}/entry_points.txt +0 -0
  44. {pyegeria-5.4.7.3.dist-info → pyegeria-5.4.7.5.dist-info}/licenses/LICENSE +0 -0
  45. {pyegeria-5.4.7.3.dist-info → pyegeria-5.4.7.5.dist-info}/top_level.txt +0 -0
pyegeria/_client_new.py CHANGED
@@ -12,6 +12,7 @@ import inspect
12
12
  import json
13
13
  import os
14
14
  import re
15
+ import sys
15
16
  from collections.abc import Callable
16
17
  from typing import Any
17
18
 
@@ -26,7 +27,7 @@ from pyegeria._exceptions_new import (
26
27
  PyegeriaAPIException, PyegeriaConnectionException, PyegeriaInvalidParameterException,
27
28
  PyegeriaUnknownException, PyegeriaClientException
28
29
  )
29
- from pyegeria._globals import enable_ssl_check, max_paging_size, NO_ELEMENTS_FOUND
30
+ from pyegeria._globals import enable_ssl_check, max_paging_size, NO_ELEMENTS_FOUND, default_time_out
30
31
  from pyegeria._validators import (
31
32
  validate_name,
32
33
  validate_server_name,
@@ -34,9 +35,14 @@ from pyegeria._validators import (
34
35
  validate_user_id,
35
36
  )
36
37
  from pyegeria.models import (SearchStringRequestBody, FilterRequestBody, GetRequestBody, NewElementRequestBody,
37
- TemplateRequestBody, UpdateStatusRequestBody, UpdateElementRequestBody, NewRelationshipRequestBody,
38
- DeleteRequestBody, UpdateRelationshipRequestBody, ResultsRequestBody, NewClassificationRequestBody,
39
- DeleteElementRequestBody, DeleteRelationshipRequestBody, DeleteClassificationRequestBody)
38
+ TemplateRequestBody, UpdateStatusRequestBody, UpdateElementRequestBody,
39
+ NewRelationshipRequestBody,
40
+ DeleteRequestBody, UpdateRelationshipRequestBody, ResultsRequestBody,
41
+ NewClassificationRequestBody,
42
+ DeleteElementRequestBody, DeleteRelationshipRequestBody, DeleteClassificationRequestBody,
43
+ LevelIdentifierQueryBody)
44
+
45
+ from pyegeria.output_formatter import populate_common_columns, resolve_output_formats, generate_output
40
46
  from pyegeria.utils import body_slimmer, dynamic_catch
41
47
 
42
48
  ...
@@ -156,6 +162,8 @@ class Client2:
156
162
  self._template_request_adapter = TypeAdapter(TemplateRequestBody)
157
163
  self._update_relationship_request_adapter = TypeAdapter(UpdateRelationshipRequestBody)
158
164
  self._results_request_adapter = TypeAdapter(ResultsRequestBody)
165
+ self._level_identifier_query_body = TypeAdapter(LevelIdentifierQueryBody)
166
+
159
167
  try:
160
168
  result = self.check_connection()
161
169
  logger.info(f"client initialized, platform origin is: {result}")
@@ -203,7 +211,7 @@ class Client2:
203
211
  return
204
212
 
205
213
  async def _async_create_egeria_bearer_token(
206
- self, user_id: str = None, password: str = None
214
+ self, user_id: str , password: str
207
215
  ) -> str:
208
216
  """Create and set an Egeria Bearer Token for the user. Async version
209
217
  Parameters
@@ -234,10 +242,8 @@ class Client2:
234
242
 
235
243
  """
236
244
  if user_id is None:
237
- validate_user_id(self.user_id)
238
245
  user_id = self.user_id
239
246
  if password is None:
240
- validate_name(self.user_pwd)
241
247
  password = self.user_pwd
242
248
 
243
249
  url = f"{self.platform_url}/api/token"
@@ -556,56 +562,6 @@ class Client2:
556
562
  response, context, e=e
557
563
  )
558
564
 
559
- def build_global_guid_lists(self) -> None:
560
- global template_guids, integration_guids
561
-
562
- self.create_egeria_bearer_token(self.user_id, self.user_pwd)
563
- # get all technology types
564
- url = (
565
- f"{self.platform_url}/servers/{self.server_name}/api/open-metadata/automated-curation/technology-types/"
566
- f"by-search-string?startFrom=0&pageSize=0&startsWith=false&"
567
- f"endsWith=false&ignoreCase=true"
568
- )
569
- body = {"filter": ""}
570
-
571
- response = self.make_request("POST", url, body)
572
- tech_types = response.json().get("elements", "no tech found")
573
- if type(tech_types) is list:
574
- for tech_type in tech_types:
575
- # get tech type details
576
- display_name = tech_type["name"]
577
-
578
- url = (f"{self.platform_url}/servers/"
579
- f"{self.server_name}/api/open-metadata/automated-curation/technology-types/by-name")
580
- body = {"filter": display_name}
581
- response = self.make_request("POST", url, body)
582
- details = response.json().get("element", "no type found")
583
- if type(details) is str:
584
- continue
585
- # get templates and update the template_guids global
586
- templates = details.get("catalogTemplates", "Not Found")
587
- if type(templates) is str:
588
- template_guids[display_name] = None
589
- else:
590
- for template in templates:
591
- template_name = template.get("name", None)
592
- template_guid = template["relatedElement"]["guid"]
593
- template_guids[template_name] = template_guid
594
- # print(f"Added {template_name} template with GUID {template_guids[template_name]}")
595
-
596
- # Now find the integration connector guids
597
- resource_list = details.get("resourceList", " ")
598
- if type(resource_list) is str:
599
- integration_guids[display_name] = None
600
- else:
601
- for resource in resource_list:
602
- resource_guid = resource["relatedElement"]["guid"]
603
- resource_type = resource["relatedElement"]["type"]["typeName"]
604
- if resource_type == "IntegrationConnector":
605
- integration_guids[display_name] = resource_guid
606
- # print(f"Added {display_name} integration connector with GUID {integration_guids[
607
- # display_name]}")
608
-
609
565
  async def __async_get_guid__(
610
566
  self,
611
567
  guid: str = None,
@@ -639,7 +595,7 @@ class Client2:
639
595
  }
640
596
  url = (
641
597
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/classification-manager/"
642
- f"elements/guid-by-unique-name?forLineage=false&forDuplicateProcessing=false"
598
+ f"elements/guid-by-unique-name"
643
599
  )
644
600
 
645
601
  result = await self._async_make_request("POST", url, body_slimmer(body))
@@ -691,6 +647,9 @@ class Client2:
691
647
  f"qualified_name={qualified_name}, tech_type={tech_type}")
692
648
  }
693
649
  raise PyegeriaInvalidParameterException(None, None, additional_info)
650
+ #
651
+ # Include basic functions for finding elements and relationships.
652
+ #
694
653
 
695
654
  def __get_guid__(
696
655
  self,
@@ -718,6 +677,11 @@ class Client2:
718
677
  )
719
678
  return result
720
679
 
680
+
681
+
682
+
683
+
684
+
721
685
  def __create_qualified_name__(self, type: str, display_name: str, local_qualifier: str = None,
722
686
  version_identifier: str = None) -> str:
723
687
  """Helper function to create a qualified name for a given type and display name.
@@ -734,10 +698,378 @@ class Client2:
734
698
  q_name = f"{q_name}::{version_identifier}"
735
699
  return q_name
736
700
 
737
- async def _async_get_element_by_guid_(self, element_guid: str) -> dict | str:
701
+ async def _async_get_relationships_with_property_value(
702
+ self,
703
+ relationship_type: str,
704
+ property_value: str,
705
+ property_names: [str],
706
+ effective_time: str = None,
707
+ for_lineage: bool = None,
708
+ for_duplicate_processing: bool = None,
709
+ start_from: int = 0,
710
+ page_size: int = max_paging_size,
711
+ time_out: int = default_time_out,
712
+ ) -> list | str:
713
+ """
714
+ Retrieve relationships of the requested relationship type name and with the requested a value found in
715
+ one of the relationship's properties specified. The value must match exactly. Async version.
716
+
717
+ https://egeria-project.org/types/
718
+
719
+ Parameters
720
+ ----------
721
+ relationship_type: str
722
+ - the type of relationship to navigate to related elements
723
+ property_value: str
724
+ - property value to be searched.
725
+ property_names: [str]
726
+ - property names to search in.
727
+ effective_time: str, default = None
728
+ - Time format is "YYYY-MM-DDTHH:MM:SS" (ISO 8601)
729
+ for_lineage: bool, default is set by server
730
+ - determines if elements classified as Memento should be returned - normally false
731
+ for_duplicate_processing: bool, default is set by server
732
+ - Normally false. Set true when the caller is part of a deduplication function
733
+ start_from: int, default = 0
734
+ - index of the list to start from (0 for start).
735
+ page_size
736
+ - maximum number of elements to return.
737
+
738
+
739
+ time_out: int, default = default_time_out
740
+ - http request timeout for this request
741
+
742
+ Returns
743
+ -------
744
+ [dict] | str
745
+ Returns a string if no elements found and a list of dict of elements with the results.
746
+
747
+ Raises
748
+ ------
749
+ InvalidParameterException
750
+ one of the parameters is null or invalid or
751
+ PropertyServerException
752
+ There is a problem adding the element properties to the metadata repository or
753
+ UserNotAuthorizedException
754
+ the requesting user is not authorized to issue this request.
755
+ """
756
+
757
+
758
+
759
+ body = {
760
+ "class": "FindPropertyNamesProperties",
761
+ "openMetadataType": relationship_type,
762
+ "propertyValue": property_value,
763
+ "propertyNames": property_names,
764
+ "effectiveTime": effective_time,
765
+ }
766
+
767
+ url = (
768
+ f"{self.platform_url}/servers/{self.server_name}/api/open-metadata/classification-manager/relationships/"
769
+ f"with-exact-property-value"
770
+ )
771
+
772
+ response: Response = await self._async_make_request(
773
+ "POST", url, body_slimmer(body), time_out=time_out
774
+ )
775
+ rels = response.json().get("relationships", NO_ELEMENTS_FOUND)
776
+ if type(rels) is list:
777
+ if len(rels) == 0:
778
+ return NO_ELEMENTS_FOUND
779
+ return rels
780
+
781
+ def get_relationships_with_property_value(
782
+ self,
783
+ relationship_type: str,
784
+ property_value: str,
785
+ property_names: [str],
786
+ effective_time: str = None,
787
+ for_lineage: bool = None,
788
+ for_duplicate_processing: bool = None,
789
+ start_from: int = 0,
790
+ page_size: int = max_paging_size,
791
+ time_out: int = default_time_out,
792
+ ) -> list | str:
793
+ """
794
+ Retrieve relationships of the requested relationship type name and with the requested a value found in
795
+ one of the relationship's properties specified. The value must match exactly.
796
+
797
+ Parameters
798
+ ----------
799
+ relationship_type: str
800
+ - the type of relationship to navigate to related elements
801
+ property_value: str
802
+ - property value to be searched.
803
+ property_names: [str]
804
+ - property names to search in.
805
+ effective_time: str, default = None
806
+ - Time format is "YYYY-MM-DDTHH:MM:SS" (ISO 8601)
807
+ for_lineage: bool, default is set by server
808
+ - determines if elements classified as Memento should be returned - normally false
809
+ for_duplicate_processing: bool, default is set by server
810
+ - Normally false. Set true when the caller is part of a deduplication function
811
+ start_from: int, default = 0
812
+ - index of the list to start from (0 for start).
813
+ page_size
814
+ - maximum number of elements to return.
815
+
816
+
817
+ time_out: int, default = default_time_out
818
+ - http request timeout for this request
819
+
820
+ Returns
821
+ -------
822
+ [dict] | str
823
+ Returns a string if no elements found and a list of dict of elements with the results.
824
+
825
+ Raises
826
+ ------
827
+ InvalidParameterException
828
+ one of the parameters is null or invalid or
829
+ PropertyServerException
830
+ There is a problem adding the element properties to the metadata repository or
831
+ UserNotAuthorizedException
832
+ the requesting user is not authorized to issue this request.
833
+ """
834
+
835
+ loop = asyncio.get_event_loop()
836
+ response = loop.run_until_complete(
837
+ self._async_get_relationships_with_property_value(
838
+ relationship_type,
839
+ property_value,
840
+ property_names,
841
+ effective_time,
842
+ for_lineage,
843
+ for_duplicate_processing,
844
+ start_from,
845
+ page_size,
846
+ time_out,
847
+ )
848
+ )
849
+ return response
850
+
851
+
852
+ async def async_get_elements_by_property_value(
853
+ self,
854
+ property_value: str,
855
+ property_names: [str],
856
+ metadata_element_type_name: str = None,
857
+ effective_time: str = None,
858
+ for_lineage: bool = None,
859
+ for_duplicate_processing: bool = None,
860
+ start_from: int = 0,
861
+ page_size: int = 0,
862
+ time_out: int = default_time_out,
863
+ ) -> list | str:
864
+ """
865
+ Retrieve elements by a value found in one of the properties specified. The value must match exactly.
866
+ An open metadata type name may be supplied to restrict the results. Async version.
867
+
868
+ https://egeria-project.org/types/
869
+
870
+ Parameters
871
+ ----------
872
+ property_value: str
873
+ - property value to be searched.
874
+ property_names: [str]
875
+ - property names to search in.
876
+ metadata_element_type_name : str, default = None
877
+ - open metadata type to be used to restrict the search
878
+ effective_time: str, default = None
879
+ - Time format is "YYYY-MM-DDTHH:MM:SS" (ISO 8601)
880
+ for_lineage: bool, default is set by server
881
+ - determines if elements classified as Memento should be returned - normally false
882
+ for_duplicate_processing: bool, default is set by server
883
+ - Normally false. Set true when the caller is part of a deduplication function
884
+ start_from: int, default = 0
885
+ - index of the list to start from (0 for start).
886
+ page_size
887
+ - maximum number of elements to return.
888
+
889
+
890
+ time_out: int, default = default_time_out
891
+ - http request timeout for this request
892
+
893
+ Returns
894
+ -------
895
+ [dict] | str
896
+ Returns a string if no elements found and a list of dict of elements with the results.
897
+
898
+ Raises
899
+ ------
900
+ PyegeriaException
901
+ """
902
+
903
+ body = {
904
+ "class": "FindPropertyNamesProperties",
905
+ "metadataElementTypeName": metadata_element_type_name,
906
+ "propertyValue": property_value,
907
+ "propertyNames": property_names,
908
+ "effectiveTime": effective_time,
909
+ "startFrom": start_from,
910
+ "pageSize": page_size,
911
+ "forLineage": for_lineage,
912
+ "forDuplicateProcessing": for_duplicate_processing
913
+ }
914
+
915
+ url = f"{self.platform_url}/servers/{self.server_name}/api/open-metadata/classification-explorer/elements/by-exact-property-value"
916
+
917
+ response: Response = await self._async_make_request(
918
+ "POST", url, body_slimmer(body), time_out=time_out
919
+ )
920
+
921
+ elements = response.json().get("elements", NO_ELEMENTS_FOUND)
922
+ if type(elements) is list:
923
+ if len(elements) == 0:
924
+ return NO_ELEMENTS_FOUND
925
+ return elements
926
+
927
+ def get_elements_by_property_value(
928
+ self,
929
+ property_value: str,
930
+ property_names: [str],
931
+ metadata_element_type_name: str = None,
932
+ effective_time: str = None,
933
+ for_lineage: bool = None,
934
+ for_duplicate_processing: bool = None,
935
+ start_from: int = 0,
936
+ page_size: int = 0,
937
+ time_out: int = default_time_out,
938
+ output_format: str = "JSON",
939
+ output_format_set: dict | str = None,
940
+ ) -> list | str:
941
+ """
942
+ Retrieve elements by a value found in one of the properties specified. The value must match exactly.
943
+ An open metadata type name may be supplied to restrict the results.
944
+
945
+ https://egeria-project.org/types/
946
+
947
+ Parameters
948
+ ----------
949
+ property_value: str
950
+ - property value to be searched.
951
+ property_names: [str]
952
+ - property names to search in.
953
+ metadata_element_type_name : str, default = None
954
+ - open metadata type to be used to restrict the search
955
+ effective_time: str, default = None
956
+ - Time format is "YYYY-MM-DDTHH:MM:SS" (ISO 8601)
957
+ for_lineage: bool, default is set by server
958
+ - determines if elements classified as Memento should be returned - normally false
959
+ for_duplicate_processing: bool, default is set by server
960
+ - Normally false. Set true when the caller is part of a deduplication function
961
+ start_from: int, default = 0
962
+ - index of the list to start from (0 for start).
963
+ page_size
964
+ - maximum number of elements to return.
965
+ time_out: int, default = default_time_out
966
+ - http request timeout for this request
967
+ output_format: str, default = "JSON"
968
+ - Type of output to return.
969
+ output_format_set: dict | str, default = None
970
+ - Output format set to use. If None, the default output format set is used.
971
+
972
+ Returns
973
+ -------
974
+ [dict] | str
975
+ Returns a string if no elements found and a list of dict of elements with the results.
976
+
977
+ Raises
978
+ ------
979
+ PyegeriaException.
980
+ """
981
+
982
+ loop = asyncio.get_event_loop()
983
+ response = loop.run_until_complete(
984
+ self.async_get_elements_by_property_value(
985
+ property_value,
986
+ property_names,
987
+ metadata_element_type_name,
988
+ effective_time,
989
+ for_lineage,
990
+ for_duplicate_processing,
991
+ start_from,
992
+ page_size,
993
+ time_out,
994
+ )
995
+ )
996
+ return response
997
+
998
+ async def async_get_guid_for_name(
999
+ self, name: str, property_name: [str] = ["qualifiedName","displayName"], type_name: str = "ValidMetadataValue"
1000
+
1001
+ ) -> list | str:
1002
+ """
1003
+ Retrieve the guid associated with the supplied element name.
1004
+ If more than one element returned, an exception is thrown. Async version.
1005
+
1006
+ Parameters
1007
+ ----------
1008
+ name: str
1009
+ - element name to be searched.
1010
+ property_name: [str], default = ["qualifiedName","displayName"]
1011
+ - propertys to search in.
1012
+ type_name: str, default = "ValidMetadataValue"
1013
+ - metadata element type name to be used to restrict the search
1014
+ Returns
1015
+ -------
1016
+ str
1017
+ Returns the guid of the element.
1018
+
1019
+ Raises
1020
+ ------
1021
+ PyegeriaException
1022
+ """
1023
+
1024
+ elements = await self.async_get_elements_by_property_value(
1025
+ name, property_name, type_name
1026
+ )
1027
+
1028
+ if type(elements) is list:
1029
+ if len(elements) == 0:
1030
+ return NO_ELEMENTS_FOUND
1031
+ elif len(elements) > 1:
1032
+ raise Exception("Multiple elements found for supplied name!")
1033
+ elif len(elements) == 1:
1034
+ return elements[0]["elementHeader"]["guid"]
1035
+ return elements
1036
+
1037
+ def get_guid_for_name(
1038
+ self, name: str, property_name: [str] = ["qualifiedName","displayName"], type_name: str = "ValidMetadataValue"
1039
+ ) -> list | str:
738
1040
  """
739
- Simplified, internal version of get_element_by_guid found in Classification Manager.
740
- Retrieve an element by its guid. Async version.
1041
+ Retrieve the guid associated with the supplied element name.
1042
+ If more than one element returned, an exception is thrown.
1043
+
1044
+ Parameters
1045
+ ----------
1046
+ name: str
1047
+ - element name to be searched.
1048
+ property_name: [str], default = ["qualifiedName","displayName"]
1049
+ - propertys to search in.
1050
+ type_name: str, default = "ValidMetadataValue"
1051
+ - metadata element type name to be used to restrict the search
1052
+ Returns
1053
+ -------
1054
+ str
1055
+ Returns the guid of the element.
1056
+
1057
+ Raises
1058
+ ------
1059
+ PyegeriaExeception
1060
+ """
1061
+
1062
+ loop = asyncio.get_event_loop()
1063
+ response = loop.run_until_complete(
1064
+ self.async_get_guid_for_name(name, property_name, type_name)
1065
+ )
1066
+ return response
1067
+
1068
+
1069
+ async def async_get_element_by_guid_(self, element_guid: str) -> dict | str:
1070
+ """
1071
+ Simplified, internal version of get_element_by_guid found in Classification Manager.
1072
+ Retrieve an element by its guid. Async version.
741
1073
 
742
1074
  Parameters
743
1075
  ----------
@@ -764,7 +1096,7 @@ class Client2:
764
1096
  "effectiveTime": None,
765
1097
  }
766
1098
 
767
- url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/classification-manager/elements/"
1099
+ url = (f"{self.platform_url}/servers/{self.server_name}/api/open-metadata/classification-manager/elements/"
768
1100
  f"{element_guid}?forLineage=false&forDuplicateProcessing=false")
769
1101
 
770
1102
  response: Response = await self._async_make_request("POST", url, body_slimmer(body))
@@ -773,6 +1105,210 @@ class Client2:
773
1105
 
774
1106
  return elements
775
1107
 
1108
+ async def async_get_related_elements_with_property_value(
1109
+ self,
1110
+ element_guid: str,
1111
+ relationship_type: str,
1112
+ property_value: str,
1113
+ property_names: [str],
1114
+ metadata_element_type_name: str = None,
1115
+ start_at_end: int = 1,
1116
+ effective_time: str = None,
1117
+ for_lineage: bool = None,
1118
+ for_duplicate_processing: bool = None,
1119
+ start_from: int = 0,
1120
+ page_size: int = 0,
1121
+ time_out: int = default_time_out,
1122
+ ) -> list | str:
1123
+ """
1124
+ Retrieve elements linked via the requested relationship type name and with the requested a value found in one of
1125
+ the classification's properties specified. The value must match exactly. An open metadata type name may be
1126
+ supplied to restrict the types of elements returned. Async version.
1127
+
1128
+ https://egeria-project.org/types/
1129
+
1130
+ Parameters
1131
+ ----------
1132
+ element_guid: str
1133
+ - the base element to get related elements for
1134
+ relationship_type: str
1135
+ - the type of relationship to navigate to related elements
1136
+ property_value: str
1137
+ - property value to be searched.
1138
+ property_names: [str]
1139
+ - property names to search in.
1140
+ metadata_element_type_name : str, default = None
1141
+ - restrict search to elements of this open metadata type
1142
+ start_at_end: int, default = 1
1143
+ - The end of the relationship to start from - typically End1
1144
+ - open metadata type to be used to restrict the search
1145
+ effective_time: str, default = None
1146
+ - Time format is "YYYY-MM-DDTHH:MM:SS" (ISO 8601)
1147
+ for_lineage: bool, default is set by server
1148
+ - determines if elements classified as Memento should be returned - normally false
1149
+ for_duplicate_processing: bool, default is set by server
1150
+ - Normally false. Set true when the caller is part of a deduplication function
1151
+ start_from: int, default = 0
1152
+ - index of the list to start from (0 for start).
1153
+ page_size
1154
+ - maximum number of elements to return.
1155
+
1156
+
1157
+ time_out: int, default = default_time_out
1158
+ - http request timeout for this request
1159
+
1160
+ Returns
1161
+ -------
1162
+ [dict] | str
1163
+ Returns a string if no elements found and a list of dict of elements with the results.
1164
+
1165
+ Raises
1166
+ ------
1167
+ PyegeriaException
1168
+ """
1169
+
1170
+ body = {
1171
+ "class": "FindPropertyNamesProperties",
1172
+ "metadataElementTypeName": metadata_element_type_name,
1173
+ "propertyValue": property_value,
1174
+ "propertyNames": property_names,
1175
+ "effectiveTime": effective_time,
1176
+ "forLineage": for_lineage,
1177
+ "forDuplicateProcessing": for_duplicate_processing,
1178
+ "startFrom": start_from,
1179
+ "pageSize": page_size
1180
+ }
1181
+
1182
+ url = (
1183
+ f"{self.platform_url}/servers/{self.server_name}/api/open-metadata/classification-explorer/elements/{element_guid}"
1184
+ f"/by-relationship/{relationship_type}/with-exact-property-value?startAtEnd={start_at_end}"
1185
+ )
1186
+
1187
+ response: Response = await self._async_make_request(
1188
+ "POST", url, body_slimmer(body), time_out=time_out
1189
+ )
1190
+ elements = response.json().get("elements", NO_ELEMENTS_FOUND)
1191
+ if type(elements) is list:
1192
+ if len(elements) == 0:
1193
+ return NO_ELEMENTS_FOUND
1194
+ return elements
1195
+
1196
+ def get_relationships_with_property_value(
1197
+ self,
1198
+ relationship_type: str,
1199
+ property_value: str,
1200
+ property_names: [str],
1201
+ effective_time: str = None,
1202
+ for_lineage: bool = None,
1203
+ for_duplicate_processing: bool = None,
1204
+ start_from: int = 0,
1205
+ page_size: int = max_paging_size,
1206
+ time_out: int = default_time_out,
1207
+ ) -> list | str:
1208
+ """
1209
+ Retrieve relationships of the requested relationship type name and with the requested a value found in
1210
+ one of the relationship's properties specified. The value must match exactly.
1211
+
1212
+ Parameters
1213
+ ----------
1214
+ relationship_type: str
1215
+ - the type of relationship to navigate to related elements
1216
+ property_value: str
1217
+ - property value to be searched.
1218
+ property_names: [str]
1219
+ - property names to search in.
1220
+ effective_time: str, default = None
1221
+ - Time format is "YYYY-MM-DDTHH:MM:SS" (ISO 8601)
1222
+ for_lineage: bool, default is set by server
1223
+ - determines if elements classified as Memento should be returned - normally false
1224
+ for_duplicate_processing: bool, default is set by server
1225
+ - Normally false. Set true when the caller is part of a deduplication function
1226
+ start_from: int, default = 0
1227
+ - index of the list to start from (0 for start).
1228
+ page_size
1229
+ - maximum number of elements to return.
1230
+
1231
+
1232
+ time_out: int, default = default_time_out
1233
+ - http request timeout for this request
1234
+
1235
+ Returns
1236
+ -------
1237
+ [dict] | str
1238
+ Returns a string if no elements found and a list of dict of elements with the results.
1239
+
1240
+ Raises
1241
+ ------
1242
+ InvalidParameterException
1243
+ one of the parameters is null or invalid or
1244
+ PropertyServerException
1245
+ There is a problem adding the element properties to the metadata repository or
1246
+ UserNotAuthorizedException
1247
+ the requesting user is not authorized to issue this request.
1248
+ """
1249
+
1250
+ loop = asyncio.get_event_loop()
1251
+ response = loop.run_until_complete(
1252
+ self._async_get_relationships_with_property_value(
1253
+ relationship_type,
1254
+ property_value,
1255
+ property_names,
1256
+ effective_time,
1257
+ for_lineage,
1258
+ for_duplicate_processing,
1259
+ start_from,
1260
+ page_size,
1261
+ time_out,
1262
+ )
1263
+ )
1264
+ return response
1265
+
1266
+ async def async_get_connector_guid(self, connector_name: str) -> str:
1267
+ """Get the guid of a connector. Async version.
1268
+ Parameters:
1269
+ connector_name (str): The name of the connector to retrieve the guid for.
1270
+ Returns:
1271
+ str: The guid of the connector.
1272
+ """
1273
+ rel = await self._async_get_relationships_with_property_value(relationship_type="RegisteredIntegrationConnector",
1274
+ property_names=["connectorName"],
1275
+ property_value=connector_name,
1276
+ )
1277
+ if rel == "No elements found":
1278
+ logger.error(f"\n\n===> No connector found with name '{connector_name}'\n\n")
1279
+ return "No connector found"
1280
+ connector_guid = rel[0]['end2']['guid']
1281
+
1282
+ if connector_guid is None:
1283
+ logger.error(f"\n\n===> No connector found with name '{connector_name}'\n\n")
1284
+ return "No connector found"
1285
+
1286
+ return connector_guid
1287
+
1288
+
1289
+ def get_connector_guid(self, connector_name: str) -> str:
1290
+ """Get the guid of a connector.
1291
+ Parameters:
1292
+ connector_name (str): The name of the connector to retrieve the guid for.
1293
+ Returns:
1294
+ str: The guid of the connector.
1295
+ """
1296
+
1297
+ loop = asyncio.get_event_loop()
1298
+ result = loop.run_until_complete(
1299
+ self.async_get_connector_guid(
1300
+ connector_name
1301
+ )
1302
+ )
1303
+ return result
1304
+
1305
+
1306
+
1307
+ #
1308
+ # Helper functions for requests
1309
+ #
1310
+
1311
+
776
1312
  def validate_new_element_request(self, body: dict | NewElementRequestBody,
777
1313
  prop: list[str]) -> NewElementRequestBody | None:
778
1314
  if isinstance(body, NewElementRequestBody):
@@ -1029,7 +1565,7 @@ class Client2:
1029
1565
  json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
1030
1566
 
1031
1567
  response = await self._async_make_request("POST", url, json_body)
1032
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
1568
+ elements = response.json().get("element", NO_ELEMENTS_FOUND)
1033
1569
  if type(elements) is str:
1034
1570
  logger.info(NO_ELEMENTS_FOUND)
1035
1571
  return NO_ELEMENTS_FOUND
@@ -1101,6 +1637,35 @@ class Client2:
1101
1637
  output_format, output_format_set)
1102
1638
  return elements
1103
1639
 
1640
+ async def _async_get_level_identifier_query_body_request(self, url: str, _gen_output: Callable[..., Any],
1641
+ output_format: str = 'JSON',
1642
+ output_format_set: str | dict = None,
1643
+ body: dict | ResultsRequestBody = None) -> Any:
1644
+ if isinstance(body, LevelIdentifierQueryBody):
1645
+ validated_body = body
1646
+ elif isinstance(body, dict):
1647
+ validated_body = self._level_identifier_query_body.validate_python(body)
1648
+ else:
1649
+ return None
1650
+
1651
+ json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
1652
+
1653
+ response = await self._async_make_request("POST", url, json_body)
1654
+ elements = response.json().get("elements", None)
1655
+ if elements is None:
1656
+ elements = response.json().get("element", NO_ELEMENTS_FOUND)
1657
+
1658
+ if type(elements) is str:
1659
+ logger.info(NO_ELEMENTS_FOUND)
1660
+ return NO_ELEMENTS_FOUND
1661
+
1662
+ if output_format != 'JSON': # return a simplified markdown representation
1663
+ logger.info(f"Found elements, output format: {output_format} and output_format_set: {output_format_set}")
1664
+ return _gen_output(elements, "", "Referenceable",
1665
+ output_format, output_format_set)
1666
+ return elements
1667
+
1668
+
1104
1669
  async def _async_create_element_body_request(self, url: str, prop: list[str],
1105
1670
  body: dict | NewElementRequestBody = None) -> str:
1106
1671
  validated_body = self.validate_new_element_request(body, prop)
@@ -1633,4 +2198,33 @@ class Client2:
1633
2198
  # }
1634
2199
  # """
1635
2200
  # loop = asyncio.get_event_loop()
1636
- # loop.run_until_complete(self._async_update_element_status(guid, status, body))
2201
+ # loop.run_until_complete(self._async_update_element_status(guid, status, body))
2202
+
2203
+ @dynamic_catch
2204
+ def _extract_referenceable_properties(self, element: dict, columns_struct: dict) -> dict:
2205
+ """Populate default Referenceable columns for output using common population pipeline."""
2206
+ return populate_common_columns(element, columns_struct)
2207
+
2208
+ @dynamic_catch
2209
+ def _generate_referenceable_output(self, elements: dict | list[dict], search_string: str | None,
2210
+ element_type_name: str | None,
2211
+ output_format: str = "JSON",
2212
+ output_format_set: dict | str = None) -> str | list[dict]:
2213
+ """Generate formatted output for generic Referenceable elements.
2214
+
2215
+ If output_format is 'JSON', returns elements unchanged. Otherwise, resolves an
2216
+ output format set and delegates to generate_output with a standard extractor.
2217
+ """
2218
+ if output_format == "JSON":
2219
+ return elements
2220
+ entity_type = element_type_name or "Referenceable"
2221
+ output_formats = resolve_output_formats(entity_type, output_format, output_format_set, default_label=entity_type)
2222
+ return generate_output(
2223
+ elements=elements,
2224
+ search_string=search_string,
2225
+ entity_type=entity_type,
2226
+ output_format=output_format,
2227
+ extract_properties_func=self._extract_referenceable_properties,
2228
+ get_additional_props_func=None,
2229
+ columns_struct=output_formats,
2230
+ )