Skip to content
Merged
174 changes: 11 additions & 163 deletions omvs_audit_report.md

Large diffs are not rendered by default.

23 changes: 18 additions & 5 deletions pyegeria/core/_server_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6522,25 +6522,38 @@ async def _async_get_guid_request(self, url: str, _type: str, _gen_output: Calla
skip_relationships: list[str] | None = None,
graph_query_depth: int = 3,
output_format: str = 'JSON', report_spec: Optional[str | dict] = None,
body: Optional[dict | GetRequestBody] = None, max_mermaid_node_count=10,
body: Optional[dict | GetRequestBody | ResultsRequestBody] = None,
max_mermaid_node_count=10,
body_model: type[GetRequestBody | ResultsRequestBody] = GetRequestBody,
**kwargs) -> Any:
"""Retrieve an element by GUID.

if isinstance(body, GetRequestBody):
`body_model` selects the request-body class to send. It defaults to
GetRequestBody, which is what nearly every endpoint reached through
this helper documents. A few endpoints document ResultsRequestBody
instead (e.g. governance-officer's .../graph); they pass it explicitly
rather than switching to _async_get_results_body_request, because only
this helper understands the singular "elementGraph" response key.
"""
if isinstance(body, (GetRequestBody, ResultsRequestBody)):
validated_body = body
elif isinstance(body, dict):
validated_body = self._validate_body(self._get_request_adapter.validate_python, body)
adapter = (self._get_request_adapter.validate_python
if body_model is GetRequestBody
else self._results_request_adapter.validate_python)
validated_body = self._validate_body(adapter, body)
else:
_type = _type.replace(" ", "")
body = {
"class": "GetRequestBody",
"class": body_model.__name__,
"metadataElementTypeName": _type,
"includeOnlyRelationships": include_only_relationships,
"skipRelationships": skip_relationships,
"graphQueryDepth": graph_query_depth,
"maxMermaidNodeCount": max_mermaid_node_count,
**kwargs
}
validated_body = self._validate_body(GetRequestBody.model_validate, body)
validated_body = self._validate_body(body_model.model_validate, body)

json_body = validated_body.model_dump_json(indent=2, exclude_none=True)

