pyegeria 5.4.0.dev11__py3-none-any.whl → 5.4.0.dev12__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 +6004 -19655
  2. commands/cat/debug_log.2025-07-01_15-22-20_102237.zip +0 -0
  3. commands/cat/debug_log.2025-07-04_15-43-28_460900.zip +0 -0
  4. commands/cat/debug_log.2025-07-06_20-48-04_338314.zip +0 -0
  5. commands/cat/debug_log.2025-07-09_10-17-09_526262.zip +0 -0
  6. commands/cat/dr_egeria_md.py +23 -13
  7. commands/cat/list_collections.py +9 -2
  8. md_processing/__init__.py +3 -1
  9. md_processing/data/commands.json +7842 -2231
  10. md_processing/md_commands/data_designer_commands.py +29 -19
  11. md_processing/md_commands/glossary_commands.py +3 -1
  12. md_processing/md_commands/product_manager_commands.py +1746 -0
  13. md_processing/md_commands/solution_architect_commands.py +390 -236
  14. md_processing/md_processing_utils/common_md_proc_utils.py +7 -5
  15. md_processing/md_processing_utils/md_processing_constants.py +25 -4
  16. pyegeria/__init__.py +1 -0
  17. pyegeria/_client.py +0 -1
  18. pyegeria/collection_manager_omvs.py +156 -117
  19. pyegeria/data_designer_omvs.py +16 -8
  20. pyegeria/egeria_tech_client.py +9 -25
  21. pyegeria/governance_officer_omvs.py +1446 -1343
  22. pyegeria/output_formatter.py +96 -8
  23. pyegeria/solution_architect_omvs.py +2278 -1728
  24. {pyegeria-5.4.0.dev11.dist-info → pyegeria-5.4.0.dev12.dist-info}/METADATA +1 -1
  25. {pyegeria-5.4.0.dev11.dist-info → pyegeria-5.4.0.dev12.dist-info}/RECORD +28 -23
  26. {pyegeria-5.4.0.dev11.dist-info → pyegeria-5.4.0.dev12.dist-info}/LICENSE +0 -0
  27. {pyegeria-5.4.0.dev11.dist-info → pyegeria-5.4.0.dev12.dist-info}/WHEEL +0 -0
  28. {pyegeria-5.4.0.dev11.dist-info → pyegeria-5.4.0.dev12.dist-info}/entry_points.txt +0 -0
