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/__init__.py CHANGED
@@ -61,7 +61,7 @@ from .project_manager import ProjectManager
61
61
  from .registered_info import RegisteredInfo
62
62
  from .runtime_manager_omvs import RuntimeManager
63
63
  from .server_operations import ServerOps
64
- from .solution_architect_omvs import SolutionArchitect
64
+ from .solution_architect import SolutionArchitect
65
65
  from .utils import body_slimmer, print_response, to_pascal_case, to_camel_case, camel_to_title_case
66
66
  from .valid_metadata_omvs import ValidMetadataManager
67
67
  from .x_action_author_omvs import ActionAuthor
pyegeria/_client_new.py CHANGED
@@ -360,18 +360,20 @@ class Client2:
360
360
  """Retrieve and return the bearer token"""
361
361
  return self.text_headers["Authorization"]
362
362
 
363
- def get_platform_origin(self):
364
- """Validate platform connectivity"""
363
+ def get_platform_origin(self) -> str:
364
+ """Return the platform origin string if reachable.
365
+
366
+ Historically this method returned a boolean; tests and helpers expect the actual origin text.
367
+ """
365
368
  origin_url = f"{self.platform_url}/open-metadata/platform-services/users/{self.user_id}/server-platform/origin"
366
369
  response = self.make_request("GET", origin_url, is_json=False)
367
370
  if response.status_code == 200:
368
- logger.success(f"Got response from {origin_url}\n Response: {response.text}")
369
- if response.text.split()[0] == "Egeria":
370
- return True
371
- else:
372
- return False
371
+ text = response.text.strip()
372
+ logger.success(f"Got response from {origin_url}\n Response: {text}")
373
+ return text
373
374
  else:
374
375
  logger.info(f"Got response from {origin_url}\n status_code: {response.status_code}")
376
+ return ""
375
377
 
376
378
  # @logger.catch
