Skip to content

Commit

Permalink
[stu-337-test-profile] Merge branch 'main' into stu-337-test-profile
Browse files Browse the repository at this point in the history
  • Loading branch information
LatentDream committed Apr 16, 2024
2 parents 55b07f3 + bdcb2f5 commit 915ced9
Show file tree
Hide file tree
Showing 34 changed files with 1,042 additions and 591 deletions.
2 changes: 2 additions & 0 deletions captain/internal/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ async def wait_if_paused(self, id_of_test_waiting_for_resume: str):
created_at=utcnow_str(),
is_saved_to_cloud=False,
error=None,
value=None,
)
)
while self.pause:
Expand Down Expand Up @@ -86,6 +87,7 @@ def kill_runner(self):
utcnow_str(),
False,
"Test sequence was interrupted",
None,
)
)
)
Expand Down
4 changes: 4 additions & 0 deletions captain/models/test_sequencer.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ class Test(BaseModel):
completion_time: Optional[float] = Field(None, alias="completionTime")
is_saved_to_cloud: bool = Field(..., alias="isSavedToCloud")
export_to_cloud: bool = Field(..., alias="exportToCloud")
min_value: Optional[float] = Field(None, alias="minValue")
max_value: Optional[float] = Field(None, alias="maxValue")
measured_value: Optional[float] = Field(None, alias="measuredValue")
unit: Optional[str] = Field(None, alias="unit")


class Role(StrEnum):
Expand Down
115 changes: 68 additions & 47 deletions captain/routes/cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
from fastapi import APIRouter, Header, Response
from flojoy.env_var import get_env_var, get_flojoy_cloud_url
from flojoy_cloud import test_sequencer
from pydantic import BaseModel, ConfigDict
from pydantic.alias_generators import to_camel
from pydantic import BaseModel, Field
from typing import Annotated, Optional
import datetime
from typing import Literal
Expand Down Expand Up @@ -56,8 +55,8 @@ async def get_cloud_part_variation(part_variation_id: str):
response = requests.get(url, headers=headers_builder())
res = response.json()
res["partVariationId"] = part_variation_id
part_variation = PartVariation(**res)
return part_variation.model_dump()
logging.info("Part variation retrieved: %s", res)
return PartVariation(**res)


class SecretNotFound(Exception):
Expand Down Expand Up @@ -93,59 +92,66 @@ def headers_builder(with_workspace_id=True) -> dict:
return headers


class CamelModel(BaseModel):
model_config = ConfigDict(alias_generator=to_camel, protected_namespaces=())


class CloudModel(CamelModel):
class CloudModel(BaseModel):
id: str
created_at: datetime.datetime
created_at: str = Field(..., alias="createdAt")
workspace_id: str = Field(..., alias="workspaceId")


class Project(CloudModel):
name: str
updated_at: Optional[datetime.datetime]
workspace_id: str
part_variation_id: str
repo_url: Optional[str]
updated_at: Optional[datetime.datetime] = Field(..., alias="updatedAt")
part_variation_id: str = Field(..., alias="partVariationId")
repo_url: Optional[str] = Field(..., alias="repoUrl")


class Station(CloudModel):
class Part(CloudModel):
name: str
product_name: str = Field(..., alias="productName")
description: str


class PartVariation(BaseModel):
partId: str
partVariationId: str
partNumber: str
class Product(CloudModel):
name: str
description: str


class Unit(BaseModel):
serialNumber: str
lotNumber: Optional[str]
class Station(BaseModel):
id: str
created_at: str = Field(..., alias="createdAt")
name: str


class PartVariation(CloudModel):
part_id: str = Field(..., alias="partId")
part_variation_id: str = Field(..., alias="partVariationId")
part_number: str = Field(..., alias="partNumber")
description: str


class Unit(CloudModel):
serial_number: str = Field(..., alias="serialNumber")
lot_number: Optional[str] = Field(..., alias="lotNumber")
parent: Optional[str]
partVariationId: str
workspaceId: str
part_variation_id: str = Field(..., alias="partVariationId")


class Measurement(BaseModel):
testId: str
sequenceName: str
cycleNumber: int
class Measurement(CloudModel):
test_id: str = Field(..., alias="testId")
sequence_name: str = Field(..., alias="sequenceName")
cycle_number: int = Field(..., alias="cycleNumber")
name: str
pass_: Optional[bool]
completionTime: float
createdAt: str
completion_time: float = Field(..., alias="completionTime")


class Session(BaseModel):
serialNumber: str
stationId: str
class Session(CloudModel):
serial_number: str
station_id: str = Field(..., alias="stationId")
integrity: bool
aborted: bool
notes: str
commitHash: str
commit_hash: str = Field(..., alias="commitHash")
measurements: list[Measurement]


Expand Down Expand Up @@ -178,6 +184,14 @@ def get_measurement(m: Measurement) -> MeasurementData:
return data


async def get_part(part_id: str) -> Part:
logging.info("Querying part")
url = get_flojoy_cloud_url() + "part/" + part_id
response = requests.get(url, headers=headers_builder())
logging.info("Part retrieved: %s", response.json())
return Part(**response.json())