@@ -62,7 +62,7 @@ def parse_upsert_command(egeria_client: EgeriaTech, object_type: str, object_act
62
62
  display_name = ""
63
63
  labels = {}
64
64
 
65
- command_spec = get_command_spec(object_type)
65
+ command_spec = get_command_spec(f"Create {object_type}")
66
66
  attributes = command_spec.get('Attributes', [])
67
67
  command_display_name = command_spec.get('display_name', None)
68
68
  command_qn_prefix = command_spec.get('qn_prefix', None)
@@ -264,8 +264,10 @@ def parse_view_command(egeria_client: EgeriaTech, object_type: str, object_actio
264
264
  parsed_output['exists'] = False
265
265
 
266
266
  labels = {}
267
-
268
- command_spec = get_command_spec(f"{object_action} {object_type}")
267
+ if object_action == "Unlink":
268
+ command_spec = get_command_spec(f"Link {object_type}")
269
+ else:
270
+ command_spec = get_command_spec(f"{object_action} {object_type}")
269
271
  attributes = command_spec.get('Attributes', [])
270
272
  command_display_name = command_spec.get('display_name', None)
271
273
 
@@ -344,12 +346,12 @@ def parse_view_command(egeria_client: EgeriaTech, object_type: str, object_actio
344
346
 
345
347
  elif style == 'Reference Name':
346
348
  parsed_attributes[key] = proc_ids(egeria_client, key, labels, txt, object_action, if_missing)
347
- if ((if_missing == ERROR) and parsed_attributes[key].get("value", None)):
349
+ if ((if_missing == ERROR) and parsed_attributes[key].get("value", None) is None):
348
350
  msg = f"Required parameter `{parsed_attributes[key]['value']}` is missing"
349
351
  logger.error(msg)
350
352
  parsed_output['valid'] = False
351
353
  parsed_output['reason'] += msg
352
- elif parsed_attributes[key]['value'] and parsed_attributes['exists'] is False:
354
+ elif parsed_attributes[key]['value'] and parsed_attributes[key]['exists'] is False:
353
355
  msg = f"Reference Name `{parsed_attributes[key]['value']}` is specified but does not exist"
354
356
  logger.error(msg)
355
357
  parsed_output['valid'] = False
@@ -51,18 +51,37 @@ command_list = ["Provenance", "Create Glossary", "Update Glossary", "Create Term
51
51
  "List Term Details", "List Glossary Terms", "List Term History", "List Term Revision History",
52
52
  "List Term Update History", "List Glossary Structure", "List Glossaries", "List Categories",
53
53
  "List Glossary Categories", "Create Personal Project", "Update Personal Project", "Create Category",
54
- "Update Category", "Create Solution Blueprint", "Update Solution Blueprint", "View Solution Blueprint", "View Solution Blueprints", "View Blueprints",
54
+ "Update Category", "Create Solution Blueprint", "Update Solution Blueprint", "View Solution Blueprint",
55
+ "View Solution Blueprints", "View Blueprints",
55
56
  "View Information Supply Chain", "View Information Supply Chains", "View Supply Chains", "View Supply Chain",
56
57
  "View Solution Components", "View Solution Component", "View Solution Roles", "View Solution Role",
57
58
  "Create Information Supply Chain", "Update Information Supply Chain",
58
- "Create Information Supply Chain Segment", "Update Information Supply Chain Segment", "Link Segments", "Detach Segments",
59
- "Create Solution Component", "Update Solution Component", "Create Term-Term Relationship",
59
+ "Link Information Supply Chain Peers", "Link Supply Chains", "Link Information Supply Chains",
60
+ "Unlink Information Supply Chain Peers", "Unlink Information Supply Chains", "Unlink Supply Chains",
61
+ "Create Solution Component", "Update Solution Component", "Link Solution Components", "Wire Solution Components",
62
+ "Detach Solution Components", "Unlink Solution Components", "Create Term-Term Relationship",
60
63
  "Update Term-Term Relationship", "Create Data Spec", "Create Data Specification", "Update Data Spec",
61
64
  "Update Data Specification", "Create Data Field", "Update Data Field", "Create Data Structure",
62
65
  "Update Data Structure", "Create Data Dictionary", "Update Data Dictionary", "Create Data Dict",
63
66
  "Update Data Dict", " View Data Dictionary", "View Data Dictionaries", "View Data Specifications",
64
67
  "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",]
68
+ "View Dataa Classes", "View Data Class", "Create Data Class", "Update Data Class",
69
+ "Create Digital Product", "Create Data Product", "Update Digital Product", "Update Data Product",
70
+ "Create Agreement", "Create Digital Agreement", "Create Data Agreement",
71
+ "Update Agreement", "Update Data Agreement", "Update Data Agreement",
72
+ "Link Digital Products", "Link Data Products", "Detach Digital Products", "Detach Data Products",
73
+ "Create Data Sharing Agreement", "Update Data Sharing Agreement",
74
+ "Create Digital Subscription", "Create Product Subscription", "Update Digital Subscription", "Update Product Subscription",
75
+ "Attach Agreement Items", "Detach Agreement Items",
76
+ "Attach Contract", "Detach Contract",
77
+ "Attach Subscriber", "Detach Subscriber",
78
+ "Link Collection to Resource", "Attach Collection to Resource",
79
+ "Unlink Collection From Resource", "Detach Collection From Resource",
80
+ "Add Member to Collection", "Add Member", "Member->Collection",
81
+ "Remove Member from Collection","Remove Member from Collection",
82
+ "View Digital Products", "View Data Products", "List Data Products", "List Digtal Products",
83
+ "View Agreements", "View Data Sharing Agreements", "List Agreements", "List Data Sharing Agreements",
84
+ "View Subscriptions", "List Subscriptions",]
66
85
 
67
86
 
68
87
  pre_command = "\n---\n==> Processing object_action:"
@@ -88,6 +107,7 @@ def load_commands(filename: str) -> None:
88
107
 
89
108
  def get_command_spec(command: str) -> dict | None:
90
109
  global COMMAND_DEFINITIONS
110
+
91
111
  com = COMMAND_DEFINITIONS.get('Command Specifications', {}).get(command, None)
92
112
  if com:
93
113
  return com
@@ -99,6 +119,7 @@ def get_command_spec(command: str) -> dict | None:
99
119
 
100
120
  def find_alternate_names(command: str) -> str | None:
101
121
  global COMMAND_DEFINITIONS
122
+
102
123
  comm_spec = COMMAND_DEFINITIONS.get('Command Specifications', {})
103
124
  for key, value in comm_spec.items():
104
125
  if isinstance(value, dict):
pyegeria/__init__.py CHANGED
@@ -43,6 +43,7 @@ from .feedback_manager_omvs import FeedbackManager
43
43
  from .full_omag_server_config import FullServerConfig
44
44
  from .glossary_browser_omvs import GlossaryBrowser
45
45
  from .glossary_manager_omvs import GlossaryManager
46
+ from .governance_officer_omvs import GovernanceOfficer
46
47
  from .mermaid_utilities import (construct_mermaid_web, construct_mermaid_jup, generate_process_graph, load_mermaid,
47
48
  parse_mermaid_code, render_mermaid, save_mermaid_graph, save_mermaid_html, )
48
49
  from .metadata_explorer_omvs import MetadataExplorer
pyegeria/_client.py CHANGED
@@ -32,7 +32,6 @@ from pyegeria._validators import (
32
32
  validate_url,
33
33
  validate_user_id,
34
34
  )
35
- from pyegeria.output_formatter import make_preamble, make_md_attribute
36
35
 
37
36
  ...
38
37
 
@@ -7,11 +7,10 @@ Copyright Contributors to the ODPi Egeria project.
7
7
  """
8
8
 
9
9
  import asyncio
10
-
11
10
  from pyegeria._client import Client
12
11
  from pyegeria._globals import NO_ELEMENTS_FOUND
13
12
  from pyegeria._validators import validate_guid, validate_search_string
14
- from pyegeria.output_formatter import (extract_mermaid_only, extract_basic_dict, generate_output)
13
+ from pyegeria.output_formatter import (extract_mermaid_only, extract_basic_dict, generate_output, markdown_to_html)
15
14
  from pyegeria.utils import body_slimmer
16
15
 
17
16
 
@@ -34,6 +33,8 @@ def query_string(params):
34
33
  return result
35
34
 
36
35
 
36
+
37
+
37
38
  class CollectionManager(Client):
38
39
  """
39
40
  Maintain and explore the contents of nested collections. These collections can be used to represent digital
@@ -191,7 +192,7 @@ class CollectionManager(Client):
191
192
  self._async_get_attached_collections(parent_guid, start_from, page_size, body, output_format))
192
193
 
193
194
  async def _async_find_collections_w_body(self, body: dict, classification_name: str = None,
194
- starts_with: bool = False, ends_with: bool = False,
195
+ starts_with: bool = True, ends_with: bool = False,
195
196
  ignore_case: bool = False, start_from: int = 0, page_size: int = 0,
196
197
  output_format: str = 'JSON', output_profile: str = "CORE") -> list | str:
197
198
  """ Returns the list of collections matching the search string filtered by the optional classification.
@@ -278,7 +279,7 @@ class CollectionManager(Client):
278
279
  return self.generate_collection_output(elements, None, None, output_format)
279
280
  return elements
280
281
 
281
- def find_collections_w_body(self, body: dict, classification_name: str = None, starts_with: bool = False,
282
+ def find_collections_w_body(self, body: dict, classification_name: str = None, starts_with: bool = True,
282
283
  ends_with: bool = False, ignore_case: bool = False, start_from: int = 0,
283
284
  page_size: int = 0, output_format: str = 'JSON',
284
285
  output_profile: str = "CORE") -> list | str:
@@ -345,7 +346,7 @@ class CollectionManager(Client):
345
346
  start_from, page_size, output_format, output_profile))
346
347
 
347
348
  async def _async_find_collections(self, search_string: str = '*', classification_name: str = None,
348
- starts_with: bool = False, ends_with: bool = False, ignore_case: bool = False,
349
+ starts_with: bool = True, ends_with: bool = False, ignore_case: bool = False,
349
350
  start_from: int = 0, page_size: int = 0, output_format: str = 'JSON',
350
351
  output_profile: str = "CORE") -> list | str:
351
352
  """ Returns the list of collections matching the search string filtered by the optional classification.
@@ -402,9 +403,9 @@ class CollectionManager(Client):
402
403
  start_from, page_size, output_format, output_profile)
