pyegeria 5.4.3.2__py3-none-any.whl → 5.4.3.4__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 (53) hide show
  1. commands/cat/debug_log.2025-09-01_07-02-58_818650.log.zip +0 -0
  2. commands/cat/debug_log.2025-09-02_07-44-39_567276.log.zip +0 -0
  3. commands/cat/debug_log.2025-09-03_07-45-21_986388.log.zip +0 -0
  4. commands/cat/debug_log.log +5379 -8107
  5. commands/cat/list_format_set.py +2 -2
  6. commands/tech/list_information_supply_chains.py +1 -1
  7. commands/tech/list_solution_blueprints.py +1 -1
  8. commands/tech/list_solution_components.py +1 -1
  9. commands/tech/list_solution_roles.py +1 -1
  10. md_processing/__init__.py +0 -4
  11. md_processing/data/commands.json +1258 -615
  12. md_processing/dr_egeria.py +6 -9
  13. md_processing/dr_egeria_inbox/data_spec_test.md +44 -418
  14. md_processing/dr_egeria_inbox/gov_def.md +239 -3
  15. md_processing/dr_egeria_inbox/product.md +13 -5
  16. md_processing/dr_egeria_outbox/monday/processed-2025-09-01 14:03-product.md +209 -0
  17. md_processing/dr_egeria_outbox/monday/processed-2025-09-01 14:24-product.md +263 -0
  18. md_processing/dr_egeria_outbox/monday/processed-2025-09-01 16:03-data_spec_test.md +2374 -0
  19. md_processing/dr_egeria_outbox/monday/processed-2025-09-01 16:05-data_spec_test.md +2374 -0
  20. md_processing/dr_egeria_outbox/monday/processed-2025-09-02 08:28-data_spec_test.md +2321 -0
  21. md_processing/dr_egeria_outbox/monday/processed-2025-09-02 08:37-data_spec_test.md +2304 -0
  22. md_processing/dr_egeria_outbox/monday/processed-2025-09-02 08:56-data_spec_test.md +2324 -0
  23. md_processing/dr_egeria_outbox/monday/processed-2025-09-02 09:00-data_spec_test.md +2324 -0
  24. md_processing/md_commands/data_designer_commands.py +170 -570
  25. md_processing/md_commands/product_manager_commands.py +1 -1
  26. md_processing/md_processing_utils/common_md_utils.py +55 -13
  27. md_processing/md_processing_utils/extraction_utils.py +14 -7
  28. md_processing/md_processing_utils/md_processing_constants.py +1 -1
  29. pyegeria/___external_references.py +3255 -0
  30. pyegeria/__init__.py +1 -1
  31. pyegeria/_client_new.py +9 -7
  32. pyegeria/_output_formats.py +124 -3
  33. pyegeria/collection_manager.py +17 -56
  34. pyegeria/config.py +10 -1
  35. pyegeria/data_designer.py +172 -124
  36. pyegeria/egeria_client.py +1 -1
  37. pyegeria/egeria_tech_client.py +1 -1
  38. pyegeria/glossary_manager.py +71 -85
  39. pyegeria/governance_officer.py +26 -29
  40. pyegeria/output_formatter.py +127 -1
  41. pyegeria/project_manager.py +33 -36
  42. pyegeria/{solution_architect_omvs.py → solution_architect.py} +443 -388
  43. {pyegeria-5.4.3.2.dist-info → pyegeria-5.4.3.4.dist-info}/METADATA +1 -1
  44. {pyegeria-5.4.3.2.dist-info → pyegeria-5.4.3.4.dist-info}/RECORD +47 -41
  45. md_processing/dr_egeria_outbox/friday/processed-2025-08-29 16:30-output_tests.md +0 -103
  46. md_processing/dr_egeria_outbox/friday/processed-2025-08-29 16:40-output_tests.md +0 -115
  47. md_processing/dr_egeria_outbox/friday/processed-2025-08-30 21:15-glossary_test1.md +0 -326
  48. md_processing/dr_egeria_outbox/friday/processed-2025-08-31 13:27-glossary_test1.md +0 -369
  49. md_processing/dr_egeria_outbox/friday/processed-2025-08-31 13:33-glossary_test1.md +0 -392
  50. md_processing/dr_egeria_outbox/friday/processed-2025-08-31 20:57-glossary_test1.md +0 -400
  51. {pyegeria-5.4.3.2.dist-info → pyegeria-5.4.3.4.dist-info}/LICENSE +0 -0
  52. {pyegeria-5.4.3.2.dist-info → pyegeria-5.4.3.4.dist-info}/WHEEL +0 -0
  53. {pyegeria-5.4.3.2.dist-info → pyegeria-5.4.3.4.dist-info}/entry_points.txt +0 -0
