pyegeria 5.4.0.dev2__py3-none-any.whl → 5.4.0.dev5__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 (28) hide show
  1. commands/cat/debug_log +227 -0
  2. commands/cat/dr_egeria_md.py +12 -3
  3. commands/cat/list_collections.py +7 -6
  4. commands/cat/list_data_designer.py +22 -10
  5. md_processing/__init__.py +4 -1
  6. md_processing/data/commands.json +142 -17
  7. md_processing/dr_egeria_outbox/processed-2025-06-22 21:06-dr_egeria_data_designer_1.md +134 -0
  8. md_processing/dr_egeria_outbox/processed-2025-06-22 21:13-dr_egeria_data_designer_1.md +133 -0
  9. md_processing/dr_egeria_outbox/processed-2025-06-22 21:19-dr_egeria_data_designer_1.md +141 -0
  10. md_processing/md_commands/data_designer_commands.py +408 -101
  11. md_processing/md_commands/glossary_commands.py +0 -30
  12. md_processing/md_commands/solution_architect_commands.py +1 -1
  13. md_processing/md_processing_utils/common_md_proc_utils.py +16 -4
  14. md_processing/md_processing_utils/md_processing_constants.py +3 -1
  15. pyegeria/collection_manager_omvs.py +120 -72
  16. pyegeria/data_designer_omvs.py +143 -42
  17. pyegeria/output_formatter.py +30 -11
  18. pyegeria/solution_architect_omvs.py +273 -5
  19. {pyegeria-5.4.0.dev2.dist-info → pyegeria-5.4.0.dev5.dist-info}/METADATA +1 -1
  20. {pyegeria-5.4.0.dev2.dist-info → pyegeria-5.4.0.dev5.dist-info}/RECORD +24 -24
  21. {pyegeria-5.4.0.dev2.dist-info → pyegeria-5.4.0.dev5.dist-info}/entry_points.txt +4 -3
  22. commands/cat/debug_log.2025-06-05_20-24-18_123924.log.zip +0 -0
  23. commands/cat/debug_log.2025-06-10_08-45-03_929921.log.zip +0 -0
  24. commands/cat/debug_log.2025-06-11_09-57-21_247890.log.zip +0 -0
  25. commands/cat/debug_log.2025-06-12_16-14-31_212042.log.zip +0 -0
  26. /commands/cat/{list_data_structures.py → list_data_structures_full.py} +0 -0
  27. {pyegeria-5.4.0.dev2.dist-info → pyegeria-5.4.0.dev5.dist-info}/LICENSE +0 -0
  28. {pyegeria-5.4.0.dev2.dist-info → pyegeria-5.4.0.dev5.dist-info}/WHEEL +0 -0