403
404
  return resp
404
405
 
405
- def find_collections(self, search_string: str = '*', classification_name: str = None, starts_with: bool = False,
406
- ends_with: bool = False, ignore_case: bool = False, start_from: int = 0, page_size: int = 0,
407
- output_format: str = 'JSON', output_profile: str = "CORE") -> list | str:
406
+ def find_collections(self, search_string: str = '*', classification_name: str = None, starts_with: bool = True,
407
+ ends_with: bool = False, ignore_case: bool = False,
408
+ start_from: int = 0, page_size: int = 0, output_format: str = 'JSON', output_profile: str = "CORE") -> list | str:
408
409
  """ Returns the list of collections matching the search string filtered by the optional classification.
409
410
  The search string is located in the request body and is interpreted as a plain string. The full
410
411
  body allows complete control including status, asOfTime and effectiveTime.
@@ -2952,7 +2953,10 @@ class CollectionManager(Client):
2952
2953
  # Digital Products
2953
2954
  #
2954
2955
  async def _async_create_digital_product(self, body: dict) -> str:
2955
- """Create a new collection that represents a digital product. Async version.
2956
+ """ Create a new collection that represents a digital product. To set a lifecycle status
2957
+ use a NewDigitalProductRequestBody which has a default status of DRAFT. Using a
2958
+ NewElementRequestBody sets the status to ACTIVE.
2959
+ Async version.
2956
2960
 
2957
2961
  Parameters
2958
2962
  ----------
@@ -2978,6 +2982,8 @@ class CollectionManager(Client):
2978
2982
  be valid dates if specified, otherwise you will get a 400 error response.
2979
2983
 
2980
2984
  JSON Structure looks like:
2985
+
2986
+ Without lifecycle status:
2981
2987
  {
2982
2988
  "class" : "NewElementRequestBody",
2983
2989
  "anchorGUID" : "anchor GUID, if set then isOwnAnchor=false",
@@ -3060,64 +3066,111 @@ class CollectionManager(Client):
3060
3066
  return resp.json().get("guid", "No GUID returned")
3061
3067
 
3062
3068
  def create_digital_product(self, body: dict) -> str:
3063
- """Create a new collection that represents a digital product. Async version.
3064
-
3065
- Parameters
3066
- ----------
3067
- body: dict
3068
- A dict representing the details of the collection to create.
3069
-
3070
- Returns
3071
- -------
3072
- str - the guid of the created collection
3073
-
3074
- Raises
3075
- ------
3076
- InvalidParameterException
3077
- If the client passes incorrect parameters on the request - such as bad URLs or invalid values
3078
- PropertyServerException
3079
- Raised by the server when an issue arises in processing a valid request
3080
- NotAuthorizedException
3081
- The principle specified by the user_id does not have authorization for the requested action
3069
+ """ Create a new collection that represents a digital product. To set a lifecycle status
3070
+ use a NewDigitalProductRequestBody which has a default status of DRAFT. Using a
3071
+ NewElementRequestBody sets the status to ACTIVE.
3072
+
3073
+ Parameters
3074
+ ----------
3075
+ body: dict
3076
+ A dict representing the details of the collection to create.
3077
+
3078
+ Returns
3079
+ -------
3080
+ str - the guid of the created collection
3081
+
3082
+ Raises
3083
+ ------
3084
+ InvalidParameterException
3085
+ If the client passes incorrect parameters on the request - such as bad URLs or invalid values
3086
+ PropertyServerException
3087
+ Raised by the server when an issue arises in processing a valid request
3088
+ NotAuthorizedException
3089
+ The principle specified by the user_id does not have authorization for the requested action
3090
+
3091
+ Notes
3092
+ -----
3093
+ Note: the three dates: introductionDate, nextVersionDate and withdrawDate must
3094
+ be valid dates if specified, otherwise you will get a 400 error response.
3095
+
3096
+ JSON Structure looks like:
3097
+
3098
+ Without lifecycle status:
3099
+ {
3100
+ "class" : "NewElementRequestBody",
3101
+ "anchorGUID" : "anchor GUID, if set then isOwnAnchor=false",
3102
+ "isOwnAnchor" : false,
3103
+ "parentGUID" : "parent GUID, if set, set all parameters beginning 'parent'",
3104
+ "parentRelationshipTypeName" : "open metadata type name",
3105
+ "parentAtEnd1": true,
3106
+ "properties": {
3107
+ "class" : "CollectionProperties",
3108
+ "qualifiedName": "Must provide a unique name here",
3109
+ "name" : "Add display name here",
3110
+ "description" : "Add description of the collection here",
3111
+ "collectionType": "Add appropriate valid value for type",
3112
+ "collectionOrder" : "OTHER",
3113
+ "orderByPropertyName" : "Add property name if 'collectionOrder' is OTHER"
3114
+ },
3115
+ "digitalProductProperties" : {
3116
+ "class" : "DigitalProductProperties",
3117
+ "productStatus" : "ACTIVE",
3118
+ "productName" : "Add name here",
3119
+ "productType" : "Add valid value here",
3120
+ "description" : "Add description here",
3121
+ "introductionDate" : "date",
3122
+ "maturity" : "Add valid value here",
3123
+ "serviceLife" : "Add the estimated lifetime of the product",
3124
+ "currentVersion": "V1.0",
3125
+ "nextVersion": "V1.1",
3126
+ "withdrawDate": "date",
3127
+ "additionalProperties": {
3128
+ "property1Name" : "property1Value",
3129
+ "property2Name" : "property2Value"
3130
+ }
3131
+ }
3132
+ }
3082
3133
 
3083
- Notes
3084
- -----
3085
- JSON Structure looks like:
3086
- {
3087
- "class" : "NewElementRequestBody",
3088
- "anchorGUID" : "anchor GUID, if set then isOwnAnchor=false",
3089
- "isOwnAnchor" : false,
3090
- "parentGUID" : "parent GUID, if set, set all parameters beginning 'parent'",
3091
- "parentRelationshipTypeName" : "open metadata type name",
3092
- "parentAtEnd1": true,
3093
- "properties": {
3094
- "class" : "CollectionProperties",
3095
- "qualifiedName": "Must provide a unique name here",
3096
- "name" : "Add display name here",
3097
- "description" : "Add description of the collection here",
3098
- "collectionType": "Add appropriate valid value for type",
3099
- "collectionOrder" : "OTHER",
3100
- "orderByPropertyName" : "Add property name if 'collectionOrder' is OTHER"
3101
- },
3102
- "digitalProductProperties" : {
3103
- "class" : "DigitalProductProperties",
3104
- "productStatus" : "ACTIVE",
3105
- "productName" : "Add name here",
3106
- "productType" : "Add valid value here",
3107
- "description" : "Add description here",
3108
- "introductionDate" : "date",
3109
- "maturity" : "Add valid value here",
3110
- "serviceLife" : "Add the estimated lifetime of the product",
3111
- "currentVersion": "V1.0",
3112
- "nextVersion": "V1.1",
3113
- "withdrawDate": "date",
3114
- "additionalProperties": {
3115
- "property1Name" : "property1Value",
3116
- "property2Name" : "property2Value"
3117
- }
3118
- }
3119
- }
3120
- """
3134
+ With a lifecycle, the body is:
3135
+ {
3136
+ "class" : "NewDigitalProductRequestBody",
3137
+ "isOwnAnchor" : true,
3138
+ "anchorScopeGUID" : "optional GUID of search scope",
3139
+ "parentGUID" : "xxx",
3140
+ "parentRelationshipTypeName" : "CollectionMembership",
3141
+ "parentAtEnd1": true,
3142
+ "properties": {
3143
+ "class" : "DigitalProductProperties",
3144
+ "qualifiedName": "DigitalProduct:Add product name here",
3145
+ "userDefinedStatus" : "Optional value here - used when initial status is OTHER",
3146
+ "name" : "Product display name",
3147
+ "description" : "Add description of product and its expected usage here",
3148
+ "identifier" : "Add product identifier here",
3149
+ "productName" : "Add product name here",
3150
+ "productType" : "Periodic Delta",
3151
+ "maturity" : "Add valid value here",
3152
+ "serviceLife" : "Add the estimated lifetime of the product",
3153
+ "introductionDate" : "date",
3154
+ "nextVersionDate": "date",
3155
+ "withdrawDate": "date",
3156
+ "currentVersion": "V0.1",
3157
+ "additionalProperties": {
3158
+ "property1Name" : "property1Value",
3159
+ "property2Name" : "property2Value"
3160
+ }
3161
+ },
3162
+ "initialStatus" : "DRAFT",
3163
+ "externalSourceGUID": "add guid here",
3164
+ "externalSourceName": "add qualified name here",
3165
+ "effectiveTime" : "{{$isoTimestamp}}",
3166
+ "forLineage" : false,
3167
+ "forDuplicateProcessing" : false
3168
+ }
3169
+
3170
+ The valid values for initialStatus are: DRAFT, PREPARED, PROPOSED, APPROVED, REJECTED, APPROVED_CONCEPT,
3171
+ UNDER_DEVELOPMENT, DEVELOPMENT_COMPLETE, APPROVED_FOR_DEPLOYMENT, ACTIVE, DISABLED, DEPRECATED,
3172
+ OTHER. If using OTHER, set the userDefinedStatus with the status value you want.
3173
+ """
3121
3174
  loop = asyncio.get_event_loop()
3122
3175
  resp = loop.run_until_complete(self._async_create_digital_product(body))
3123
3176
  return resp
@@ -5331,7 +5384,7 @@ class CollectionManager(Client):
5331
5384
  #
5332
5385
  #
5333
5386
 
5334
- async def _async_attach_collection(self, parent_guid: str, collection_guid: str, body: dict = None):
5387
+ async def _async_attach_collection(self, parent_guid: str, collection_guid: str, body: dict = None, make_anchor: bool = False):
5335
5388
  """ Connect an existing collection to an element using the ResourceList relationship (0019).