# Routes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Expand All @@ -195,20 +209,25 @@ async def get_cloud_projects():
response = requests.get(url, headers=headers_builder())
if response.status_code != 200:
return Response(status_code=response.status_code, content=json.dumps([]))
logging.info("Projects retrieved: %s", response.json())
projects = [Project(**project_data) for project_data in response.json()]
logging.info("Projects: %s", projects)
projects_res = []
for p in projects:
part_var = await get_cloud_part_variation(p.part_variation_id)
part = await get_part(part_var.part_id)
projects_res.append(
{
"label": p.name,
"value": p.id,
"part": part_var.model_dump(by_alias=True),
"repoUrl": p.repo_url,
"productName": part.product_name,
}
)
return Response(
status_code=200,
content=json.dumps(
[
{
"label": p.name,
"value": p.id,
"repoUrl": p.repo_url,
"part": await get_cloud_part_variation(p.part_variation_id),
}
for p in projects
]
),
content=json.dumps(projects_res),
)
except Exception as e:
return error_response_builder(e)
Expand All @@ -227,7 +246,9 @@ async def get_cloud_stations(project_id: str):
if response.status_code != 200:
logging.error(f"Error getting stations from Flojoy Cloud: {response.text}")
return Response(status_code=response.status_code, content=json.dumps([]))
logging.info("Stations retrieved: %s", response.json())
stations = [Station(**s) for s in response.json()]
logging.info("Stations: %s", stations)
if not stations:
return Response(status_code=404, content=json.dumps([]))
return Response(
Expand All @@ -250,7 +271,7 @@ async def get_cloud_variant_unit(part_var_id: str):
units = [Unit(**u) for u in response.json()]
if not units:
return Response(status_code=404, content=json.dumps([]))
dict_model = [unit.model_dump() for unit in units]
dict_model = [unit.model_dump(by_alias=True) for unit in units]
return Response(status_code=200, content=json.dumps(dict_model))
except Exception as e:
return error_response_builder(e)
Expand All @@ -261,7 +282,7 @@ async def post_cloud_session(_: Response, body: Session):
try:
logging.info("Posting session")
url = get_flojoy_cloud_url() + "session/"
payload = body.model_dump()
payload = body.model_dump(by_alias=True)
for i, m in enumerate(payload["measurements"]):
m["data"] = make_payload(get_measurement(body.measurements[i]))
m["pass"] = m.pop("pass_")
Expand Down
2 changes: 1 addition & 1 deletion captain/routes/test_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ async def install(url: Annotated[str, Header()]):
- Currently done for Github. (infer that the repo doesn't contain space)
- Private repo is not (directly) supported
TODO:
- [ ] Option if git is not install on the system
- [ ] Backup if git is not install on the system
"""
try:
logging.info(f"Installing the profile from the url: {url}")
Expand Down
12 changes: 11 additions & 1 deletion captain/types/test_sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,18 @@ class TestSequenceMessage(dict):
created_at: str
is_saved_to_cloud: bool
error: Optional[str]
value: Optional[float]

def __init__(
self, state, target_id, status, time_taken, created_at, is_saved_to_cloud, error
self,
state,
target_id,
status,
time_taken,
created_at,
is_saved_to_cloud,
error,
value,
):
self["state"] = state
self["target_id"] = target_id
Expand All @@ -36,6 +45,7 @@ def __init__(
self["created_at"] = created_at
self["is_saved_to_cloud"] = is_saved_to_cloud
self["error"] = error
self["value"] = value

def __setitem__(self, __key: Any, __value: Any) -> None:
super().__setattr__(__key, __value)
Expand Down
13 changes: 12 additions & 1 deletion captain/utils/test_sequencer/run_test_sequence.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import asyncio
from datetime import datetime
import logging
import subprocess
import time
from captain.routes.cloud import utcnow_str
Expand Down Expand Up @@ -67,8 +68,13 @@ async def wrapper(node: TestNode) -> Extract:
await _stream_result_to_frontend(
MsgState.running, test_id=node.id, result=StatusTypes.pending
)
test_sequencer._set_output_loc(node.id)
test_sequencer._set_output_loc(node.id, rm_existing_data=True)
logging.info(
f"Running test {node.id} - min: {node.min_value} | max: {node.max_value}"
)
test_sequencer._set_min_max(node.min_value, node.max_value)
children_getter, test_result = func(node)
measured_value = test_sequencer._get_most_recent_data(node.id)
if test_result is None:
raise Exception(f"{node.id}: Test returned None")
else:
Expand All @@ -80,6 +86,9 @@ async def wrapper(node: TestNode) -> Extract:
created_at=test_result.created_at,
error=test_result.error,
is_saved_to_cloud=False,
value=float(measured_value)
if isinstance(measured_value, float) or isinstance(measured_value, int)
else None,
)
return children_getter, test_result

Expand Down Expand Up @@ -190,6 +199,7 @@ async def _stream_result_to_frontend(
created_at: str = datetime.now().isoformat(),
is_saved_to_cloud: bool = False,
error: str | None = None,
value: float | None = None,
):
asyncio.create_task(
ts_manager.ws.broadcast(
Expand All @@ -201,6 +211,7 @@ async def _stream_result_to_frontend(
created_at,
is_saved_to_cloud,
error,
value,
)
)
)
Expand Down
Loading

0 comments on commit 915ced9

Please sign in to comment.