Expand Down
26 changes: 13 additions & 13 deletions pyegeria/omvs/actor_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ async def _async_create_actor_profile_from_template(self, body: Optional[dict |

# Handle Optional body parameter
body_to_use = body if body is not None else {}
return await self._async_create_element_from_template("POST", url, body_to_use)
return await self._async_create_element_from_template(url, body_to_use)

@dynamic_catch
def create_actor_profile_from_template(self, body: Optional[dict | TemplateRequestBody] = None) -> str:
Expand Down Expand Up @@ -580,7 +580,7 @@ async def _async_detach_asset_from_profile(self, asset_guid: str, it_profile_gui
"""
url = (f"{self.command_root}/assets/{asset_guid}/it-profiles/{it_profile_guid}/detach")

await self._async_delete_element_request(url, body)
await self._async_delete_relationship_request(url, body)
logger.debug(f"Detached asset {asset_guid} from it profile {it_profile_guid}")

def detach_asset_from_profile(self, asset_guid: str, it_profile_guid: str,
Expand Down Expand Up @@ -1430,7 +1430,7 @@ async def _async_create_actor_role_from_template(self, body: Optional[dict | Tem

# Handle Optional body parameter
body_to_use = body if body is not None else {}
return await self._async_create_element_from_template("POST", url, body_to_use)
return await self._async_create_element_from_template(url, body_to_use)

@dynamic_catch
def create_actor_role_from_template(self, body: Optional[dict | TemplateRequestBody] = None) -> str:
Expand Down Expand Up @@ -1754,7 +1754,7 @@ async def _async_detach_person_role_from_profile(self, person_role_guid: str, pe
url = (
f"{self.command_root}/actor-roles/{person_role_guid}/person-role-appointments/{person_profile_guid}/detach")

await self._async_delete_element_request(url, body)
await self._async_delete_relationship_request(url, body)
logger.debug(f"Detached Person Rolet {person_role_guid} from Person Profile {person_profile_guid}")

def detach_person_role_from_profile(self, person_role_guid: str, person_profile_guid: str,
Expand Down Expand Up @@ -2188,7 +2188,7 @@ def detach_it_profile_role_from_it_profile(self, it_profile_role_guid: str, it_p

@dynamic_catch
async def _async_delete_actor_role(self, actor_role_guid: str,
body: Optional[dict | DeleteElementRequestBody] = None,
body: Optional[dict | DeleteRelationshipRequestBody] = None,
cascade: bool = False) -> None:
""" Delete an actor role. Async Version.

Expand Down Expand Up @@ -2231,11 +2231,11 @@ async def _async_delete_actor_role(self, actor_role_guid: str,
"""
url = f"{self.command_root}/actor-roles/{actor_role_guid}/delete"

await self._async_delete_element_request(url, body, cascade)
await self._async_delete_relationship_request(url, body, cascade)
logger.debug(f"Deleted actor role {actor_role_guid} with cascade {cascade}")

@dynamic_catch
def delete_actor_role(self, actor_role_guid: str, body: Optional[dict | DeleteElementRequestBody] = None,
def delete_actor_role(self, actor_role_guid: str, body: Optional[dict | DeleteRelationshipRequestBody] = None,
cascade: bool = False) -> None:
""" Delete an actor role. Async Version.

Expand Down Expand Up @@ -3002,7 +3002,7 @@ async def _async_create_user_identity_from_template(self, body: Optional[dict |
"""
url = f"{self.command_root}/user-identities/from-template"

return await self._async_create_element_from_template("POST", url, body)
return await self._async_create_element_from_template(url, body)

@dynamic_catch
def create_user_identity_from_template(self, body: Optional[dict | TemplateRequestBody] = None) -> str:
Expand Down Expand Up @@ -3613,7 +3613,7 @@ async def _async_add_security_group_membership(self, user_identity_guid: str, se

"""

url = url = (f"{self.command_root}/user-identities/{user_identity_guid}/security-group-membership/classify")
url = (f"{self.command_root}/user-identities/{user_identity_guid}/security-group-memberships/classify")
await self._async_new_classification_request(url, ["SecurityGroupMembershipProperties"], body)
logger.debug(f"Classifying User Identity {user_identity_guid} with Security Groups {security_groups}")

Expand Down Expand Up @@ -3712,7 +3712,7 @@ async def _async_update_security_group_membership(self, user_identity_guid: str,
"forDuplicateProcessing" : false
}
"""
url = (f"{self.command_root}/user-identities/{user_identity_guid}/security-group-membership/reclassify")
url = (f"{self.command_root}/user-identities/{user_identity_guid}/security-group-memberships/reclassify")

await self._async_make_request("POST", url, body)
logger.debug(f"Updated security classifications for {user_identity_guid}")
Expand Down Expand Up @@ -5544,7 +5544,7 @@ async def _async_create_contact_details_from_template(self, body: Optional[dict
}
"""
url = f"{self.command_root}/contact-details/from-template"
return await self._async_create_element_body_request(url, ["ContactDetailsProperties"], body)
return await self._async_create_element_from_template(url, body)

@dynamic_catch
def create_contact_details_from_template(self, body: Optional[dict | TemplateRequestBody] = None) -> str:
Expand Down Expand Up @@ -6582,7 +6582,7 @@ async def _async_create_perspective_from_template(self, body: Optional[dict | Te
"""
url = f"{self.command_root}/perspectives/from-template"
body_to_use = body if body is not None else {}
return await self._async_create_element_body_request(url, ["PerspectiveProperties"], body_to_use)
return await self._async_create_element_from_template(url, body_to_use)

@dynamic_catch
def create_perspective_from_template(self, body: Optional[dict | TemplateRequestBody] = None) -> str:
Expand Down Expand Up @@ -7388,7 +7388,7 @@ async def _async_create_skill_from_template(self, body: Optional[dict | Template
"""
url = f"{self.command_root}/skills/from-template"
body_to_use = body if body is not None else {}
return await self._async_create_element_body_request(url, ["SkillProperties"], body_to_use)
return await self._async_create_element_from_template(url, body_to_use)

@dynamic_catch
def create_skill_from_template(self, body: Optional[dict | TemplateRequestBody] = None) -> str:
Expand Down
16 changes: 8 additions & 8 deletions pyegeria/omvs/classification_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -961,7 +961,7 @@ async def _async_get_semantic_assignees(

"""

url = (f"{self.classification_command_root}/glossaries/elements/by-semantic-assignment/{term_guid}")
url = (f"{self.classification_command_root}/elements/by-semantic-assignment/{term_guid}")

response = await self._async_make_request("POST", url, body_slimmer(body), timeout=default_timeout, **kwargs)
elements = response.json().get("elements", None)
Expand Down Expand Up @@ -1362,7 +1362,7 @@ async def _async_get_source_elements(

"""

url = (f"{self.classification_command_root}/glossaries/elements/{element_guid}/source")
url = (f"{self.classification_command_root}/elements/{element_guid}/source")

response = await self._async_get_results_body_request(url, "Referenceable", self._generate_referenceable_output,
start_from=start_from, page_size=page_size,
Expand Down Expand Up @@ -1496,7 +1496,7 @@ async def _async_get_elements_sourced_from(

"""

url = (f"{self.classification_command_root}/glossaries/elements/{element_guid}/sourced-from")
url = (f"{self.classification_command_root}/elements/{element_guid}/sourced-from")

response = await self._async_get_results_body_request(url, "Referenceable", self._generate_referenceable_output,
start_from=start_from, page_size=page_size,
Expand Down Expand Up @@ -1888,7 +1888,7 @@ async def _async_get_licensed_elements(

"""

url = (f"{self.classification_command_root}/glossaries/elements/licenses/{license_type_guid}")
url = (f"{self.classification_command_root}/elements/licenses/{license_type_guid}")

response = await self._async_get_results_body_request(url, "Referenceable", self._generate_referenceable_output,
start_from=start_from, page_size=page_size,
Expand Down Expand Up @@ -2017,7 +2017,7 @@ async def _async_get_licenses(

"""

url = (f"{self.classification_command_root}/glossaries/elements/{element_guid}/licenses")
url = (f"{self.classification_command_root}/elements/{element_guid}/licenses")

response = await self._async_get_results_body_request(url, "Referenceable", self._generate_referenceable_output,
start_from=start_from, page_size=page_size,
Expand Down Expand Up @@ -2146,7 +2146,7 @@ async def _async_get_certified_elements(

"""

url = (f"{self.classification_command_root}/glossaries/elements/certifications/{certification_type_guid}")
url = (f"{self.classification_command_root}/elements/certifications/{certification_type_guid}")

response = await self._async_get_results_body_request(url, "Referenceable", self._generate_referenceable_output,
start_from=start_from, page_size=page_size,
Expand Down Expand Up @@ -11108,7 +11108,7 @@ async def _async_clear_known_duplicate_classification(
"effectiveTime": effective_time
}

await self._async_delete_relationship_request(url, body)
await self._async_delete_classification_request(url, body)

def clear_known_duplicate_classification(
self,
Expand Down Expand Up @@ -11591,7 +11591,7 @@ async def _async_clear_consolidated_duplicate_classification(
"effectiveTime": effective_time
}

await self._async_delete_relationship_request(url, body)
await self._async_delete_classification_request(url, body)

def clear_consolidated_duplicate_classification(
self,
Expand Down
2 changes: 1 addition & 1 deletion pyegeria/omvs/data_designer.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ async def _async_detach_specialized_data_value_specification(
"""
url = (
f"{self.ref_data_designer_command_base}/data-value-specifications/{spec_guid}"
f"/specialized-data-value-specification-definition/{grain_guid}/detach"
f"/specialized-data-value-specifications/{grain_guid}/detach"
)
await self._async_delete_relationship_request(url, body, cascade_delete)

Expand Down
2 changes: 1 addition & 1 deletion pyegeria/omvs/data_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ async def _async_create_annotation_from_template(self, body: dict | TemplateRequ
```
"""
url = f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/data-discovery/annotations/from-template"
return await self._async_create_element_body_request(url, "AnnotationProperties", body)
return await self._async_create_element_from_template(url, body)

def create_annotation_from_template(self, body: dict | TemplateRequestBody) -> str:
"""Create an annotation from a template.
Expand Down
18 changes: 9 additions & 9 deletions pyegeria/omvs/glossary_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1834,7 +1834,7 @@ def add_is_abstract_concept(

@dynamic_catch
async def _async_remove_is_abstract_concept(
self, term_guid: str, body: Optional[dict | DeleteClassificationRequestBody] = None,
self, term_guid: str, body: Optional[dict | DeleteElementRequestBody] = None,
) -> None:
"""Remove the abstract concept designation from the glossary term. Async Version.

Expand Down Expand Up @@ -1876,12 +1876,12 @@ async def _async_remove_is_abstract_concept(
f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/"
f"terms/{term_guid}/is-abstract-concept/delete"
)
await self._async_delete_classification_request(url, body)
await self._async_delete_element_request(url, body)
logger.info(f"Removed AbstractConcept classification to {term_guid}")

@dynamic_catch
def remove_is_abstract_concept(
self, term_guid: str, body: Optional[dict | DeleteClassificationRequestBody] = None,
self, term_guid: str, body: Optional[dict | DeleteElementRequestBody] = None,
) -> None:
"""Remove the abstract concept designation from the glossary term.

Expand Down Expand Up @@ -2026,7 +2026,7 @@ def add_is_context_definition(

@dynamic_catch
async def _async_remove_is_context_definition(
self, term_guid: str, body: Optional[dict | DeleteClassificationRequestBody] = None,
self, term_guid: str, body: Optional[dict | DeleteRelationshipRequestBody] = None,
) -> None:
"""Remove the context definition designation from the glossary term. Async Version.

Expand Down Expand Up @@ -2067,12 +2067,12 @@ async def _async_remove_is_context_definition(
f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/"
f"terms/{term_guid}/is-context-definition/delete"
)
await self._async_delete_classification_request(url, body)
await self._async_delete_relationship_request(url, body)
logger.info(f"Removed ContextDefinition classification to {term_guid}")

@dynamic_catch
def remove_is_context_definition(
self, term_guid: str, body: Optional[dict | DeleteClassificationRequestBody] = None,
self, term_guid: str, body: Optional[dict | DeleteRelationshipRequestBody] = None,
) -> None:
"""Remove the context definition designation from the glossary term.

Expand Down Expand Up @@ -2407,7 +2407,7 @@ def add_activity_description(

@dynamic_catch
async def _async_remove_activity_description(
self, term_guid: str, body: Optional[dict | DeleteClassificationRequestBody] = None,
self, term_guid: str, body: Optional[dict | DeleteRelationshipRequestBody] = None,
) -> None:
"""Remove the activity designation from the glossary term. Async Version.

Expand Down Expand Up @@ -2449,12 +2449,12 @@ async def _async_remove_activity_description(
f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/"
f"terms/{term_guid}/is-activity/remove"
)
await self._async_delete_classification_request(url, body)
await self._async_delete_relationship_request(url, body)
logger.info(f"Removed ActivityDescription classification to {term_guid}")

@dynamic_catch
def remove_activity_description(
self, term_guid: str, body: Optional[dict | DeleteClassificationRequestBody] = None,
self, term_guid: str, body: Optional[dict | DeleteRelationshipRequestBody] = None,
) -> None:
"""Remove the activity designation from the glossary term.

Expand Down
8 changes: 6 additions & 2 deletions pyegeria/omvs/governance_officer.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
ReferenceableProperties, TemplateRequestBody,
UpdateElementRequestBody, NewRelationshipRequestBody,
DeleteElementRequestBody, DeleteRelationshipRequestBody,
UpdateRelationshipRequestBody)
UpdateRelationshipRequestBody, ResultsRequestBody)
from pyegeria.core.utils import dynamic_catch

GOV_DEF_PROPERTIES_LIST = ["GovernanceDefinitionProperties", "GovernanceStrategyProperties", "RegulationProperties",
Expand Down Expand Up @@ -2739,10 +2739,14 @@ async def _async_get_governance_action_process_graph(self, guid: str, element_ty
f"{self.url_marker}/governance-action-processes/{guid}/graph")
type = element_type if element_type else "GovernanceDefinition"

# This endpoint documents ResultsRequestBody, not the GetRequestBody
# this helper sends by default (Egeria-api-governance-officer.http).
# Kept on _async_get_guid_request because only it reads the singular
# "elementGraph" response key that the graph endpoint returns.
response = await self._async_get_guid_request(url, _type=type,
_gen_output=self._generate_governance_definition_output,
output_format=output_format, report_spec=report_spec,
body=body, **kwargs)
body=body, body_model=ResultsRequestBody, **kwargs)

return response

Expand Down
5 changes: 2 additions & 3 deletions pyegeria/omvs/lineage_linker.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,8 @@ async def _async_link_lineage(
}
```
"""
url = f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/lineage-linker/elements/{element_one_guid}/{relationship_type_name}/{element_two_guid}/attach"
response = await self._async_make_request("POST", url, body)
return response.json().get("guid")
url = f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/lineage-linker/from-elements/{element_one_guid}/via/{relationship_type_name}/to-elements/{element_two_guid}/attach"
return await self._async_new_relationship_request(url, ["LineageRelationshipProperties"], body)

def link_lineage(
self,
Expand Down
Loading