5336
5389
  Async version.
5337
5390
 
@@ -5343,6 +5396,8 @@ class CollectionManager(Client):
5343
5396
  The identifier of the collection being attached.
5344
5397
  body: dict, optional, default = None
5345
5398
  A dict representing the details of the relationship.
5399
+ make_anchor: bool, optional, default = False
5400
+ Indicates if the collection should be anchored to the element.
5346
5401
 
5347
5402
  Returns
5348
5403
  -------
@@ -5383,13 +5438,13 @@ class CollectionManager(Client):
5383
5438
  """
5384
5439
 
5385
5440
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/metadata-elements/"
5386
- f"{parent_guid}/collections/{collection_guid}/attach")
5441
+ f"{parent_guid}/collections/{collection_guid}/attach?makeAchor={make_anchor}")
5387
5442
  if body:
5388
5443
  await self._async_make_request("POST", url, body)
5389
5444
  else:
5390
5445
  await self._async_make_request("POST", url)
5391
5446
 
5392
- def attach_collection(self, parent_guid: str, collection_guid: str, body: dict = None):
5447
+ def attach_collection(self, parent_guid: str, collection_guid: str, body: dict = None, make_anchor: bool = False):
5393
5448
  """ Connect an existing collection to an element using the ResourceList relationship (0019).