377
379
  def make_request(
@@ -92,6 +92,7 @@ COMMON_COLUMNS = [
92
92
  Column(name='Qualified Name', key='qualified_name', format=True),
93
93
  Column(name='Category', key='category'),
94
94
  Column(name='Description', key='description', format=True),
95
+ Column(name='Status', key='status'),
95
96
  ]
96
97
 
97
98
  COMMON_METADATA_COLUMNS = [
@@ -513,13 +514,17 @@ output_format_sets = FormatSetDict({
513
514
  )
514
515
  ),
515
516
 
516
- "Data Structure": FormatSet(
517
+ "Data Structures": FormatSet(
517
518
  target_type="Data Structure",
518
519
  heading="Data Structure Information",
519
520
  description="Attributes useful to Data Structures.",
520
521
  aliases=["Data Structure", "DataStructures", "Data Structures", "Data Struct", "DataStructure"],
521
522
  annotations={"wikilinks": ["[[Data Structure]]"]},
522
- formats=[Format(types=["ALL"], columns=COMMON_COLUMNS)], # Reusing common formats and columns
523
+ formats=[Format(types=["ALL"], columns=COMMON_COLUMNS +
524
+ [
525
+ Column(name="Member Of", key='member_of_collections')
526
+ ]
527
+ )], # Reusing common formats and columns
523
528
  action=ActionParameter(
524
529
  function="DataDesigner.find_data_structures",
525
530
  required_params=["search_string"],
@@ -540,7 +545,90 @@ output_format_sets = FormatSetDict({
540
545
  spec_params={},
541
546
  )
542
547
  ),
543
-
548
+ "DataField-DrE": FormatSet(
549
+ target_type="Data Field",
550
+ heading="Data Field Information",
551
+ description="Attributes useful to Data Fields.",
552
+ aliases=[],
553
+ annotations={"wikilinks": ["[[Data Field]]"]},
554
+ formats=[Format(types=["ALL"], columns=COMMON_COLUMNS +
555
+ [Column(name='Data Type', key='data_type'),
556
+ Column(name='Position', key='position'),
557
+ Column(name='Minimum Cardinality', key='min_cardinality'),
558
+ Column(name='Maximum Cardinality', key='max_cardinality'),
559
+ Column(name='In Data Structure', key='data_structure_qnames'),
560
+ Column(name='Data Class', key='data_class'),
561
+ Column(name='Glossary Term', key='glossary_term'),
562
+ Column(name='Aliases', key='aliases'),
563
+ Column(name='Name Patterns', key='name_patterns'),
564
+ Column(name='Namespaces', key='namespaces'),
565
+ Column(name='IsNullable', key='is_nullable'),
566
+ Column(name='Minimum Length', key='min_length'),
567
+ Column(name='Length', key='length'),
568
+ Column(name='Precision', key='precision'),
569
+ Column(name='Ordered Values', key='ordered_values'),
570
+ Column(name='Units', key='units'),
571
+ Column(name='Sort Order', key='sort_order'),
572
+ Column(name='Default Value', key='default_value'),
573
+ Column(name='Version Identifier', key='version_identifier'),
574
+ Column(name='In Data Specification', key='member_of_data_spec_qnames'),
575
+ Column(name='In Data Dictionary', key='member_of_data_dicts_qnames'),
576
+ Column(name='Parent Data Field', key='parent_data_field'),
577
+ Column(name='Qualified Name', key='qualified_name'),
578
+ Column(name='GUID', key='GUID'),
579
+ Column(name ='Merge Update', key='merge_update'),
580
+ Column(name='Additional Properties', key='additional_properties'),
581
+ Column(name='Extended Properties', key='extended_properties'),
582
+ ])
583
+ ],
584
+ action=ActionParameter(
585
+ function="DataDesigner.find_data_fields",
586
+ required_params=["search_string"],
587
+ spec_params={},
588
+ )
589
+ ),
590
+ "DataClass-DrE": FormatSet(
591
+ target_type="Data Class",
592
+ heading="Data Class Information",
593
+ description="Attributes useful to Data Classes.",
594
+ aliases=[],
595
+ annotations={"wikilinks": ["[[Data Field]]"]},
596
+ formats=[Format(types=["ALL"], columns=COMMON_COLUMNS +
597
+ [Column(name='Namespaces', key='namespaces'),
598
+ Column(name='Match Property Names', key='match_property_names'),
599
+ Column(name='Match Threshold', key='match_threshold'),
600
+ Column(name='IsCaseSensitive', key='is_case_sensitive'),
601
+ Column(name='Specification', key='specification'),
602
+ Column(name='Specification Details', key='specification_details'),
603
+ Column(name='Data Type', key='data_type'),
604
+ Column(name='Allow Duplicate Values', key='allow_duplicate_values'),
605
+ Column(name='IsNullable', key='is_nullable'),
606
+ Column(name='IsCaseSensitive', key='is_case_sensitive'),
607
+ Column(name='Default Value', key='default_value'),
608
+ Column(name='Average Value', key='average_value'),
609
+ Column(name='Value List', key='value_list'),
610
+ Column(name='Value Range From', key='value_range_from'),
611
+ Column(name='Value Range To', key='value_range_to'),
612
+ Column(name='Sample Values', key='sample_values'),
613
+ Column(name='Data Patterns', key='data_patterns'),
614
+ Column(name='Glossary Term', key='glossary_term'),
615
+ Column(name='In Data Dictionary', key='in_data_dictionary'),
616
+ Column(name='Containing Data Class', key='containing_data_class'),
617
+ Column(name='Specialized Data Class', key='specialized_data_class'),
618
+ Column(name='Version Identifier', key='version_identifier'),
619
+ Column(name='Qualified Name', key='qualified_name'),
620
+ Column(name='GUID', key='GUID'),
621
+ Column(name ='Merge Update', key='merge_update'),
622
+ Column(name='Additional Properties', key='additional_properties'),
623
+ Column(name='Extended Properties', key='extended_properties'),
624
+ ])
625
+ ],
626
+ action=ActionParameter(
627
+ function="DataDesigner.find_data_fields",
628
+ required_params=["search_string"],
629
+ spec_params={},
630
+ )
631
+ ),
544
632
  "Mandy-DataStruct": FormatSet(
545
633
  target_type="Data Structure",
546
634
  heading="Puddy Approves",
@@ -559,6 +647,39 @@ output_format_sets = FormatSetDict({
559
647
  spec_params={"output_format":"DICT"},
560
648
  )
561
649
  ),
650
+ "DataStruct-DrE": FormatSet(
651
+ target_type="Data Structure",
652
+ heading="Data Structure Information",
653
+ description="Information used with Dr. Egeria to describe Data Structures.",
654
+ aliases=[],
655
+ annotations={"wikilinks": ["[[Data Structure]]"]},
656
+ formats=[
657
+ Format(types=["TABLE", "LIST"], columns=COMMON_COLUMNS + [
658
+ Column(name='Namespace', key='namespace'),
659
+ Column(name='In Data Specifications', key='member_of_data_spec_qnames'),
660
+ Column(name='In Data Dictionary', key='member_of_data_dicts_qnames'),
661
+ Column(name='Glossary Term', key='glossary_term'),
662
+ ]),
663
+ Format(types=["DICT", "MD"], columns=COMMON_COLUMNS + [
664
+ Column(name='Namespace', key='namespace'),
665
+ Column(name='In Data Specifications', key='member_of_data_spec_qnames'),
666
+ Column(name='In Data Dictionary', key='member_of_data_dicts_qnames'),
667
+ Column(name='Glossary Term', key='glossary_term'),
668
+ Column(name='GUID', key='GUID')]),
669
+ Format(types=["REPORT", "MERMAID", "HTML"], columns=COMMON_COLUMNS + [
670
+ Column(name='Namespace', key='namespace'),
671
+ Column(name='In Data Specifications', key='member_of_data_spec_qnames'),
672
+ Column(name='In Data Dictionary', key='member_of_data_dicts_qnames'),
673
+ Column(name='Glossary Term', key='glossary_term'),
674
+ Column(name='Mermaid', key='mermaid'),
675
+ Column(name='GUID', key='GUID')])
676
+ ],
677
+ action=ActionParameter(
678
+ function="DataDesigner.find_data_structures",
679
+ required_params=["search_string"],
680
+ spec_params={"output_format": "DICT"},
681
+ )
682
+ ),
562
683
  "Governance Basics": FormatSet(
563
684
  target_type="Governance Definition",
564
685
  heading="Basic Governance-Definitions Information",
@@ -25,7 +25,7 @@ from pyegeria.models import (SearchStringRequestBody, FilterRequestBody, GetRequ
25
25
  get_defined_field_values, PyegeriaModel)
26
26
  from pyegeria.output_formatter import (generate_output,
27
27
  _extract_referenceable_properties, populate_columns_from_properties,
28
- get_required_relationships)
28
+ get_required_relationships, populate_common_columns)
29
29
  from pyegeria.utils import body_slimmer, dynamic_catch
30
30
 
31
31
 
@@ -2680,7 +2680,7 @@ class CollectionManager(Client2):
2680
2680
  f"{self.platform_url}/servers/"
2681
2681
  f"{self.view_server}/api/open-metadata/collection-manager/collections/digital-products/"
2682
2682
  f"{upstream_digital_prod_guid}/product-dependencies/{downstream_digital_prod_guid}/attach")
2683
- await self._async_new_relationship_request(url, "InformationSupplyChainLinkProperties", body)
2683
+ await self._async_new_relationship_request(url, ["InformationSupplyChainLinkProperties"], body)
2684
2684
  logger.info(f"Linked {upstream_digital_prod_guid} -> {downstream_digital_prod_guid}")
2685
2685
 
2686
2686
 
@@ -5483,64 +5483,25 @@ class CollectionManager(Client2):
5483
5483
  return added_props
5484
5484
 
5485
5485
  def _extract_collection_properties(self, element: dict, columns_struct: dict) -> dict:
5486
- """
5487
- Extract common properties from a collection element and populate into the provided columns_struct.
5486
+ """Populate collection columns for output.
5488
5487
 
5489
- Args:
5490
- element (dict): The collection element
5491
- columns_struct (dict): The columns structure to populate
5488
+ Uses `populate_common_columns` to fill standard fields and derive requested relationships.
5492
5489
 
5493
- Returns:
5494
- dict: columns_struct with column 'value' fields populated
5495
- """
5496
- # First, populate from element.properties using the utility
5497
- col_data = populate_columns_from_properties(element, columns_struct)
5498
-
5499
- columns_list = col_data.get("formats", {}).get("columns", [])
5500
-
5501
- # Populate header-derived values
5502
- header_props = _extract_referenceable_properties(element)
5503
- for column in columns_list:
5504
- key = column.get('key')
5505
- if key in header_props:
5506
- column['value'] = header_props.get(key)
5507
- elif isinstance(key, str) and key.lower() == 'guid':
5508
- column['value'] = header_props.get('GUID')
5509
-
5510
- # Derived/computed fields
5511
- # collectionCategories are classifications
5512
- classification_names = ""
5513
- classifications = element.get('elementHeader', {}).get("collectionCategories", [])
5514
- for classification in classifications:
5515
- classification_names += f"{classification['classificationName']}, "
5516
- if classification_names:
5517
- for column in columns_list:
5518
- if column.get('key') == 'classifications':
5519
- column['value'] = classification_names[:-2]
5520
- break
5521
-
5522
- # Populate requested relationship-based columns generically from top-level keys
5523
- col_data = get_required_relationships(element, col_data)
5524
-
5525
- # Subject area classification
5526
- subject_area = element.get('elementHeader', {}).get("subjectArea", "") or ""
5527
- subj_val = ""
5528
- if isinstance(subject_area, dict):
5529
- subj_val = subject_area.get("classificationProperties", {}).get("subjectAreaName", "")
5530
- for column in columns_list:
5531
- if column.get('key') == 'subject_area':
5532
- column['value'] = subj_val
5533
- break
5534
-
5535
- # Mermaid graph
5536
- mermaid_val = element.get('mermaidGraph', "") or ""
5537
- for column in columns_list:
5538
- if column.get('key') == 'mermaid':
5539
- column['value'] = mermaid_val
5540
- break
5490
+ Parameters
5491
+ ----------
5492
+ element : dict
5493
+ Raw element from the OMVS.
5494
+ columns_struct : dict
5495
+ Format-set structure whose columns' `value` fields will be populated.
5541
5496
 
5497
+ Returns
5498
+ -------
5499
+ dict
5500
+ The same columns_struct with populated values.
5501
+ """
5502
+ # Use centralized common population
5503
+ col_data = populate_common_columns(element, columns_struct)
5542
5504
  logger.trace(f"Extracted/Populated columns: {col_data}")
5543
-
5544
5505
  return col_data
5545
5506
 
5546
5507
 
pyegeria/config.py CHANGED
@@ -25,6 +25,7 @@ import inspect
25
25
  import os
26
26
  import json
27
27
  from typing import List, Optional, Union, Dict, Any
28
+ import sys
28
29
 
29
30
  from loguru import logger
30
31
  from pydantic import BaseModel, Field, validator, ConfigDict
@@ -36,6 +37,12 @@ logger.disable("pyegeria")
36
37
  # --- Pydantic Settings for Environment Variables ---
37
38
 
38
39
  class PyegeriaSettings(BaseSettings):
40
+ """Top-level environment settings for pyegeria.
41
+
42
+ This class centralizes discovery of important filesystem paths and default
43
+ configuration values. It can be constructed directly or via `with_env_file`
44
+ to load overrides from a specific .env-like file.
45
+ """
39
46
  """
40
47
  Settings loaded from environment variables using pydantic-settings.
41
48
  This class is used to load environment variables from the .env file.
@@ -89,6 +96,7 @@ class PyegeriaSettings(BaseSettings):
89
96
  # --- Pydantic Models for Configuration ---
90
97
 
91
98
  class EnvironmentConfig(BaseModel):
99
+ """Runtime environment parameters that influence formatting and behavior."""
92
100
  """Environment configuration settings"""
93
101
  console_width: int = Field(default=200, alias="Console Width")
94
102
  dr_egeria_inbox: str = Field(default="md_processing/dr-egeria-inbox", alias="Dr.Egeria Inbox")
@@ -149,6 +157,7 @@ class UserProfileConfig(BaseModel):
149
157
 
150
158
 
151
159
  class AppConfig(BaseModel):
160
+ """Aggregated application configuration used by pyegeria components."""
152
161
  """Main application configuration"""
153
162
  Environment: EnvironmentConfig
154
163
  Debug: DebugConfig
@@ -333,7 +342,7 @@ def load_app_config(env_file: str | None = None):
333
342
  )
334
343
  log["logging_file_format"] = os.getenv(
335
344
  "PYEGERIA_LOGGING_FILE_FORMAT",
336
- log.get("logging_file_format", " {time:YYYY-MM-DD HH:mm:ss} | {level} | {function}:{line} - {message }-{extra}"),
345
+ log.get("logging_file_format", " {time:YYYY-MM-DD HH:mm:ss} | {level} | {function}:{line} - {message}-{extra}"),
337
346
  )
338
347
 
339
348
  # User Profile