pyegeria/data_designer.py CHANGED
@@ -18,7 +18,8 @@ from pyegeria.models import (SearchStringRequestBody, FilterRequestBody, GetRequ
18
18
  TemplateRequestBody,
19
19
  UpdateElementRequestBody, NewRelationshipRequestBody,
20
20
  DeleteRequestBody)
21
- from pyegeria.output_formatter import (extract_mermaid_only, extract_basic_dict)
21
+ from pyegeria.output_formatter import (extract_mermaid_only, extract_basic_dict, populate_columns_from_properties,
22
+ get_required_relationships, populate_common_columns)
22
23
  from pyegeria.output_formatter import (generate_output,
23
24
  _extract_referenceable_properties)
24
25
  from pyegeria.utils import body_slimmer, dynamic_catch
@@ -1296,13 +1297,11 @@ class DataDesigner(Client2):
1296
1297
 
1297
1298
  member_of_collections = el_struct.get("memberOfCollections", {})
1298
1299
  for collection in member_of_collections:
1299
- c_type = collection["relatedElement"]["properties"].get("collectionType", "") or ""
1300
+ type_name = collection["relatedElement"]["elementHeader"]["type"].get("typeName", "") or ""
1300
1301
  guid = collection["relatedElement"]["elementHeader"]["guid"]
1301
- name = collection["relatedElement"]["properties"].get("name", "") or ""
1302
+ name = collection["relatedElement"]["properties"].get("displayName", "") or ""
1302
1303
  qualifiedName = collection['relatedElement']["properties"].get("qualifiedName", "") or ""
1303
- classifications = collection["relatedElement"]["elementHeader"]["classifications"]
1304
- for classification in classifications:
1305
- type_name = classification["type"]['typeName']
1304
+ if type_name:
1306
1305
  if type_name == "DataDictionary":
1307
1306
  member_of_data_dicts_guids.append(guid)
1308
1307
  member_of_data_dicts_names.append(name)
@@ -2517,7 +2516,7 @@ class DataDesigner(Client2):
2517
2516
 
2518
2517
  loop = asyncio.get_event_loop()