5394
5449
 
5395
5450
  Parameters
@@ -5400,6 +5455,8 @@ class CollectionManager(Client):
5400
5455
  The identifier of the collection being attached.
5401
5456
  body: dict, optional, default = None
5402
5457
  A dict representing the details of the relationship.
5458
+ make_anchor: bool, optional, default = False
5459
+ Indicates if the collection should be anchored to the element.
5403
5460
 
5404
5461
  Returns
5405
5462
  -------
@@ -5438,7 +5495,7 @@ class CollectionManager(Client):
5438
5495
  }
5439
5496
  """
5440
5497
  loop = asyncio.get_event_loop()
5441
- loop.run_until_complete(self._async_attach_collection(parent_guid, collection_guid, body))
5498
+ loop.run_until_complete(self._async_attach_collection(parent_guid, collection_guid, body, make_anchor))
5442
5499
 
5443
5500
  async def _async_detach_collection(self, parent_guid: str, collection_guid: str, body: dict = None):
5444
5501
  """ Detach an existing collection from an element. If the collection is anchored to the element, it is delete.
@@ -5453,6 +5510,7 @@ class CollectionManager(Client):
5453
5510
  body: dict, optional, default = None
5454
5511
  A dict representing the details of the relationship.
5455
5512
 
5513
+
5456
5514
  Returns
