pyegeria 5.4.0.24__py3-none-any.whl → 5.4.0.25__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.
- commands/cat/debug_log +7373 -1452
- commands/cat/debug_log.2025-08-17_11-34-27_981852.zip +0 -0
- commands/cat/dr_egeria_md.py +21 -4
- commands/cat/logs/pyegeria.log +4 -0
- md_processing/.DS_Store +0 -0
- md_processing/__init__.py +7 -3
- md_processing/data/commands.json +1683 -2801
- md_processing/dr_egeria_inbox/product.md +69 -20
- md_processing/dr_egeria_outbox/.obsidian/workspace.json +5 -5
- md_processing/dr_egeria_outbox/monday/processed-2025-08-19 07:05-product.md +426 -0
- md_processing/dr_egeria_outbox/monday/processed-2025-08-19 07:56-product.md +212 -0
- md_processing/dr_egeria_outbox/monday/processed-2025-08-19 09:43-product.md +201 -0
- md_processing/dr_egeria_outbox/tuesday/processed-2025-08-19 10:55-product.md +209 -0
- md_processing/md_commands/governance_officer_commands.py +1 -73
- md_processing/md_commands/product_manager_commands.py +453 -211
- md_processing/md_processing_utils/common_md_proc_utils.py +60 -5
- md_processing/md_processing_utils/common_md_utils.py +21 -9
- md_processing/md_processing_utils/extraction_utils.py +2 -2
- md_processing/md_processing_utils/md_processing_constants.py +8 -7
- pyegeria/.DS_Store +0 -0
- pyegeria/_client_new.py +58 -10
- pyegeria/_output_formats.py +25 -0
- pyegeria/collection_manager.py +79 -14
- pyegeria/{data_designer_omvs.py → data_designer.py} +1171 -1675
- pyegeria/glossary_browser.py +1259 -0
- pyegeria/{glossary_manager_omvs.py → glossary_manager.py} +1181 -1099
- pyegeria/models.py +9 -3
- pyegeria/output_formatter.py +2 -1
- pyegeria/project_manager.py +1952 -0
- pyegeria/utils.py +4 -1
- {pyegeria-5.4.0.24.dist-info → pyegeria-5.4.0.25.dist-info}/METADATA +1 -1
- {pyegeria-5.4.0.24.dist-info → pyegeria-5.4.0.25.dist-info}/RECORD +35 -34
- md_processing/dr_egeria_outbox/monday/processed-2025-07-14 12:38-data_designer_out.md +0 -663
- md_processing/dr_egeria_outbox/monday/processed-2025-07-21 10:52-generated_help_report.md +0 -2744
- md_processing/dr_egeria_outbox/monday/processed-2025-07-21 18:38-collections.md +0 -62
- md_processing/dr_egeria_outbox/monday/processed-2025-08-01 11:34-gov_def.md +0 -444
- md_processing/dr_egeria_outbox/monday/processed-2025-08-17 21:04-product.md +0 -97
- pyegeria/glossary_browser_omvs.py +0 -3840
- pyegeria/governance_officer_omvs.py +0 -2367
- {pyegeria-5.4.0.24.dist-info → pyegeria-5.4.0.25.dist-info}/LICENSE +0 -0
- {pyegeria-5.4.0.24.dist-info → pyegeria-5.4.0.25.dist-info}/WHEEL +0 -0
- {pyegeria-5.4.0.24.dist-info → pyegeria-5.4.0.25.dist-info}/entry_points.txt +0 -0
@@ -129,8 +129,12 @@ def parse_upsert_command(egeria_client: EgeriaTech, object_type: str, object_act
|
|
129
129
|
default_value = attr[key].get('default_value', None)
|
130
130
|
|
131
131
|
style = attr[key]['style']
|
132
|
-
if style in ['Simple', '
|
132
|
+
if style in ['Simple', 'Comment']:
|
133
133
|
parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value)
|
134
|
+
elif style == 'Dictionary':
|
135
|
+
parsed_attributes[key] = proc_dictionary_attribute(txt, object_action, labels, if_missing, default_value)
|
136
|
+
parsed_attributes[key]['name_list'] = json.dumps(parsed_attributes[key]['value'], indent=2)
|
137
|
+
|
134
138
|
elif style == 'Valid Value':
|
135
139
|
parsed_attributes[key] = proc_valid_value(txt, object_action, labels,
|
136
140
|
attr[key].get('valid_values', None), if_missing,
|
@@ -330,8 +334,12 @@ def parse_view_command(egeria_client: EgeriaTech, object_type: str, object_actio
|
|
330
334
|
default_value = attr[key].get('default_value', None)
|
331
335
|
|
332
336
|
style = attr[key]['style']
|
333
|
-
if style in ['Simple', '
|
337
|
+
if style in ['Simple', 'Comment']:
|
334
338
|
parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value)
|
339
|
+
elif style == 'Dictionary':
|
340
|
+
parsed_attributes[key] = proc_dictionary_attribute(txt, object_action, labels, if_missing,
|
341
|
+
default_value)
|
342
|
+
parsed_attributes[key]['name_list'] = json.dumps(parsed_attributes[key]['value'], indent=2)
|
335
343
|
elif style == 'Valid Value':
|
336
344
|
parsed_attributes[key] = proc_valid_value(txt, object_action, labels,
|
337
345
|
attr[key].get('valid_values', None), if_missing,
|
@@ -406,7 +414,7 @@ def parse_view_command(egeria_client: EgeriaTech, object_type: str, object_actio
|
|
406
414
|
value = parsed_attributes[key].get('value', None)
|
407
415
|
|
408
416
|
if value is not None:
|
409
|
-
# if the value is a dict, get the
|
417
|
+
# if the value is a dict or list, get the stringifiedt
|
410
418
|
value = parsed_attributes[key].get('name_list', None) if isinstance(value, (dict, list)) else value
|
411
419
|
parsed_output['display'] += f"\n\t* {key}: `{value}`\n\t"
|
412
420
|
|
@@ -469,6 +477,50 @@ def proc_simple_attribute(txt: str, action: str, labels: set, if_missing: str =
|
|
469
477
|
|
470
478
|
return {"status": INFO, "OK": None, "value": attribute, "valid": valid, "exists": True}
|
471
479
|
|
480
|
+
@logger.catch
|
481
|
+
def proc_dictionary_attribute(txt: str, action: str, labels: set, if_missing: str = INFO, default_value=None,
|
482
|
+
simp_type: str = None) -> dict:
|
483
|
+
"""Process a dictionary attribute based on the provided labels and if_missing value.
|
484
|
+
Extract the attribute value from the text and store it in a dictionary along with valid.
|
485
|
+
If it doesn`t exist, mark the dictionary entry as invalid and print an error message with severity of if_missing.
|
486
|
+
|
487
|
+
Parameters:
|
488
|
+
----------
|
489
|
+
txt: str
|
490
|
+
The block of object_action text to extract attributes from.
|
491
|
+
labels: list
|
492
|
+
The possible attribute labels to search for. The first label will be used in messages.
|
493
|
+
if_missing: str, default is INFO
|
494
|
+
Can be one of "WARNING", "ERROR", "INFO". The severity of the missing attribute.
|
495
|
+
default_value: default is None
|
496
|
+
The default value to return if the attribute is missing.
|
497
|
+
"""
|
498
|
+
valid = True
|
499
|
+
|
500
|
+
if if_missing not in ["WARNING", "ERROR", "INFO"]:
|
501
|
+
msg = "Invalid severity for missing attribute"
|
502
|
+
logger.error(msg)
|
503
|
+
return {"status": ERROR, "reason": msg, "value": None, "valid": False}
|
504
|
+
|
505
|
+
if default_value == "":
|
506
|
+
default_value = None
|
507
|
+
|
508
|
+
attr = extract_attribute(txt, labels)
|
509
|
+
attribute = json.loads(attr) if attr is not None else default_value
|
510
|
+
|
511
|
+
|
512
|
+
if attribute is None:
|
513
|
+
if if_missing == INFO or if_missing == WARNING:
|
514
|
+
msg = f"Optional attribute with labels: `{labels}` missing"
|
515
|
+
valid = True
|
516
|
+
logger.info(msg)
|
517
|
+
else:
|
518
|
+
msg = f"Missing attribute with labels `{labels}` "
|
519
|
+
valid = False
|
520
|
+
logger.error(msg)
|
521
|
+
return {"status": if_missing, "reason": msg, "value": None, "valid": valid, "exists": False}
|
522
|
+
|
523
|
+
return {"status": INFO, "OK": None, "value": attribute, "valid": valid, "exists": True}
|
472
524
|
|
473
525
|
@logger.catch
|
474
526
|
def proc_valid_value(txt: str, action: str, labels: set, valid_values: [], if_missing: str = INFO,
|
@@ -529,8 +581,11 @@ def proc_valid_value(txt: str, action: str, labels: set, valid_values: [], if_mi
|
|
529
581
|
logger.error(msg)
|
530
582
|
return {"status": if_missing, "reason": msg, "value": None, "valid": valid, "exists": False}
|
531
583
|
else:
|
584
|
+
# Todo: look at moving validation into pydantic or another style...
|
585
|
+
if "Status" in labels:
|
586
|
+
attribute = attribute.upper()
|
532
587
|
if attribute not in v_values:
|
533
|
-
msg = f"Invalid value for attribute `{labels}`"
|
588
|
+
msg = f"Invalid value for attribute `{labels}` attribute is `{attribute}`"
|
534
589
|
logger.warning(msg)
|
535
590
|
return {"status": WARNING, "reason": msg, "value": attribute, "valid": False, "exists": True}
|
536
591
|
|
@@ -656,7 +711,7 @@ def proc_el_id(egeria_client: EgeriaTech, element_type: str, qn_prefix: str, ele
|
|
656
711
|
logger.error(msg)
|
657
712
|
identifier_output = {"status": ERROR, "reason": msg, "value": element_name, "valid": False, "exists": False, }
|
658
713
|
|
659
|
-
elif action in ["Update", "View"] and exists:
|
714
|
+
elif action in ["Update", "View", "Link", "Detach"] and exists:
|
660
715
|
msg = f"Element {element_name} exists"
|
661
716
|
logger.info(msg)
|
662
717
|
identifier_output = {
|
@@ -307,12 +307,15 @@ def set_prop_body(object_type: str, qualified_name: str, attributes: dict)->dict
|
|
307
307
|
"qualifiedName" : qualified_name,
|
308
308
|
"description": attributes['Description'].get('value', None),
|
309
309
|
"category": attributes.get('Category', {}).get('value', None),
|
310
|
+
"identifier": attributes.get('Identifier', {}).get('value', None),
|
310
311
|
"userDefinedStatus": attributes.get('User Defined Status', {}).get('value', None),
|
311
312
|
"versionIdentifier": attributes.get('Version Identifier', {}).get('value', None),
|
312
313
|
"effectiveFrom": attributes.get('Effective From', {}).get('value', None),
|
313
314
|
"effectiveTo": attributes.get('Effective To', {}).get('value', None),
|
314
315
|
"additionalProperties": attributes.get('Additional Properties', {}).get('value', None),
|
315
|
-
"extendedProperties": attributes.get('Extended Properties', {}).get('value', None)
|
316
|
+
"extendedProperties": attributes.get('Extended Properties', {}).get('value', None),
|
317
|
+
"supportLevel": attributes.get('Support Level', {}).get('value', None),
|
318
|
+
"serviceLevels": attributes.get('Service Levels', {}).get('value', None),
|
316
319
|
}
|
317
320
|
|
318
321
|
def set_product_body(object_type: str, qualified_name: str, attributes: dict)->dict:
|
@@ -324,6 +327,9 @@ def set_product_body(object_type: str, qualified_name: str, attributes: dict)->d
|
|
324
327
|
prop_bod["introductionDate"] = attributes.get('Introduction Date', {}).get('value', [])
|
325
328
|
prop_bod["withdrawalDate"] = attributes.get('Withdrawal Date', {}).get('value', [])
|
326
329
|
prop_bod["nextVersion"] = attributes.get('Next Version Date', {}).get('value', [])
|
330
|
+
return prop_bod
|
331
|
+
|
332
|
+
|
327
333
|
|
328
334
|
def set_update_status_body(object_type: str, attributes: dict)->dict:
|
329
335
|
return {
|
@@ -425,6 +431,8 @@ def set_delete_request_body(object_type: str, attributes: dict)->dict:
|
|
425
431
|
"forDuplicateProcessing": attributes.get('For Duplicate Processing', {}).get('value', False)
|
426
432
|
}
|
427
433
|
|
434
|
+
|
435
|
+
|
428
436
|
def set_filter_request_body(object_type: str, attributes: dict)->dict:
|
429
437
|
return {
|
430
438
|
"class": "FilterRequestBody",
|
@@ -457,14 +465,18 @@ def set_classifications(object_type: str, attributes: dict)->dict:
|
|
457
465
|
body = {classification: {} for classification in classifications} if cclassifications else {}
|
458
466
|
return body
|
459
467
|
|
460
|
-
def set_collection_classifications(object_type: str, attributes: dict)->dict:
|
468
|
+
def set_collection_classifications(object_type: str, attributes: dict, obj_types: list[str])->dict:
|
461
469
|
classifications = attributes.get('Classifications', {}).get('name_list', None)
|
462
|
-
|
463
|
-
if object_type in
|
464
|
-
if
|
465
|
-
classifications
|
466
|
-
|
467
|
-
|
470
|
+
obj = object_type.replace(" ", "")
|
471
|
+
if object_type in obj_types:
|
472
|
+
if classifications:
|
473
|
+
if object_type not in classifications:
|
474
|
+
classifications.append(obj)
|
475
|
+
else:
|
476
|
+
classifications = [obj]
|
477
|
+
|
478
|
+
body = {}
|
468
479
|
if classifications:
|
469
|
-
|
480
|
+
for classification in classifications:
|
481
|
+
body[classification] = {"class" : f"{classification}Properties"}
|
470
482
|
return body
|
@@ -91,7 +91,7 @@ def extract_attribute(text: str, labels: set) -> str | None:
|
|
91
91
|
# Iterate over the list of labels
|
92
92
|
for label in labels:
|
93
93
|
# Construct pattern for the current label
|
94
|
-
# text = re.sub(r'\s+', ' ', text).strip()
|
94
|
+
# text = re.sub(r'\s+', ' ', text).strip() # just added
|
95
95
|
text = re.sub(r'\n\n+', '\n\n', text).strip()
|
96
96
|
|
97
97
|
label = label.strip()
|
@@ -395,7 +395,7 @@ def get_element_by_name(egeria_client, element_type: str, element_name: str) ->
|
|
395
395
|
return q_name, guid, unique, exists
|
396
396
|
|
397
397
|
else: # Missing guid from element_dictionary
|
398
|
-
guid = egeria_client.
|
398
|
+
guid = egeria_client.__get_guid__(qualified_name=q_name)
|
399
399
|
if guid == NO_ELEMENTS_FOUND:
|
400
400
|
guid = None
|
401
401
|
exists = False
|
@@ -131,20 +131,21 @@ command_list = ["Provenance", "Create Glossary", "Update Glossary", "Create Term
|
|
131
131
|
"View Dataa Classes", "View Data Class", "Create Data Class", "Update Data Class",
|
132
132
|
"Create Digital Product", "Create Data Product", "Update Digital Product", "Update Data Product",
|
133
133
|
"Create Agreement", "Update Agreement",
|
134
|
-
"Link Digital Products", "Link
|
134
|
+
"Link Digital Products", "Link Product-Product", "Detach Digital Products", "Detach Product-Product",
|
135
135
|
"Create Data Sharing Agreement", "Update Data Sharing Agreement",
|
136
|
-
|
137
|
-
"
|
136
|
+
"Create Digital Subscription", "Create Product Subscription", "Update Digital Subscription", "Update Product Subscription",
|
137
|
+
"Link Agreement->Item", "Detach Agreement->Item",
|
138
138
|
"Attach Contract", "Detach Contract",
|
139
|
-
"
|
140
|
-
"Link Collection
|
141
|
-
"Unlink Collection
|
139
|
+
"Link Subscriber->Subscription", "Detach Subscriber->Subscription",
|
140
|
+
"Link Collection->Resource", "Attach Collection->Resource",
|
141
|
+
"Unlink Collection->Resource", "Detach Collection->Resource",
|
142
142
|
"Add Member to Collection", "Add Member", "Member->Collection",
|
143
|
-
"Remove Member from Collection","Remove Member
|
143
|
+
"Remove Member from Collection","Remove Member->Collection",
|
144
144
|
"View Governance Definitions", "View Gov Definitions",
|
145
145
|
"List Governance Definitions", "List Gov Definitions",
|
146
146
|
"View Governance Definition Context","List Governance Definition Context",
|
147
147
|
"View Governance Def Context", "List Governance Def Context",
|
148
|
+
"View Report",
|
148
149
|
# "Create Business Imperative", "Update Business Imperative",
|
149
150
|
# "Create Regulation Article Definition", "Update Regulation Article Definition",
|
150
151
|
# "Create Threat Definition", "Update Threat Definition",
|
pyegeria/.DS_Store
CHANGED
Binary file
|
pyegeria/_client_new.py
CHANGED
@@ -35,7 +35,7 @@ from pyegeria._validators import (
|
|
35
35
|
)
|
36
36
|
from pyegeria.models import SearchStringRequestBody, FilterRequestBody, GetRequestBody, NewElementRequestBody, \
|
37
37
|
TemplateRequestBody, UpdateStatusRequestBody, UpdateElementRequestBody, NewRelationshipRequestBody, \
|
38
|
-
DeleteRequestBody, UpdateRelationshipRequestBody, ResultsRequestBody
|
38
|
+
DeleteRequestBody, UpdateRelationshipRequestBody, ResultsRequestBody, NewClassificationRequestBody
|
39
39
|
from pyegeria.utils import body_slimmer
|
40
40
|
|
41
41
|
...
|
@@ -146,6 +146,7 @@ class Client2:
|
|
146
146
|
self._update_element_request_adapter = TypeAdapter(UpdateElementRequestBody)
|
147
147
|
self._update_status_request_adapter = TypeAdapter(UpdateStatusRequestBody)
|
148
148
|
self._new_relationship_request_adapter = TypeAdapter(NewRelationshipRequestBody)
|
149
|
+
self._new_classification_request_adapter = TypeAdapter(NewClassificationRequestBody)
|
149
150
|
self._delete_request_adapter = TypeAdapter(DeleteRequestBody)
|
150
151
|
self._template_request_adapter = TypeAdapter(TemplateRequestBody)
|
151
152
|
self._update_relationship_request_adapter = TypeAdapter(UpdateRelationshipRequestBody)
|
@@ -755,9 +756,21 @@ class Client2:
|
|
755
756
|
return None
|
756
757
|
return validated_body
|
757
758
|
|
759
|
+
def validate_new_element_from_template_request(self, body: dict | TemplateRequestBody
|
760
|
+
) -> NewElementRequestBody | None:
|
761
|
+
if isinstance(body, TemplateRequestBody):
|
762
|
+
validated_body = body
|
763
|
+
|
764
|
+
elif isinstance(body, dict):
|
765
|
+
# if body.get("properties", {}).get("class", "") == prop:
|
766
|
+
validated_body = self._template_request_adapter.validate_python(body)
|
767
|
+
else:
|
768
|
+
return None
|
769
|
+
return validated_body
|
770
|
+
|
758
771
|
def validate_new_relationship_request(self, body: dict | NewRelationshipRequestBody,
|
759
772
|
prop: str = None) -> NewRelationshipRequestBody | None:
|
760
|
-
if isinstance(body,
|
773
|
+
if isinstance(body, NewRelationshipRequestBody):
|
761
774
|
if (prop and body.properties.class_ == prop) or (prop is None):
|
762
775
|
validated_body = body
|
763
776
|
else:
|
@@ -775,6 +788,26 @@ class Client2:
|
|
775
788
|
|
776
789
|
return validated_body
|
777
790
|
|
791
|
+
def validate_new_classification_request(self, body: dict | NewClassificationRequestBody,
|
792
|
+
prop: str = None) -> NewClassificationRequestBody | None:
|
793
|
+
if isinstance(body, NewClassificationRequestBody):
|
794
|
+
if (prop and body.properties.class_ == prop) or (prop is None):
|
795
|
+
validated_body = body
|
796
|
+
else:
|
797
|
+
raise PyegeriaInvalidParameterException(additional_info=
|
798
|
+
{"reason": "unexpected property class name"})
|
799
|
+
|
800
|
+
elif isinstance(body, dict):
|
801
|
+
if body.get("properties", {}).get("class", "") == prop:
|
802
|
+
validated_body = self._new_classification_request_adapter.validate_python(body)
|
803
|
+
else:
|
804
|
+
raise PyegeriaInvalidParameterException(additional_info=
|
805
|
+
{"reason": "unexpected property class name"})
|
806
|
+
else:
|
807
|
+
return None
|
808
|
+
|
809
|
+
return validated_body
|
810
|
+
|
778
811
|
def validate_delete_request(self, body: dict | DeleteRequestBody,
|
779
812
|
cascade_delete: bool = False) -> DeleteRequestBody | None:
|
780
813
|
if isinstance(body, DeleteRequestBody):
|
@@ -819,7 +852,7 @@ class Client2:
|
|
819
852
|
elif status:
|
820
853
|
body = {
|
821
854
|
"class": "UpdateStatusRequestBody",
|
822
|
-
"
|
855
|
+
"newStatus": status
|
823
856
|
}
|
824
857
|
validated_body = UpdateStatusRequestBody.model_validate(body)
|
825
858
|
else:
|
@@ -939,11 +972,11 @@ class Client2:
|
|
939
972
|
else:
|
940
973
|
body = {
|
941
974
|
"class": "GetRequestBody",
|
942
|
-
|
975
|
+
"metadataElementTypeName": _type
|
943
976
|
}
|
944
977
|
validated_body = GetRequestBody.model_validate(body)
|
945
978
|
|
946
|
-
json_body = validated_body.model_dump_json(indent=2)
|
979
|
+
json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
|
947
980
|
|
948
981
|
response = await self._async_make_request("POST", url, json_body)
|
949
982
|
elements = response.json().get("element", NO_ELEMENTS_FOUND)
|
@@ -972,7 +1005,7 @@ class Client2:
|
|
972
1005
|
}
|
973
1006
|
validated_body = ResultsRequestBody.model_validate(body)
|
974
1007
|
|
975
|
-
json_body = validated_body.model_dump_json(indent=2)
|
1008
|
+
json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
|
976
1009
|
|
977
1010
|
response = await self._async_make_request("POST", url, json_body)
|
978
1011
|
elements = response.json().get("elements", None)
|
@@ -996,7 +1029,15 @@ class Client2:
|
|
996
1029
|
logger.info(json_body)
|
997
1030
|
response = await self._async_make_request("POST", url, json_body)
|
998
1031
|
logger.info(response.json())
|
999
|
-
return response.json().get("guid")
|
1032
|
+
return response.json().get("guid", "NO_GUID_RETURNED")
|
1033
|
+
|
1034
|
+
async def _async_create_element_from_template(self, url: str, body: dict | TemplateRequestBody = None) -> str:
|
1035
|
+
validated_body = self.validate_new_element_from_template_request(body)
|
1036
|
+
json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
|
1037
|
+
logger.info(json_body)
|
1038
|
+
response = await self._async_make_request("POST", url, json_body, is_json=True)
|
1039
|
+
logger.info(response.json())
|
1040
|
+
return response.json().get("guid", "NO_GUID_RETURNED")
|
1000
1041
|
|
1001
1042
|
async def _async_update_element_body_request(self, url: str, prop: list[str],
|
1002
1043
|
body: dict | UpdateElementRequestBody = None) -> None:
|
@@ -1024,6 +1065,16 @@ class Client2:
|
|
1024
1065
|
else:
|
1025
1066
|
await self._async_make_request("POST", url)
|
1026
1067
|
|
1068
|
+
async def _async_new_classification_request(self, url: str, prop: str,
|
1069
|
+
body: dict | NewRelationshipRequestBody = None) -> None:
|
1070
|
+
validated_body = self.validate_new_classification_request(body, prop)
|
1071
|
+
if validated_body:
|
1072
|
+
json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
|
1073
|
+
logger.info(json_body)
|
1074
|
+
await self._async_make_request("POST", url, json_body)
|
1075
|
+
else:
|
1076
|
+
await self._async_make_request("POST", url)
|
1077
|
+
|
1027
1078
|
async def _async_delete_request(self, url: str, body: dict | DeleteRequestBody = None,
|
1028
1079
|
cascade_delete: bool = False) -> None:
|
1029
1080
|
validated_body = self.validate_delete_request(body, cascade_delete)
|
@@ -1035,9 +1086,6 @@ class Client2:
|
|
1035
1086
|
await self._async_make_request("POST", url)
|
1036
1087
|
|
1037
1088
|
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
1089
|
async def _async_update_relationship_request(self, url: str, prop: str,
|
1042
1090
|
body: dict | UpdateRelationshipRequestBody = None) -> None:
|
1043
1091
|
validated_body = self.validate_update_relationship_request(body, prop)
|
pyegeria/_output_formats.py
CHANGED
@@ -143,6 +143,14 @@ COLLECTION_DICT = Format(
|
|
143
143
|
],
|
144
144
|
)
|
145
145
|
|
146
|
+
BASIC_COLLECTIONS_COLUMNS = [
|
147
|
+
Column(name='Qualified Name', key='qualified_name', format=True),
|
148
|
+
Column(name='GUID', key='guid', format=True),
|
149
|
+
Column(name='Type Name', key='type_name'),
|
150
|
+
Column(name="Containing Members", key='collection_members'),
|
151
|
+
Column(name="Member Of", key='member_of_collections')
|
152
|
+
]
|
153
|
+
|
146
154
|
COLLECTION_REPORT = Format(
|
147
155
|
types=["REPORT"],
|
148
156
|
columns=COLLECTIONS_MEMBERS_COLUMNS + [
|
@@ -239,6 +247,8 @@ output_format_sets = FormatSetDict({
|
|
239
247
|
Column(name="Effective To", key='effective_to'),
|
240
248
|
Column(name="GUID", key='guid'),
|
241
249
|
Column(name="Open Metadata Type Name", key='type_name'),
|
250
|
+
Column(name="Glossary", key='parent_glossary'),
|
251
|
+
Column(name="Subject Aream", key='subject_area'),
|
242
252
|
],
|
243
253
|
)
|
244
254
|
]
|
@@ -257,6 +267,21 @@ output_format_sets = FormatSetDict({
|
|
257
267
|
spec_params={},
|
258
268
|
)
|
259
269
|
),
|
270
|
+
"BasicCollections": FormatSet(
|
271
|
+
heading="Common Collection Information",
|
272
|
+
description="Attributes generic to all Collections.",
|
273
|
+
aliases=[],
|
274
|
+
annotations=COMMON_ANNOTATIONS,
|
275
|
+
formats=[Format(
|
276
|
+
types=["ALL"],
|
277
|
+
columns=BASIC_COLLECTIONS_COLUMNS,
|
278
|
+
)], # Reusing common formats
|
279
|
+
action=ActionParameter(
|
280
|
+
function="CollectionManager.find_collections",
|
281
|
+
user_params=["search_string"],
|
282
|
+
spec_params={},
|
283
|
+
)
|
284
|
+
),
|
260
285
|
|
261
286
|
"CollectionMembers": FormatSet(
|
262
287
|
heading="Collection Membership Information",
|
pyegeria/collection_manager.py
CHANGED
@@ -672,7 +672,7 @@ class CollectionManager(Client2):
|
|
672
672
|
----
|
673
673
|
Body sample:
|
674
674
|
{
|
675
|
-
"class": "
|
675
|
+
"class": "GetRequestBody",
|
676
676
|
"asOfTime": "{{$isoTimestamp}}",
|
677
677
|
"effectiveTime": "{{$isoTimestamp}}",
|
678
678
|
"forLineage": false,
|
@@ -680,7 +680,7 @@ class CollectionManager(Client2):
|
|
680
680
|
}
|
681
681
|
"""
|
682
682
|
|
683
|
-
url = str(HttpUrl(f"{self.collection_command_root}/{collection_guid}"))
|
683
|
+
url = str(HttpUrl(f"{self.collection_command_root}/{collection_guid}/retrieve"))
|
684
684
|
type = element_type if element_type else "Collection"
|
685
685
|
|
686
686
|
response = await self._async_get_guid_request(url, _type=type,
|
@@ -1414,6 +1414,26 @@ class CollectionManager(Client2):
|
|
1414
1414
|
self._async_create_collection(display_name, description, category,
|
1415
1415
|
["ContextEvent"], body))
|
1416
1416
|
|
1417
|
+
@dynamic_catch
|
1418
|
+
def create_glossary_category(self, display_name: str, parent_guid: str, description: str = None ) -> str:
|
1419
|
+
"""Create a new glossary category."""
|
1420
|
+
body = {
|
1421
|
+
"class": "NewRelationshipRequestBody",
|
1422
|
+
"parentGUID": parent_guid,
|
1423
|
+
"parentRelationshipTypeName": "CategoryHierarchy",
|
1424
|
+
"parentAtEnd1": True,
|
1425
|
+
"is_own_anchor": False,
|
1426
|
+
"anchor_guid": parent_guid,
|
1427
|
+
"properties": {
|
1428
|
+
"class": "GlossaryCategoryProperties",
|
1429
|
+
"displayName": display_name,
|
1430
|
+
"description": description,
|
1431
|
+
"parentCategory": parent_guid,
|
1432
|
+
},
|
1433
|
+
}
|
1434
|
+
response = self.create_collection(body=body)
|
1435
|
+
return response
|
1436
|
+
|
1417
1437
|
@dynamic_catch
|
1418
1438
|
async def _async_create_data_spec_collection(self, display_name: str = None, description: str = None,
|
1419
1439
|
category: str = None, classification_name: str = None,
|
@@ -1520,15 +1540,16 @@ class CollectionManager(Client2):
|
|
1520
1540
|
}
|
1521
1541
|
|
1522
1542
|
"""
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1543
|
+
if body:
|
1544
|
+
validated_body = self.validate_new_element_request(body,"DataSpecProperties")
|
1545
|
+
elif display_name is not None:
|
1526
1546
|
qualified_name = self.__create_qualified_name__("DataSpec", display_name, EGERIA_LOCAL_QUALIFIER)
|
1527
|
-
|
1528
|
-
initial_classifications_data = {"class" : "ClassificationProperties"}
|
1547
|
+
logger.info(f"\n\tDisplayName was {display_name}, classification {classification_name}\n")
|
1529
1548
|
if classification_name:
|
1530
|
-
|
1531
|
-
classification_name:
|
1549
|
+
initial_classification_data = {
|
1550
|
+
classification_name: {
|
1551
|
+
"class" : "ClassificationProperties"
|
1552
|
+
}
|
1532
1553
|
}
|
1533
1554
|
else:
|
1534
1555
|
initial_classification_dict = None
|
@@ -2398,12 +2419,11 @@ class CollectionManager(Client2):
|
|
2398
2419
|
"""
|
2399
2420
|
|
2400
2421
|
url = (f"{self.collection_command_root}/{collection_guid}/update")
|
2401
|
-
await self.
|
2422
|
+
await self._async_update_element_body_request(url, "DigitalProductProperties", body )
|
2402
2423
|
|
2403
2424
|
|
2404
2425
|
@dynamic_catch
|
2405
|
-
def update_digital_product(self, collection_guid: str, body: dict | UpdateElementRequestBody,
|
2406
|
-
merge_update: bool = True) -> None:
|
2426
|
+
def update_digital_product(self, collection_guid: str, body: dict | UpdateElementRequestBody,) -> None:
|
2407
2427
|
""" Update the properties of a digital product..
|
2408
2428
|
Collections: https://egeria-project.org/concepts/collection
|
2409
2429
|
|
@@ -2467,7 +2487,7 @@ class CollectionManager(Client2):
|
|
2467
2487
|
"""
|
2468
2488
|
|
2469
2489
|
return asyncio.get_event_loop().run_until_complete(
|
2470
|
-
self._async_update_digital_product(collection_guid, body
|
2490
|
+
self._async_update_digital_product(collection_guid, body))
|
2471
2491
|
|
2472
2492
|
|
2473
2493
|
@dynamic_catch
|
@@ -2512,7 +2532,7 @@ class CollectionManager(Client2):
|
|
2512
2532
|
}
|
2513
2533
|
"""
|
2514
2534
|
|
2515
|
-
url = f"{self.
|
2535
|
+
url = f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/metadata-elements/{collection_guid}/update-status"
|
2516
2536
|
await self._async_update_status_request(url, status, body)
|
2517
2537
|
|
2518
2538
|
@dynamic_catch
|
@@ -5071,6 +5091,12 @@ class CollectionManager(Client2):
|
|
5071
5091
|
loop = asyncio.get_event_loop()
|
5072
5092
|
loop.run_until_complete(self._async_add_to_collection(collection_guid, element_guid, body))
|
5073
5093
|
|
5094
|
+
def add_term_to_category(self, category_guid: str, term_guid: str,
|
5095
|
+
body: dict | NewRelationshipRequestBody = None) -> None:
|
5096
|
+
"""Add a term to a category. The request body is optional."""
|
5097
|
+
loop = asyncio.get_event_loop()
|
5098
|
+
loop.run_until_complete(self._async_add_to_collection(category_guid, term_guid, body))
|
5099
|
+
|
5074
5100
|
|
5075
5101
|
@dynamic_catch
|
5076
5102
|
async def _async_update_collection_membership_prop(self, collection_guid: str, element_guid: str, body: dict = None,
|
@@ -5296,6 +5322,45 @@ class CollectionManager(Client2):
|
|
5296
5322
|
#
|
5297
5323
|
|
5298
5324
|
|
5325
|
+
def remove_term_from_category(self, category_guid: str, term_guid: str,
|
5326
|
+
body: dict | DeleteRequestBody= None) -> None:
|
5327
|
+
"""Remove a term from a category.
|
5328
|
+
|
5329
|
+
Parameters
|
5330
|
+
----------
|
5331
|
+
category_guid: str
|
5332
|
+
identity of the collection to return members for.
|
5333
|
+
term_guid: str
|
5334
|
+
Effective time of the query. If not specified will default to any time.
|
5335
|
+
body: dict, optional, defaults to None
|
5336
|
+
The body of the request to add to the collection. See notes.
|
5337
|
+
|
5338
|
+
Returns
|
5339
|
+
-------
|
5340
|
+
None
|
5341
|
+
|
5342
|
+
Raises
|
5343
|
+
------
|
5344
|
+
|
5345
|
+
InvalidParameterException
|
5346
|
+
If the client passes incorrect parameters on the request - such as bad URLs or invalid values
|
5347
|
+
PropertyServerException
|
5348
|
+
Raised by the server when an issue arises in processing a valid request
|
5349
|
+
NotAuthorizedException
|
5350
|
+
The principle specified by the user_id does not have authorization for the requested action
|
5351
|
+
|
5352
|
+
Notes
|
5353
|
+
-----
|
5354
|
+
|
5355
|
+
"""
|
5356
|
+
loop = asyncio.get_event_loop()
|
5357
|
+
loop.run_until_complete(self._async_remove_from_collection(category_guid, term_guid, body))
|
5358
|
+
|
5359
|
+
#
|
5360
|
+
#
|
5361
|
+
#
|
5362
|
+
|
5363
|
+
|
5299
5364
|
@dynamic_catch
|
5300
5365
|
async def _async_get_member_list(self, collection_guid: str = None, collection_name: str = None,
|
5301
5366
|
collection_qname: str = None, ) -> list | str:
|