Compare commits

...

6 Commits

Author SHA1 Message Date
Gergő Jedlicska 6dd0813089 Merge pull request #310 from specklesystems/gergo/contextView
Gergo/context view
2023-10-26 15:02:37 +02:00
Gergő Jedlicska a1831b57db feat: automation context result view reporting and creating 2023-10-26 15:00:03 +02:00
Gergő Jedlicska 1ff3245531 feat: automate sdk report context view 2023-10-26 13:32:48 +02:00
Gergő Jedlicska 3b4723a186 Merge pull request #309 from specklesystems/gergo/automateReportFunctionName
feat: migrate to new automate api
2023-10-25 18:06:44 +02:00
Gergő Jedlicska efe9551c5e fix: legacy typing and tests 2023-10-25 17:53:23 +02:00
Gergő Jedlicska 23a5087fbc feat: migrate to new automate api 2023-10-25 17:46:00 +02:00
3 changed files with 95 additions and 54 deletions
+55 -45
View File
@@ -2,7 +2,7 @@
from dataclasses import dataclass, field
from pathlib import Path
import time
from typing import Any, Dict, List, Optional, Union
from typing import Any, Dict, List, Optional, Tuple, Union
import httpx
from gql import gql
@@ -91,7 +91,7 @@ class AutomationContext:
def elapsed(self) -> float:
"""Return the elapsed time in seconds since the initialization time."""
return (time.perf_counter() - self._init_time) / 1000
return time.perf_counter() - self._init_time
def receive_version(self) -> Base:
"""Receive the Speckle project version that triggered this automation run."""
@@ -110,8 +110,8 @@ class AutomationContext:
return base
def create_new_version_in_project(
self, root_object: Base, model_id: str, version_message: str = ""
) -> str:
self, root_object: Base, model_name: str, version_message: str = ""
) -> Tuple[str, str]:
"""Save a base model to a new version on the project.
Args:
@@ -120,15 +120,28 @@ class AutomationContext:
version_message (str): The message for the new version.
"""
if model_id == self.automation_run_data.model_id:
if model_name == self.automation_run_data.branch_name:
raise ValueError(
f"The target model id: {model_id} cannot match the model id"
f" that triggered this automation: {self.automation_run_data.model_id}"
f"The target model: {model_name} cannot match the model"
f" that triggered this automation:"
f" {self.automation_run_data.model_id} /"
f" {self.automation_run_data.branch_name}"
)
branch = self._get_model(model_id)
if not branch.name:
raise ValueError(f"The model {model_id} has no name.")
branch = self.speckle_client.branch.get(
self.automation_run_data.project_id, model_name, 1
)
# we just check if it exists
if (not branch) or isinstance(branch, SpeckleException):
branch_create = self.speckle_client.branch.create(
self.automation_run_data.project_id,
model_name,
)
if isinstance(branch_create, Exception):
raise branch_create
model_id = branch_create
else:
model_id = branch.id
root_object_id = operations.send(
root_object,
@@ -139,7 +152,7 @@ class AutomationContext:
version_id = self.speckle_client.commit.create(
stream_id=self.automation_run_data.project_id,
object_id=root_object_id,
branch_name=branch.name,
branch_name=model_name,
message=version_message,
source_application="SpeckleAutomate",
)
@@ -148,43 +161,31 @@ class AutomationContext:
raise version_id
self._automation_result.result_versions.append(version_id)
return version_id
return model_id, version_id
def _get_model(self, model_id: str) -> Branch:
query = gql(
"""
query ProjectModel($projectId: String!, $modelId: String!){
project(id: $projectId) {
model(id: $modelId) {
name
id
description
}
}
}
"""
def set_context_view(
self,
# f"{model_id}@{version_id} or {model_id} "
resource_ids: Optional[List[str]] = None,
include_source_model_version: bool = True,
) -> None:
link_resources = (
[
f"{self.automation_run_data.model_id}@{self.automation_run_data.version_id}"
]
if include_source_model_version
else []
)
params = {"projectId": self.automation_run_data.project_id, "modelId": model_id}
response = self.speckle_client.httpclient.execute(query, params)
return Branch.model_validate(response["project"]["model"])
def _get_model(self, model_id: str) -> Branch:
query = gql(
"""
query ProjectModel($projectId: String!, $modelId: String!){
project(id: $projectId) {
model(id: $modelId) {
name
id
description
}
}
}
"""
if resource_ids:
link_resources.append(*resource_ids)
if not link_resources:
raise Exception(
"We do not have enough resource ids to compose a context view"
)
self._automation_result.result_view = (
f"{self.automation_run_data.speckle_server_url}/projects"
f"/{self.automation_run_data.project_id}/models/{','.join(link_resources)}"
)
params = {"projectId": self.automation_run_data.project_id, "modelId": model_id}
response = self.speckle_client.httpclient.execute(query, params)
return Branch.model_validate(response["project"]["model"])
def report_run_status(self) -> None:
"""Report the current run status to the project of this automation."""
@@ -196,8 +197,11 @@ class AutomationContext:
$automationRunId: String!,
$versionId: String!,
$functionId: String!,
$functionName: String!,
$functionLogo: String,
$runStatus: AutomationRunStatus!
$elapsed: Float!
$contextView: String
$resultVersionIds: [String!]!
$statusMessage: String
$objectResults: JSONObject
@@ -211,7 +215,10 @@ class AutomationContext:
functionRuns: [
{
functionId: $functionId
functionName: $functionName
functionLogo: $functionLogo
status: $runStatus,
contextView: $contextView,
elapsed: $elapsed,
resultVersionIds: $resultVersionIds,
statusMessage: $statusMessage
@@ -241,8 +248,11 @@ class AutomationContext:
"automationRunId": self.automation_run_data.automation_run_id,
"versionId": self.automation_run_data.version_id,
"functionId": self.automation_run_data.function_id,
"functionName": self.automation_run_data.function_name,
"functionLogo": self.automation_run_data.function_logo,
"runStatus": self.run_status.value,
"statusMessage": self._automation_result.status_message,
"contextView": self._automation_result.result_view,
"elapsed": self.elapsed(),
"resultVersionIds": self._automation_result.result_versions,
"objectResults": object_results,
+1 -1
View File
@@ -26,8 +26,8 @@ class AutomationRunData(BaseModel):
automation_run_id: str
function_id: str
function_release: str
function_name: str
function_logo: Optional[str]
model_config = ConfigDict(
alias_generator=camelcase, populate_by_name=True, protected_namespaces=()
@@ -79,7 +79,7 @@ def automation_run_data(
automation_run_id = crypto_random_string(10)
function_id = crypto_random_string(10)
function_release = crypto_random_string(10)
function_name = f"automate test {crypto_random_string(3)}"
return AutomationRunData(
project_id=project_id,
model_id=model_id,
@@ -90,8 +90,8 @@ def automation_run_data(
automation_revision_id=automation_revision_id,
automation_run_id=automation_run_id,
function_id=function_id,
function_release=function_release,
function_name="foobar",
function_name=function_name,
function_logo=None,
)
@@ -235,17 +235,48 @@ def test_create_version_in_project_raises_error_for_same_model(
) -> None:
with pytest.raises(ValueError):
automation_context.create_new_version_in_project(
Base(), automation_context.automation_run_data.model_id
Base(), automation_context.automation_run_data.branch_name
)
def test_create_version_in_project(
automation_context: AutomationContext,
) -> None:
model_id = automation_context.speckle_client.branch.create(
automation_context.automation_run_data.project_id, "foobar"
)
root_object = Base()
root_object.foo = "bar"
version_id = automation_context.create_new_version_in_project(root_object, model_id)
model_id, version_id = automation_context.create_new_version_in_project(
root_object, "foobar"
)
assert model_id is not None
assert version_id is not None
def test_set_context_view(automation_context: AutomationContext) -> None:
automation_context.set_context_view()
assert automation_context._automation_result.result_view is not None
assert automation_context._automation_result.result_view.endswith(
f"models/{automation_context.automation_run_data.model_id}@{automation_context.automation_run_data.version_id}"
)
automation_context._automation_result.result_view = None
dummy_context = "foo@bar"
automation_context.set_context_view([dummy_context])
assert automation_context._automation_result.result_view is not None
assert automation_context._automation_result.result_view.endswith(
f"models/{automation_context.automation_run_data.model_id}@{automation_context.automation_run_data.version_id},{dummy_context}"
)
automation_context._automation_result.result_view = None
dummy_context = "foo@baz"
automation_context.set_context_view(
[dummy_context], include_source_model_version=False
)
assert automation_context._automation_result.result_view is not None
assert automation_context._automation_result.result_view.endswith(
f"models/{dummy_context}"
)