5457
5515
  -------
5458
5516
  Nothing
@@ -6060,6 +6118,7 @@ class CollectionManager(Client):
6060
6118
  for classification in classifications:
6061
6119
  classification_names += f"{classification['classificationName']}, "
6062
6120
  classification_names = classification_names[:-2]
6121
+ mermaid = element.get('mermaidGraph', "") or ""
6063
6122
 
6064
6123
  member_names = ""
6065
6124
  members = self.get_member_list(collection_guid=guid)
@@ -6072,7 +6131,7 @@ class CollectionManager(Client):
6072
6131
  'GUID': guid, 'display_name': display_name, 'qualified_name': qualified_name, 'description': description,
6073
6132
  'classifications': classification_names, 'collection_type': collection_type, 'members': member_names,
6074
6133
  'properties': properties, 'additional_properties': additional_properties,
6075
- 'extended_properties': extended_properties,
6134
+ 'extended_properties': extended_properties, 'mermaid': mermaid
6076
6135
  }
6077
6136
 
6078
6137
  def generate_basic_structured_output(self, elements, filter, output_format: str = 'DICT',
@@ -6083,7 +6142,7 @@ class CollectionManager(Client):
6083
6142
  Args:
6084
6143
  elements: Dictionary or list of dictionaries containing element data
6085
6144
  filter: The search string used to find the elements
6086
- output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID)
6145
+ output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID, HTML)
6087
6146
 
6088
6147
  Returns:
6089
6148
  Formatted output as string or list of dictionaries
@@ -6093,6 +6152,19 @@ class CollectionManager(Client):
6093
6152
  return extract_mermaid_only(elements)
6094
6153
  elif output_format == "DICT":
6095
6154
  return extract_basic_dict(elements)
6155
+ elif output_format == "HTML":
6156
+ if collection_type is None:
6157
+ entity_type = "Collection"
6158
+ else:
6159
+ entity_type = collection_type
6160
+
6161
+ return generate_output(
6162
+ elements=elements,
6163
+ search_string=filter,
6164
+ entity_type=entity_type,
6165
+ output_format="HTML",
6166
+ extract_properties_func=self._extract_collection_properties
6167
+ )
6096
6168
 
6097
6169
  # For other formats (MD, FORM, REPORT, LIST), use generate_output
6098
6170
  elif output_format in ["MD", "FORM", "REPORT", "LIST"]:
@@ -6121,7 +6193,7 @@ class CollectionManager(Client):
6121
6193
  classification_name: str
6122
6194
  The type of collection.
6123
6195
  filter: The search string used to find the elements
6124
- output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID)
6196
+ output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID, HTML)
6125
6197
 
6126
6198
  Returns:
6127
6199
  Formatted output as a string or list of dictionaries
@@ -6131,10 +6203,20 @@ class CollectionManager(Client):
6131
6203
  else:
6132
6204
  entity_type = classification_name
6133
6205
 