@@ -95,36 +95,6 @@ def update_term_categories(egeria_client: EgeriaTech, term_guid: str, categories
95
95
  print_msg("DEBUG-INFO", msg, debug_level)
96
96
 
97
97
 
98
- # def update_term_categories(egeria_client: EgeriaTech, term_guid: str, current_categories: List[str],
99
- # new_categories: List[str]) -> None:
100
- # """
101
- # Updates the categories of a term.
102
- #
103
- # Args:
104
- # egeria_client: The Egeria client to use for the update.
105
- # term_guid: The GUID of the term to update.
106
- # current_categories: The current categories of the term.
107
- # new_categories: The new categories of the term.
108
- # """
109
- # if new_categories: # If categories are specified, add them
110
- # for cat in new_categories:
111
- # if cat not in current_categories:
112
- # egeria_client.add_term_to_category(term_guid, cat)
113
- # msg = f"Added term {term_guid} to category {cat}"
114
- # print_msg("DEBUG-INFO", msg, debug_level)
115
- # # Remove any categories that are not in the new list
116
- # for cat in current_categories:
117
- # if cat not in new_categories:
118
- # egeria_client.remove_term_from_category(term_guid, cat)
119
- # msg = f"Removed term {term_guid} from category {cat}"
120
- # print_msg("DEBUG-INFO", msg, debug_level)
121
- # else: # No categories specified - so remove any categories a term is in
122
- # for cat in current_categories:
123
- # egeria_client.remove_term_from_category(term_guid, cat)
124
- # msg = f"Removed term {term_guid} from category {cat}"
125
- # print_msg("DEBUG-INFO", msg, debug_level)
126
-
127
-
128
98
  def process_glossary_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
129
99
  """
130
100
  Processes a glossary create or update object_action by extracting key attributes such as
@@ -917,7 +917,7 @@ def process_information_supply_chain_link_unlink_command(egeria_client: EgeriaTe
917
917
  @logger.catch
918
918
  def process_sol_arch_list_command(egeria_client: EgeriaTech, txt: str, kind:str, directive: str = "display" ) -> Optional[str]:
919
919
  """
920
- Processes a Informartion Blueprint list object_action by extracting key attributes such as
920
+ Processes Solution Blueprint list object_action by extracting key attributes such as
921
921
  search string from the given text.
922
922
 
923
923
  :param txt: A string representing the input cell to be processed for
@@ -154,6 +154,9 @@ def parse_upsert_command(egeria_client: EgeriaTech, object_type: str, object_act
154
154
  logger.error(msg)
155
155
  parsed_output['valid'] = False
156
156
  parsed_output['reason'] += msg
157
+ elif parsed_attributes[key]['valid'] is False:
158
+ parsed_output['valid'] = False
159
+ parsed_output['reason'] += parsed_attributes[key]['reason']
157
160
 
158
161
  elif style == 'GUID':
159
162
  parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing)
@@ -244,7 +247,7 @@ def parse_upsert_command(egeria_client: EgeriaTech, object_type: str, object_act
244
247
  logger.info(msg)
245
248
 
246
249
 
247
- if parsed_output.get('qualified_name',None):
250
+ if parsed_output.get('qualified_name',None) and "* Qualified Name" not in parsed_output['display']:
248
251
  parsed_output['display'] += f"\n\t* Qualified Name: `{parsed_output['qualified_name']}`\n\t"
249
252
  if parsed_output.get('guid',None):
250
253
  parsed_output['display'] += f"\n\t* GUID: `{parsed_output['guid']}`\n\t"
@@ -341,8 +344,12 @@ def parse_view_command(egeria_client: EgeriaTech, object_type: str, object_actio
341
344
 
342
345
  elif style == 'Reference Name':
343
346
  parsed_attributes[key] = proc_ids(egeria_client, key, labels, txt, object_action, if_missing)
344
- if ((if_missing == ERROR) and parsed_attributes[key].get("value", None) and parsed_attributes[key][
345
- 'exists'] is False):
347
+ if ((if_missing == ERROR) and parsed_attributes[key].get("value", None)):
348
+ msg = f"Required parameter `{parsed_attributes[key]['value']}` is missing"
349
+ logger.error(msg)
350
+ parsed_output['valid'] = False
351
+ parsed_output['reason'] += msg
352
+ elif parsed_attributes[key]['value'] and parsed_attributes['exists'] is False:
346
353
  msg = f"Reference Name `{parsed_attributes[key]['value']}` is specified but does not exist"
347
354
  logger.error(msg)
348
355
  parsed_output['valid'] = False
@@ -366,7 +373,6 @@ def parse_view_command(egeria_client: EgeriaTech, object_type: str, object_actio
366
373
  elif style == 'Bool':
367
374
  parsed_attributes[key] = proc_bool_attribute(txt, object_action, labels, if_missing, default_value)
368
375
 
369
-
370
376
  elif style == 'Reference Name List':
371
377
  parsed_attributes[key] = proc_name_list(egeria_client, key, txt, labels, if_missing)
372
378
  if (parsed_attributes[key].get("value", None) and (
@@ -671,6 +677,7 @@ def proc_ids(egeria_client: EgeriaTech, element_type: str, element_labels: set,
671
677
  """
672
678
  Processes element identifiers from the input text using the labels supplied,
673
679
  checking if the element exists in Egeria, and validating the information.
680
+ Only a single element is allowed.
674
681
 
675
682
  Parameters
676
683
  ----------
@@ -704,7 +711,12 @@ def proc_ids(egeria_client: EgeriaTech, element_type: str, element_labels: set,
704
711
  value = None
705
712
 
706
713
  element_name = extract_attribute(txt, element_labels)
714
+
707
715
  if element_name:
716
+ if '\n' in element_name or ',' in element_name:
717
+ msg = f"Element name `{element_name}` appears to be a list rather than a single element"
718
+ logger.error(msg)
719
+ return {"status": ERROR, "reason": msg, "value": None, "valid": False, "exists": False, }
708
720
  q_name, guid, unique, exists = get_element_by_name(egeria_client, element_type, element_name)
709
721
  value = element_name
710
722
  else:
@@ -60,7 +60,9 @@ command_list = ["Provenance", "Create Glossary", "Update Glossary", "Create Term
60
60
  "Update Term-Term Relationship", "Create Data Spec", "Create Data Specification", "Update Data Spec",
61
61
  "Update Data Specification", "Create Data Field", "Update Data Field", "Create Data Structure",
62
62
  "Update Data Structure", "Create Data Dictionary", "Update Data Dictionary", "Create Data Dict",
63
- "Update Data Dict", " View Data Dictionary", "View Data Dictionaries", "Create Data Class", "Update Data Class",]
63
+ "Update Data Dict", " View Data Dictionary", "View Data Dictionaries", "View Data Specifications",
64
+ "View Data Specs", "View Data Structures", "View Data Structure", "View Data Fields", "View Data Field",
65
+ "View Dataa Classes", "View Data Class", "Create Data Class", "Update Data Class",]
64
66
 
65
67
 
66
68
  pre_command = "\n---\n==> Processing object_action:"
@@ -303,7 +303,7 @@ class CollectionManager(Client):
303
303
  return NO_ELEMENTS_FOUND
304
304
 
305
305
  if output_format != 'JSON': # return a simplified markdown representation
306
- return self.generate_collection_output(elements, None, None, output_format, output_profile)
306
+ return self.generate_collection_output(elements, None, None, output_format)
307
307
  return elements
308
308
 
309
309
  def find_collections(self, search_string: str, as_of_time: str = None, effective_time: str = None,
@@ -1138,6 +1138,7 @@ class CollectionManager(Client):
1138
1138
  qualified_name = self.__create_qualified_name__("DataSpec", display_name)
1139
1139
 
1140
1140
  body = body_slimmer({
1141
+ "class": "NewCollectionRequestBody",
1141
1142
  "anchorGUID": anchor_guid, "anchorScopeGUID": anchor_scope_guid, "isOwnAnchor": is_own_anchor,
1142
1143
  "parentGUID": parent_guid, "parentRelationshipTypeName": parent_relationship_type_name,
1143
1144
  "parentAtEnd1": parent_at_end1, "collectionProperties": {
@@ -1276,6 +1277,7 @@ class CollectionManager(Client):
1276
1277
  qualified_name = self.__create_qualified_name__("DataDict", display_name)
1277
1278
 
1278
1279
  body = {
1280
+ "class": "NewCollectionRequestBody",
1279
1281
  "anchorGUID": anchor_guid, "isOwnAnchor": is_own_anchor_s, "anchorScopeGUID": anchor_scope_guid,
1280
1282
  "parentGUID": parent_guid, "parentRelationshipTypeName": parent_relationship_type_name,
1281
1283
  "parentAtEnd1": parent_at_end1_s, "collectionProperties": {
@@ -2665,18 +2667,28 @@ class CollectionManager(Client):
2665
2667
  display_name = properties.get("name", "") or ""
2666
2668
  description = properties.get("description", "") or ""
2667
2669
  qualified_name = properties.get("qualifiedName", "") or ""
2668
- collection_type = properties.get("collectionType", "") or ""
2670
+ # collection_type = properties.get("collectionType", "") or ""
2669
2671
  additional_properties = properties.get("additionalProperties", {}) or {}
2670
2672
  extended_properties = properties.get("extendedProperties", {}) or {}
2671
- classifications = ", ".join(properties.get("classifications", [])) or ""
2672
- # classification_names = ""
2673
- # classifications = element['elementHeader'].get("classifications", [])
2674
- # for classification in classifications:
2675
- # classification_names += f"{classification['classificationName']}, "
2673
+ # classifications = ", ".join(properties.get("classifications", [])) or ""
2674
+
2675
+ classification_names = ""
2676
+ classifications = element['elementHeader'].get("classifications", [])
2677
+ for classification in classifications:
2678
+ classification_names += f"{classification['classificationName']}, "
2679
+ classification_names = classification_names[:-2]
2680
+
2681
+ member_names = ""
2682
+ members = self.get_member_list(collection_guid=guid)
2683
+ if isinstance(members, list):
2684
+ for member in members:
2685
+ member_names += f"{member['qualifiedName']}, "
2686
+ member_names = member_names[:-2]
2676
2687
 
2677
2688
  return {
2678
- 'guid': guid, 'properties': properties, 'display_name': display_name, 'description': description,
2679
- 'qualified_name': qualified_name, 'classifications': classifications, 'collection_type': collection_type,
2689
+ 'GUID': guid,'display_name': display_name,'qualified_name': qualified_name, 'description': description,
2690
+ 'classifications': classification_names, 'members': member_names, 'properties': properties,
2691
+ # 'collection_type': collection_type,
2680
2692
  'additional_properties': additional_properties, 'extended_properties': extended_properties,
2681
2693
  }
2682
2694
 
@@ -2719,80 +2731,116 @@ class CollectionManager(Client):
2719
2731
  # Default case
2720
2732
  return None
2721
2733
 
2722
- def generate_collection_output(self, elements, filter, collection_type: str, output_format,
2723
- output_profile: str = "CORE") -> str | list | dict:
2734
+
2735
+ def generate_collection_output(self, elements, filter, collection_type, output_format) -> str | list:
2724
2736
  """
2725
- Generate output in the specified format for the given elements.
2737
+ Generate output for collections in the specified format.
2726
2738
 
2727
2739
  Args:
2728
- elements: Dictionary or list of dictionaries containing element data
2740
+ elements: Dictionary or list of dictionaries containing data field elements
2741
+ collection_type: str
2742
+ The type of collection.
2729
2743
  filter: The search string used to find the elements
2730
- output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID, JSON)
2731
- output_profile: str, optional, default = "CORE"
2732
- The desired output profile - BASIC, CORE, FULL
2744
+ output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID)
2745
+
2733
2746
  Returns:
2734
- Formatted output as string or list of dictionaries
2747
+ Formatted output as a string or list of dictionaries
2735
2748
  """
2736
2749
  if collection_type is None:
2737
2750
  entity_type = "Collection"
2738
2751
  else:
2739
2752
  entity_type = collection_type
2740
2753
 
2741
- # For LIST and DICT formats, get member information
2742
-
2743
- if output_format in ["LIST", "DICT"]:
2744
- # Get the collection GUID
2745
- collection_guid = None
2746
- if isinstance(elements, dict):
2747
- collection_guid = elements.get('elementHeader', {}).get('guid')
2748
- elif isinstance(elements, list) and len(elements) > 0:
2749
- collection_guid = elements[0].get('elementHeader', {}).get('guid')
2750
-
2751
- # Get member list if we have a valid collection GUID
2752
- members = []
2753
- if collection_guid:
2754
- members = self.get_member_list(collection_guid=collection_guid)
2755
- if isinstance(members, str): # "No members found" case
2756
- members = []
2757
-
2758
- # For DICT format, include all member information in the result
2759
- if output_format == "DICT":
2760
- result = self.generate_basic_structured_output(elements, filter, output_format, collection_type)
2761
- if isinstance(result, list):
2762
- for item in result:
2763
- item['members'] = members
2764
- return result
2765
- elif isinstance(result, dict):
2766
- result['members'] = members
2767
- return result
2768
-
2769
- # For LIST format, add a column with bulleted list of qualified names
2770
- elif output_format == "LIST":
2771
- # Define columns for LIST format, including the new Members column
2772
- columns = [{'name': 'Collection Name', 'key': 'display_name'},
2773
- {'name': 'Qualified Name', 'key': 'qualified_name'},
2774
- {'name': 'Collection Type', 'key': 'collection_type'},
2775
- {'name': 'Description', 'key': 'description', 'format': True},
2776
- {'name': 'Classifications', 'key': 'classifications'},
2777
- {'name': 'Members', 'key': 'members', 'format': True}]
2778
-
2779
- # Create a function to add member information to the properties
2780
- def get_additional_props(element, guid, output_format):
2781
- if not members:
2782
- return {'members': ''}
2783
-
2784
- # Create a comma-separated list of qualified names (no newlines to avoid table formatting issues)
2785
- member_list = ", ".join([member.get('qualifiedName', '') for member in members])
2786
- return {'members': member_list}
2787
-
2788
- # Generate output with the additional properties
2789
-
2790
- return generate_output(elements=elements, search_string=filter, entity_type=entity_type,
2791
- output_format=output_format, extract_properties_func=self._extract_collection_properties,
2792
- get_additional_props_func=get_additional_props, columns=columns)
2793
-
2794
- # For FORM, REPORT, JSON formats, keep behavior unchanged
2795
- return self.generate_basic_structured_output(elements, filter, output_format, collection_type)
2754
+ if output_format in ["MD", "FORM", "REPORT", "LIST", "DICT", "MERMAID"]:
2755
+ # Define columns for LIST format
2756
+ columns = [{'name': 'Name', 'key': 'display_name'},
2757
+ {'name': 'Qualified Name', 'key': 'qualified_name','format': True},
2758
+ {'name': 'Description', 'key': 'description', 'format': True},
2759
+ {'name': "Classifications", 'key': 'classifications' },
2760
+ {'name': 'Members', 'key': 'members', 'format': True},
2761
+ ]
2762
+
2763
+ return generate_output(elements=elements, search_string=filter, entity_type=entity_type,
2764
+ output_format=output_format, extract_properties_func=self._extract_collection_properties,
2765
+ columns=columns if output_format == 'LIST' else None)
2766
+ else:
2767
+ return self.generate_basic_structured_output(elements, filter, output_format)
2768
+
2769
+
2770
+ # def generate_collection_output(self, elements, filter, collection_type: str, output_format,
2771
+ # output_profile: str = "CORE") -> str | list | dict:
2772
+ # """
2773
+ # Generate output in the specified format for the given elements.
2774
+ #
2775
+ # Args:
2776
+ # elements: Dictionary or list of dictionaries containing element data
2777
+ # filter: The search string used to find the elements
2778
+ # output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID, JSON)
2779
+ # output_profile: str, optional, default = "CORE"
2780
+ # The desired output profile - BASIC, CORE, FULL
2781
+ # Returns:
2782
+ # Formatted output as string or list of dictionaries
2783
+ # """
2784
+ # if collection_type is None:
2785
+ # entity_type = "Collection"
2786
+ # else:
2787
+ # entity_type = collection_type
2788
+ #
2789
+ # # For LIST and DICT formats, get member information
2790
+ #
2791
+ # if output_format in ["LIST", "DICT"]:
2792
+ # # Get the collection GUID
2793
+ # collection_guid = None
2794
+ # if isinstance(elements, dict):
2795
+ # collection_guid = elements.get('elementHeader', {}).get('guid')
2796
+ # elif isinstance(elements, list) and len(elements) > 0:
2797
+ # collection_guid = elements[0].get('elementHeader', {}).get('guid')
2798
+ #
2799
+ # # Get member list if we have a valid collection GUID
2800
+ # members = []
2801
+ # if collection_guid:
2802
+ # members = self.get_member_list(collection_guid=collection_guid)
2803
+ # if isinstance(members, str): # "No members found" case
2804
+ # members = []
2805
+ #
2806
+ # # For DICT format, include all member information in the result
2807
+ # if output_format == "DICT":
2808
+ # result = self.generate_basic_structured_output(elements, filter, output_format, collection_type)
2809
+ # if isinstance(result, list):
2810
+ # for item in result:
2811
+ # item['members'] = members
2812
+ # return result
2813
+ # elif isinstance(result, dict):
2814
+ # result['members'] = members
2815
+ # return result
2816
+ #
2817
+ # # For LIST format, add a column with bulleted list of qualified names
2818
+ # elif output_format == "LIST":
2819
+ # # Define columns for LIST format, including the new Members column
2820
+ # columns = [{'name': 'Collection Name', 'key': 'display_name'},
2821
+ # {'name': 'Qualified Name', 'key': 'qualified_name'},
2822
+ # {'name': 'Collection Type', 'key': 'collection_type'},
2823
+ # {'name': 'Description', 'key': 'description', 'format': True},
2824
+ # {'name': 'Classifications', 'key': 'classifications'},
2825
+ # {'name': 'Members', 'key': 'members', 'format': True}]
2826
+ #
2827
+ # # Create a function to add member information to the properties
2828
+ # def get_additional_props(element, guid, output_format):
2829
+ # if not members:
2830
+ # return {'members': ''}
2831
+ #
2832
+ # # Create a comma-separated list of qualified names (no newlines to avoid table formatting issues)
2833
+ # member_list = ", ".join([member.get('qualifiedName', '') for member in members])
2834
+ # return {'members': member_list}
2835
+ #
2836
+ # # Generate output with the additional properties
2837
+ #
2838
+ # return generate_output(elements=elements, search_string=filter, entity_type=entity_type,
2839
+ # output_format=output_format, extract_properties_func=self._extract_collection_properties,
2840
+ # get_additional_props_func=get_additional_props, columns=columns)
2841
+ #
2842
+ # # For FORM, REPORT, JSON formats, keep behavior unchanged
2843
+ # return self.generate_basic_structured_output(elements, filter, output_format, collection_type)
2796
2844
 
2797
2845
  # def generate_data_class_output(self, elements, filter, output_format) -> str | list: # return
2798
2846
  # self.generate_basic_structured_output(elements, filter, output_format) # # def generate_data_field_output(