2519
2518
  response = loop.run_until_complete(
2520
- self._async_get_data_fields_by_name(filter, classification_names, body, start_from, page_size,
2519
+ self._async_get_data_fields_by_name(filter_string, classification_names, body, start_from, page_size,
2521
2520
  output_format, output_format_set))
2522
2521
  return response
2523
2522
 
@@ -4682,120 +4681,163 @@ class DataDesigner(Client2):
4682
4681
 
4683
4682
 
4684
4683
 
4685
- def _extract_data_structure_properties(self, element: dict) -> dict:
4686
- """
4687
- Extract common properties from a data structure element.
4688
-
4689
- Args:
4690
- element (dict): The data structure element
4691
-
4692
- Returns:
4693
- dict: Dictionary of extracted properties
4694
- """
4695
- props = _extract_referenceable_properties(element)
4696
-
4697
- props['properties'] = element.get('properties', {})
4698
-
4699
- props['namespace'] = props['properties'].get("namespace", "") or ""
4700
-
4701
- classification_names = []
4702
- for c in props['classifications']:
4703
- classification_names.append(c.get("classificationName", None))
4704
- props['classifications'] = classification_names
4705
-
4706
- # Now lets get the related elements
4707
- associated_elements = self.get_data_rel_elements_dict(element)
4708
- props['data_specs'] = associated_elements.get("member_of_data_spec_qnames", [])
4709
-
4710
- # data_structures = associated_elements.get("member_of_data_struct_qnames", [])
4711
- props['assigned_meanings'] = associated_elements.get("assigned_meanings_qnames", [])
4712
- props['parent_names'] = associated_elements.get("parent_qnames", [])
4713
- props['member_data_fields'] = associated_elements.get("member_data_field_qnames", [])
4714
-
4715
- props['mermaid'] = element.get('mermaidGraph', "") or ""
4716
-
4717
- return props
4718
-
4719
- def _extract_data_class_properties(self, element: dict) -> dict:
4720
- """
4721
- Extract common properties from a data class element.
4722
-
4723
- Args:
4724
- element (dict): The data class element
4725
-
4726
- Returns:
4727
- dict: Dictionary of extracted properties
4728
- """
4729
- props = _extract_referenceable_properties(element)
4730
- properties = element.get('properties', {})
4731
- props['properties'] = properties
4732
-
4733
- classification_names = []
4734
- for c in props['classifications']:
4735
- classification_names.append(c.get("classificationName", None))
4736
- props['classifications'] = classification_names
4737
-
4738
- props['namespace'] = props['properties'].get("namespace", "") or ""
4739
-
4740
- props['data_type'] = properties.get('dataType', "") or ""
4741
- props['match_property_names'] = properties.get('matchPropertyNames', []) or []
4742
- props['match_threshold'] = properties.get('matchThreshold', 0)
4743
- props['allow_duplicate_values'] = properties.get('allowDuplicateValues', False)
4744
- props['is_case_sensitive'] = properties.get('isCaseSensitive', False)
4745
- props['is_nullable'] = properties.get('isNullable', False)
4746
-
4747
- # Now lets get the related elements
4748
- associated_elements = self.get_data_rel_elements_dict(element)
4749
- props['data_dictionaries'] = associated_elements.get("member_of_data_dicts_qnames", [])
4750
- props['assigned_meanings'] = associated_elements.get("assigned_meanings_qnames", [])
4751
- props['parent_names'] = associated_elements.get("parent_qnames", [])
4752
- props['nested_data_classes'] = associated_elements.get("nested_data_class_qnames", [])
4753
- props['specialized_data_classes'] = associated_elements.get("specialized_data_class_qnames", [])
4754
- props['mermaid'] = element.get('mermaidGraph', "") or ""
4755
-
4756
- return props
4757
-
4758
- def _extract_data_field_properties(self, element: dict) -> dict:
4759
- """
4760
- Extract common properties from a data field element.
4761
-
4762
- Args:
4763
- element (dict): The data field element
4764
-
4765
- Returns:
4766
- dict: Dictionary of extracted properties
4767
- """
4768
- props = _extract_referenceable_properties(element)
4769
-
4770
- props['properties'] = element.get('properties', {})
4771
- props['namespace'] = props['properties'].get("namespace", "") or ""
4772
- properties = element.get('properties', {})
4773
-
4774
- classification_names = []
4775
- for c in props['classifications']:
4776
- classification_names.append(c.get("classificationName", None))
4777
- props['classifications'] = classification_names
4778
-
4779
- props['is_nullable'] = properties.get('isNullable', False)
4780
- props['data_type'] = properties.get('dataType', "") or ""
4781
- props['minimum_length'] = properties.get('minimumLength', 0)
4782
- props['length'] = properties.get('length', 0)
4783
- props['precision'] = properties.get('precision', 0)
4784
- props['ordered_values'] = properties.get('orderedValues', False)
4785
- props['sort_order'] = properties.get('sortOrder', "") or ""
4786
-
4787
- # Now lets get the related elements
4788
- associated_elements = self.get_data_rel_elements_dict(element)
4789
- props['data_dictionaries'] = associated_elements.get("member_of_data_dicts_qnames", [])
4790
- props['data_structures'] = associated_elements.get("data_structure_qnames", [])
4791
- props['assigned_meanings'] = associated_elements.get("assigned_meanings_qnames", [])
4792
- props['parent_names'] = associated_elements.get("parent_qnames", [])
4793
- props['data_class'] = associated_elements.get("data_class_qnames", [])
4794
- props['mermaid'] = element.get('mermaidGraph', "") or ""
4795
-
4796
- return props
4797
-
4798
- def _generate_basic_structured_output(self, elements: dict, filter: str, output_format: str,
4684
+ def _extract_data_structure_properties(self, element: dict, columns_struct: dict) -> dict:
4685
+ """Extractor for Data Structure elements with related overlay.
4686
+
4687
+ Pattern:
4688
+ - Populate common columns via populate_common_columns.
4689
+ - Derive related properties using get_data_rel_elements_dict from the element body.
4690
+ - Overlay values into matching columns' 'value' fields, handling formats as list or dict.
4691
+ - Return the enriched columns_struct.
4692
+ """
4693
+ col_data = populate_common_columns(element, columns_struct)
4694
+
4695
+ try:
4696
+ related_map = self.get_data_rel_elements_dict(element)
4697
+ except Exception:
4698
+ related_map = {}
4699
+
4700
+ if isinstance(related_map, dict) and related_map:
4701
+ try:
4702
+ formats = col_data.get("formats") if isinstance(col_data, dict) else None
4703
+ if isinstance(formats, list):
4704
+ targets = formats
4705
+ elif isinstance(formats, dict):
4706
+ inner = formats.get("formats") if isinstance(formats.get("formats"), (dict, list)) else None
4707
+ if isinstance(inner, list):
4708
+ targets = inner
4709
+ elif isinstance(inner, dict):
4710
+ targets = [inner]
4711
+ else:
4712
+ targets = [formats]
4713
+ else:
4714
+ targets = []
4715
+
4716
+ if targets:
4717
+ for fmt in targets:
4718
+ cols = fmt.get("columns", []) if isinstance(fmt, dict) else []
4719
+ for col in cols:
4720
+ key = col.get("key") if isinstance(col, dict) else None
4721
+ if key and key in related_map:
4722
+ col["value"] = related_map.get(key)
4723
+ else:
4724
+ cols = col_data.get("columns", []) if isinstance(col_data, dict) else []
4725
+ for col in cols:
4726
+ key = col.get("key") if isinstance(col, dict) else None
4727
+ if key and key in related_map:
4728
+ col["value"] = related_map.get(key)
4729
+ except Exception:
4730
+ pass
4731
+
4732
+ return col_data
4733
+
4734
+
4735
+ def _extract_data_class_properties(self, element: dict,columns_struct: dict) -> dict:
4736
+ """Extractor for Data Class elements with related overlay, mirroring Data Field pattern."""
4737
+ col_data = populate_common_columns(element, columns_struct)
4738
+
4739
+ try:
4740
+ related_map = self.get_data_rel_elements_dict(element)
4741
+ except Exception:
4742
+ related_map = {}
4743
+
4744
+ if isinstance(related_map, dict) and related_map:
4745
+ try:
4746
+ formats = col_data.get("formats") if isinstance(col_data, dict) else None
4747
+ if isinstance(formats, list):
4748
+ targets = formats
4749
+ elif isinstance(formats, dict):
4750
+ inner = formats.get("formats") if isinstance(formats.get("formats"), (dict, list)) else None
4751
+ if isinstance(inner, list):
4752
+ targets = inner
4753
+ elif isinstance(inner, dict):
4754
+ targets = [inner]
4755
+ else:
4756
+ targets = [formats]
4757
+ else:
4758
+ targets = []
4759
+
4760
+ if targets:
4761
+ for fmt in targets:
4762
+ cols = fmt.get("columns", []) if isinstance(fmt, dict) else []
4763
+ for col in cols:
4764
+ key = col.get("key") if isinstance(col, dict) else None
4765
+ if key and key in related_map:
4766
+ col["value"] = related_map.get(key)
4767
+ else:
4768
+ cols = col_data.get("columns", []) if isinstance(col_data, dict) else []
4769
+ for col in cols:
4770
+ key = col.get("key") if isinstance(col, dict) else None
4771
+ if key and key in related_map:
4772
+ col["value"] = related_map.get(key)
4773
+ except Exception:
4774
+ pass
4775
+
4776
+ return col_data
4777
+
4778
+ def _extract_data_field_properties(self, element: dict, columns_struct: dict) -> dict:
4779
+ """Extractor for Data Field elements.
4780
+
4781
+ Steps:
4782
+ - Populate base/referenceable/common properties into columns_struct via populate_common_columns.
4783
+ - Derive related properties using get_data_rel_elements_dict from the element body.
4784
+ - For each column in columns_struct, if its 'key' matches a key from the related dict, set its 'value'.
4785
+ - Return the enriched columns_struct.
4786
+ """
4787
+ # 1) Populate common columns first (header, properties, basic relationships, mermaid)
4788
+ col_data = populate_common_columns(element, columns_struct)
4789
+
4790
+ # 2) Build a map of related properties/elements from the body. The Data Designer methods
4791
+ # return a body that may include keys like assignedMeanings, otherRelatedElements,
4792
+ # memberOfCollections, memberDataFields, assignedDataClasses, nestedDataClasses, etc.
4793
+ try:
4794
+ related_map = self.get_data_rel_elements_dict(element)
4795
+ except Exception:
4796
+ related_map = {}
4797
+
4798
+ if isinstance(related_map, dict) and related_map:
4799
+ # 3) Walk the configured columns and overlay values when the key matches an entry from related_map
4800
+ try:
4801
+ formats = col_data.get("formats") if isinstance(col_data, dict) else None
4802
+ if isinstance(formats, list):
4803
+ targets = formats
4804
+ elif isinstance(formats, dict):
4805
+ # Handle dict variant. It may be a single format dict or a wrapper containing 'formats'.
4806
+ # Examples seen:
4807
+ # { 'columns': [...] }
4808
+ # { 'types': 'ALL', 'columns': [...] }
4809
+ # { 'formats': { 'columns': [...] } }
4810
+ inner = formats.get("formats") if isinstance(formats.get("formats"), dict | list) else None
4811
+ if isinstance(inner, list):
4812
+ targets = inner
4813
+ elif isinstance(inner, dict):
4814
+ targets = [inner]
4815
+ else:
4816
+ targets = [formats]
4817
+ else:
4818
+ targets = []
4819
+
4820
+ if targets:
4821
+ for fmt in targets:
4822
+ cols = fmt.get("columns", []) if isinstance(fmt, dict) else []
4823
+ for col in cols:
4824
+ key = col.get("key") if isinstance(col, dict) else None
4825
+ if key and key in related_map:
4826
+ col["value"] = related_map.get(key)
4827
+ else:
4828
+ # If columns are on the top-level (non-standard), attempt to handle gracefully
4829
+ cols = col_data.get("columns", []) if isinstance(col_data, dict) else []
4830
+ for col in cols:
4831
+ key = col.get("key") if isinstance(col, dict) else None
4832
+ if key and key in related_map:
4833
+ col["value"] = related_map.get(key)
4834
+ except Exception:
4835
+ # Do not fail rendering due to overlay issues; keep the base columns
4836
+ pass
4837
+
4838
+ return col_data
4839
+
4840
+ def _generate_basic_structured_output(self, elements: dict, filter: str, type: str = None ,output_format: str = 'DICT',
4799
4841
  columns_struct: dict = None) -> str | list:
4800
4842
  """
4801
4843
  Generate output in the specified format for the given elements.
@@ -4837,7 +4879,7 @@ class DataDesigner(Client2):
4837
4879
  columns_struct,
4838
4880
  )
4839
4881
 
4840
- def _generate_data_structure_output(self, elements: dict | list[dict], filter: str = None,
4882
+ def _generate_data_structure_output(self, elements: dict | list[dict], filter: str = None, type: str = None,
4841
4883
  output_format: str = "DICT",
4842
4884
  output_format_set: str | dict = None) -> str | list:
4843
4885
  """
@@ -4872,7 +4914,7 @@ class DataDesigner(Client2):
4872
4914
  output_formats,
4873
4915
  )
4874
4916
 
4875
- def _generate_data_class_output(self, elements: dict | list[dict], filter: str = None, output_format: str = "DICT",
4917
+ def _generate_data_class_output(self, elements: dict | list[dict], filter: str = None, type: str = None, output_format: str = "DICT",
4876
4918
  output_format_set: str | dict = None) -> str | list:
4877
4919
  """
4878
4920
  Generate output for data classes in the specified format.
@@ -4907,7 +4949,7 @@ class DataDesigner(Client2):
4907
4949
  output_formats,
4908
4950
  )
4909
4951
 
4910
- def _generate_data_field_output(self, elements: dict | list[dict], filter: str = None, output_format: str = "DICT",
4952
+ def _generate_data_field_output(self, elements: dict | list[dict], filter: str = None, type: str = None, output_format: str = "DICT",
4911
4953
  output_format_set: str | dict = None) -> str | list:
4912
4954
  """
4913
4955
  Generate output for data fields in the specified format.
@@ -4943,6 +4985,12 @@ class DataDesigner(Client2):
4943
4985
  output_formats,
4944
4986
  )
4945
4987
 
4988
+ def _extract_additional_data_struct_properties(self, element, columns_struct):
4989
+ return None
4990
+ def _extract_additional_data_field_properties(self, element, columns_struct):
4991
+ return None
4992
+ def _extract_additional_data_class_properties(self, element, columns_struct):
4993
+ return None
4946
4994
 
4947
4995
  if __name__ == "__main__":
4948
4996
  print("Data Designer")
pyegeria/egeria_client.py CHANGED
@@ -24,7 +24,7 @@ from pyegeria.full_omag_server_config import FullServerConfig
24
24
  from pyegeria.metadata_explorer_omvs import MetadataExplorer
25
25
  from pyegeria.my_profile_omvs import MyProfile
26
26
  from pyegeria.feedback_manager_omvs import FeedbackManager
27
- from pyegeria.solution_architect_omvs import SolutionArchitect
27
+ from pyegeria.solution_architect import SolutionArchitect
28
28
  from pyegeria.server_operations import ServerOps
29
29
  from pyegeria.registered_info import RegisteredInfo
30
30
  from pyegeria.valid_metadata_omvs import ValidMetadataManager
@@ -12,7 +12,7 @@ from pyegeria.egeria_cat_client import EgeriaCat
12
12
  from pyegeria.metadata_explorer_omvs import MetadataExplorer
13
13
  from pyegeria.registered_info import RegisteredInfo
14
14
  from pyegeria.runtime_manager_omvs import RuntimeManager
15
- from pyegeria.solution_architect_omvs import SolutionArchitect
15
+ from pyegeria.solution_architect import SolutionArchitect
16
16
  from pyegeria.template_manager_omvs import TemplateManager
17
17
  from pyegeria.valid_metadata_omvs import ValidMetadataManager
18
18
  from pyegeria.governance_officer import GovernanceOfficer
@@ -30,7 +30,7 @@ from pyegeria.models import (NewElementRequestBody,
30
30
  from pyegeria._output_formats import select_output_format_set, get_output_format_type_match
31
31
  from pyegeria.output_formatter import (generate_output,
32
32
  _extract_referenceable_properties, populate_columns_from_properties,
33
- get_required_relationships)
33
+ get_required_relationships, populate_common_columns, overlay_additional_values, resolve_output_formats)
34
34
  from pyegeria.utils import body_slimmer, dynamic_catch
35
35
 
36
36
  EGERIA_LOCAL_QUALIFIER = app_settings.User_Profile.egeria_local_qualifier
@@ -2527,84 +2527,90 @@ class GlossaryManager(CollectionManager):
2527
2527
  #
2528
2528
 
2529
2529
  def _extract_glossary_properties(self, element: dict, columns_struct: dict) -> dict:
2530
- props = element.get('properties', {}) or {}
2531
- normalized = {
2532
- 'properties': props,
2533
- 'elementHeader': element.get('elementHeader', {}),
2534
- }
2535
- col_data = populate_columns_from_properties(normalized, columns_struct)
2536
- columns_list = col_data.get('formats', {}).get('columns', [])
2530
+ """Extract glossary columns for rendering.
2531
+
2532
+ This extractor uses `populate_common_columns` for standard fields (properties, header, relationships,
2533
+ subject area, mermaid). It then overlays glossary-specific values such as:
2534
+ - categories_names: comma/newline separated Display Names of categories in the glossary
2535
+ - categories_qualified_names: comma/newline separated Qualified Names of categories in the glossary
2536
+
2537
+ Parameters
2538
+ ----------
2539
+ element : dict
2540
+ Raw element as returned by the OMVS.
2541
+ columns_struct : dict
2542
+ The selected output format structure (from _output_formats), whose columns' `value` fields will be filled.
2543
+
2544
+ Returns
2545
+ -------
2546
+ dict
2547
+ The same columns_struct with values populated. Non-empty values are not overwritten.
2548
+ """
2549
+ # Common population first
2550
+ col_data = populate_common_columns(element, columns_struct)
2551
+ # Overlay glossary-specific extras: categories lists
2537
2552
  header_props = _extract_referenceable_properties(element)
2538
2553
  guid = header_props.get('GUID')
2539
- for column in columns_list:
2540
- key = column.get('key')
2541
- if key in header_props:
2542
- column['value'] = header_props.get(key)
2543
- elif isinstance(key, str) and key.lower() == 'guid':
2544
- column['value'] = guid
2554
+ extra: dict = {}
2545
2555
  if guid:
2546
- categories = None
2547
2556
  try:
2548
2557
  categories = self.get_categories_for_glossary(guid)
2549
2558
  except Exception:
2550
2559
  categories = None
2551
- cat_display_list = []
2552
- cat_qn_list = []
2553
2560
  if isinstance(categories, list):
2561
+ cat_display_list = []
2562
+ cat_qn_list = []
2554
2563
  for category in categories:
2555
2564
  gcp = category.get('glossaryCategoryProperties', {})
2556
- dn = gcp.get('displayName', '') or ''
2557
- qn = gcp.get('qualifiedName', '') or ''
2565
+ dn = (gcp.get('displayName') or '')
2566
+ qn = (gcp.get('qualifiedName') or '')
2558
2567
  if dn:
2559
2568
  cat_display_list.append(dn)
2560
2569
  if qn:
2561
2570
  cat_qn_list.append(qn)
2562
- cat_names_md = (", \n".join(cat_display_list)).rstrip(',') if cat_display_list else ''
2563
- cat_qn_md = (", \n".join(cat_qn_list)).rstrip(',') if cat_qn_list else ''
2564
- for column in columns_list:
2565
- if column.get('key') == 'categories_names' and not column.get('value'):
2566
- column['value'] = cat_names_md
2567
- if column.get('key') == 'categories_qualified_names' and not column.get('value'):
2568
- column['value'] = cat_qn_md
2569
- for column in columns_list:
2570
- if column.get('key') == 'mermaid' and not column.get('value'):
2571
- column['value'] = element.get('mermaidGraph', '') or ''
2572
- break
2573
- return col_data
2571
+ if cat_display_list:
2572
+ extra['categories_names'] = ", \n".join(cat_display_list)
2573
+ if cat_qn_list:
2574
+ extra['categories_qualified_names'] = ", \n".join(cat_qn_list)
2575
+ return overlay_additional_values(col_data, extra)
2574
2576
 
2575
2577
  def _extract_term_properties(self, element: dict, columns_struct: dict) -> dict:
2576
- col_data = populate_columns_from_properties(element, columns_struct)
2577
- columns_list = col_data.get("formats", {}).get("columns", [])
2578
- header_props = _extract_referenceable_properties(element)
2579
- for column in columns_list:
2580
- key = column.get('key')
2581
- if key in header_props:
2582
- column['value'] = header_props.get(key)
2583
- elif isinstance(key, str) and key.lower() == 'guid':
2584
- column['value'] = header_props.get('GUID')
2585
- classification_names = ""
2586
- classifications = element.get('elementHeader', {}).get("collectionCategories", [])
2587
- for classification in classifications:
2588
- classification_names += f"{classification['classificationName']}, "
2589
- if classification_names:
2590
- for column in columns_list:
2591
- if column.get('key') == 'classifications':
2592
- column['value'] = classification_names[:-2]
2593
- break
2594
- col_data = get_required_relationships(element, col_data)
2595
- subject_area = element.get('elementHeader', {}).get("subjectArea", "") or ""
2596
- subj_val = ""
2597
- if isinstance(subject_area, dict):
2598
- subj_val = subject_area.get("classificationProperties", {}).get("subjectAreaName", "")
2599
- for column in columns_list:
2600
- if column.get('key') == 'subject_area':
2601
- column['value'] = subj_val
2602
- break
2603
- mermaid_val = element.get('mermaidGraph', "") or ""
2604
- for column in columns_list:
2605
- if column.get('key') == 'mermaid':
2606
- column['value'] = mermaid_val
2607
- break
2578
+ """Extract glossary term columns for rendering.
2579
+
2580
+ Populates standard columns via `populate_common_columns`, and if requested by the
2581
+ selected columns, derives a classifications string (from `elementHeader.collectionCategories`)
2582
+ into the `classifications` column.
2583
+
2584
+ Parameters
2585
+ ----------
2586
+ element : dict
2587
+ Raw term element returned by the OMVS.
2588
+ columns_struct : dict
2589
+ The chosen format-set structure whose column `value`s will be set.
2590
+
2591
+ Returns
2592
+ -------
2593
+ dict
2594
+ The same `columns_struct` with values populated.
2595
+ """
2596
+ # Use centralized population
2597
+ col_data = populate_common_columns(element, columns_struct)
2598
+ # Term-specific classifications (collectionCategories) to 'classifications' column
2599
+ columns_list = col_data.get('formats', {}).get('columns', [])
2600
+ try:
2601
+ classification_names = ""
2602
+ classifications = element.get('elementHeader', {}).get("collectionCategories", [])
2603
+ for classification in classifications:
2604
+ nm = classification.get('classificationName')
2605
+ if nm:
2606
+ classification_names += f"{nm}, "
2607
+ if classification_names:
2608
+ for column in columns_list:
2609
+ if column.get('key') == 'classifications' and column.get('value') in (None, ""):
2610
+ column['value'] = classification_names[:-2]
2611
+ break
2612
+ except Exception:
2613
+ pass
2608
2614
  return col_data
2609
2615
 
2610
2616
  def _get_term_additional_properties(self, element: dict, term_guid: str, output_format: str = None) -> dict:
@@ -2650,17 +2656,7 @@ class GlossaryManager(CollectionManager):
2650
2656
  output_format: str = 'DICT',
2651
2657
  output_format_set: dict | str = None) -> str | list[dict]:
2652
2658
  entity_type = 'Glossary'
2653
- if output_format_set:
2654
- if isinstance(output_format_set, str):
2655
- output_formats = select_output_format_set(output_format_set, output_format)
2656
- elif isinstance(output_format_set, dict):
2657
- output_formats = get_output_format_type_match(output_format_set, output_format)
2658
- else:
2659
- output_formats = None
2660
- else:
2661
- output_formats = select_output_format_set(entity_type, output_format)
2662
- if output_formats is None:
2663
- output_formats = select_output_format_set('Default', output_format)
2659
+ output_formats = resolve_output_formats(entity_type, output_format, output_format_set)
2664
2660
  return generate_output(
2665
2661
  elements=elements,
2666
2662
  search_string=search_string,
@@ -2676,17 +2672,7 @@ class GlossaryManager(CollectionManager):
2676
2672
  output_format: str = 'DICT',
2677
2673
  output_format_set: dict | str = None) -> str | list[dict]:
2678
2674
  entity_type = 'GlossaryTerm'
2679
- if output_format_set:
2680
- if isinstance(output_format_set, str):
2681
- output_formats = select_output_format_set(output_format_set, output_format)
2682
- elif isinstance(output_format_set, dict):
2683
- output_formats = get_output_format_type_match(output_format_set, output_format)
2684
- else:
2685
- output_formats = None
2686
- else:
2687
- output_formats = select_output_format_set(entity_type, output_format)
2688
- if output_formats is None:
2689
- output_formats = select_output_format_set('Default', output_format)
2675
+ output_formats = resolve_output_formats(entity_type, output_format, output_format_set)
2690
2676
  return generate_output(
2691
2677
  elements=elements,
2692
2678
  search_string=search_string,