6134
- if output_format in ["MD", "FORM", "REPORT", "LIST", "DICT", "MERMAID"]:
6206
+ if output_format == "HTML":
6207
+ return generate_output(
6208
+ elements=elements,
6209
+ search_string=filter,
6210
+ entity_type=entity_type,
6211
+ output_format="HTML",
6212
+ extract_properties_func=self._extract_collection_properties
6213
+ )
6214
+
6215
+ elif output_format in ["MD", "FORM", "REPORT", "LIST", "DICT", "MERMAID"]:
6135
6216
  # Define columns for LIST format
6136
6217
  columns = [{'name': 'Name', 'key': 'display_name'},
6137
6218
  {'name': 'Qualified Name', 'key': 'qualified_name', 'format': True},
6219
+ {'name': 'Collection Type', 'key': 'collection_type'},
6138
6220
  {'name': 'Description', 'key': 'description', 'format': True},
6139
6221
  {'name': "Classifications", 'key': 'classifications'},
6140
6222
  {'name': 'Members', 'key': 'members', 'format': True}, ]
@@ -6146,49 +6228,6 @@ class CollectionManager(Client):
6146
6228
  else:
6147
6229
  return self.generate_basic_structured_output(elements, filter, output_format)
6148
6230
 
6149
- # def generate_collection_output(self, elements, filter, collection_type: str, output_format,
6150
- # # output_profile: str = "CORE") -> str | list | dict: # """ # Generate output in the specified #
6151
- # format # for the given elements. # # Args: # elements: Dictionary or list of dictionaries #
6152
- # containing # element data # filter: The search string used to find the elements # #
6153
- # output_format: The # desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID, JSON) # #
6154
- # output_profile: str, optional, # default = "CORE" # The desired output profile - BASIC, CORE,
6155
- # FULL # Returns: # # Formatted output as string or list of dictionaries # """ # if #
6156
- # collection_type is None: # # entity_type = "Collection" # else: # entity_type = #
6157
- # collection_type # # # For LIST and DICT # formats, get member information # # if output_format in
6158
- # ["LIST", "DICT"]: # # Get the collection # GUID # collection_guid = None # if #
6159
- # isinstance(elements, dict): # collection_guid # = elements.get('elementHeader', {}).get('guid')
6160
- # elif isinstance(elements, list) and len(elements) > # 0: # collection_guid = elements[ #
6161
- # 0].get('elementHeader', {}).get('guid') # # # Get member # list if we have a valid #
6162
- # collection GUID # members = [] # if collection_guid: # # members = #
6163
- # self.get_member_list(collection_guid=collection_guid) # if isinstance(members,
6164
- # str): # "No members found" case # members = [] # # # For DICT format, include all
6165
- # member information in the result # if output_format == "DICT": # result = # #
6166
- # self.generate_basic_structured_output(elements, filter, output_format, collection_type) # if # #
6167
- # isinstance(result, list): # for item in result: # item['members'] = # #
6168
- # members # return result # elif isinstance(result, dict): # # result['members']
6169
- # = members # return result # # # For LIST format, add a column with # bulleted list
6170
- # of qualified names # elif output_format == "LIST": # # Define columns for # LIST format,
6171
- # including the new Members column # columns = [{'name': 'Collection Name',
6172
- # 'key': 'display_name'}, # {'name': 'Qualified Name', 'key': 'qualified_name'}, # # {'name':
6173
- # 'Collection Type', 'key': 'collection_type'}, # {'name': 'Description',
6174
- # 'key': 'description', 'format': True}, # {'name': 'Classifications',
6175
- # 'key': 'classifications'}, # {'name': 'Members', 'key': 'members', 'format': True}] # # #
6176
- # Create a function to add member information to the properties # def get_additional_props(element,
6177
- # guid, output_format): # if not members: # return {'members': ''} # # #
6178
- # Create a comma-separated list of qualified names (no newlines to avoid table formatting issues) # # #
6179
- # member_list = ", ".join([member.get('qualifiedName', '') for member in members]) # return { #
6180
- # 'members': member_list} # # # Generate output with the additional properties # # # return #
6181
- # generate_output(elements=elements, search_string=filter, entity_type=entity_type,
6182
- # # output_format=output_format, extract_properties_func=self._extract_collection_properties,
6183
- # # get_additional_props_func=get_additional_props, columns=columns) # # # For FORM, REPORT, JSON formats,
6184
- # keep behavior unchanged # return self.generate_basic_structured_output(elements, filter, output_format,
6185
- # collection_type)
6186
-
6187
- # def generate_data_class_output(self, elements, filter, output_format) -> str | list: # return # # #
6188
- # self.generate_basic_structured_output(elements, filter, output_format) # # def generate_data_field_output( #
6189
- # self, elements, filter, output_format) -> str | list: # return self.generate_basic_structured_output( #
6190
- # elements, filter, output_format)
6191
-
6192
6231
 
6193
6232
  if __name__ == "__main__":
6194
6233
  print("Main-Collection Manager")
@@ -4283,7 +4283,7 @@ r replace_all_properties: bool, default = False
4283
4283
  ignore_case_s = str(ignore_case).lower()
4284
4284
 
4285
4285
  possible_query_params = query_string(
4286
- [("startFrom", start_from), ("pageSize", page_size), ("startsWith", ends_with_s), ("endsWith", ends_with_s),
4286
+ [("startFrom", start_from), ("pageSize", page_size), ("startsWith", starts_with_s), ("endsWith", ends_with_s),
4287
4287
  ("ignoreCase", ignore_case_s)])
4288
4288
 
4289
4289
  url = (f"{base_path(self, self.view_server)}/data-classes/by-search-string"
@@ -5308,7 +5308,7 @@ r replace_all_properties: bool, default = False
5308
5308
  Args:
5309
5309
  elements: Dictionary or list of dictionaries containing element data
5310
5310
  filter: The search string used to find the elements
5311
- output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID)
5311
+ output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID, HTML)
5312
5312
 
5313
5313
  Returns:
5314
5314
  Formatted output as string or list of dictionaries
@@ -5318,6 +5318,14 @@ r replace_all_properties: bool, default = False
5318
5318
  return extract_mermaid_only(elements)
5319
5319
  elif output_format == "DICT":
5320
5320
  return extract_basic_dict(elements)
5321
+ elif output_format == "HTML":
5322
+ return generate_output(
5323
+ elements=elements,
5324
+ search_string=filter,
5325
+ entity_type="Data Element",
5326
+ output_format="HTML",
5327
+ extract_properties_func=self._extract_data_structure_properties
5328
+ )
5321
5329
 
5322
5330
  # For other formats (MD, FORM, REPORT, LIST), use generate_output
5323
5331
  elif output_format in ["MD", "FORM", "REPORT", "LIST"]:
@@ -5339,12 +5347,12 @@ r replace_all_properties: bool, default = False
5339
5347
  Args:
5340
5348
  elements: Dictionary or list of dictionaries containing data structure elements
5341
5349
  filter: The search string used to find the elements
5342
- output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID)
5350
+ output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID, HTML)
5343
5351
 
5344
5352
  Returns:
5345
5353
  Formatted output as string or list of dictionaries
5346
5354
  """
5347
- if output_format in ["MD", "FORM", "REPORT", "LIST", "MERMAID"]:
5355
+ if output_format in ["MD", "FORM", "REPORT", "LIST", "MERMAID", "HTML"]:
5348
5356
  # Define columns for LIST format
5349
5357
  columns = [{'name': 'Structure Name', 'key': 'display_name'},
5350
5358
  {'name': 'Qualified Name', 'key': 'qualified_name','format': True}, {'name': 'Namespace', 'key': 'namespace'},
@@ -5364,12 +5372,12 @@ r replace_all_properties: bool, default = False
5364
5372
  Args:
5365
5373
  elements: Dictionary or list of dictionaries containing data class elements
5366
5374
  filter: The search string used to find the elements
5367
- output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID)
5375
+ output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID, HTML)
5368
5376
 
5369
5377
  Returns:
5370
5378
  Formatted output as string or list of dictionaries
5371
5379
  """
5372
- if output_format in ["DICT", "MD", "FORM", "REPORT", "LIST", "MERMAID"]:
5380
+ if output_format in ["DICT", "MD", "FORM", "REPORT", "LIST", "MERMAID", "HTML"]:
5373
5381
  # Define columns for LIST format
5374
5382
  columns = [{'name': 'Class Name', 'key': 'display_name'},
5375
5383
  {'name': 'Qualified Name', 'key': 'qualified_name','format': True},
@@ -5388,12 +5396,12 @@ r replace_all_properties: bool, default = False
5388
5396
  Args:
5389
5397
  elements: Dictionary or list of dictionaries containing data field elements
5390
5398
  filter: The search string used to find the elements
5391
- output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID)
5399
+ output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID, HTML)
5392
5400
 
5393
5401
  Returns:
5394
5402
  Formatted output as a string or list of dictionaries
5395
5403
  """
5396
- if output_format in ["MD", "FORM", "REPORT", "LIST", "DICT", "MERMAID"]:
5404
+ if output_format in ["MD", "FORM", "REPORT", "LIST", "DICT", "MERMAID", "HTML"]:
5397
5405
  # Define columns for LIST format
5398
5406
  columns = [{'name': 'Field Name', 'key': 'display_name'},
5399
5407
  {'name': 'Qualified Name', 'key': 'qualified_name','format': True}, {'name': 'Data Type', 'key': 'data_type'},