Skip to content

Commit 902c768

Browse files
committed
✨ Refactor project-related models and RPCs for consistency and clarity
- Rename ProjectRpcGet to ProjectJobRpcGet - Update job-related models to include workbench and job_parent_resource_name - Adjust job creation logic to use updated models - Modify tests to reflect model changes
1 parent d793717 commit 902c768

File tree

6 files changed

+87
-49
lines changed

6 files changed

+87
-49
lines changed

packages/models-library/src/models_library/rpc/webserver/projects.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
from datetime import datetime
22
from typing import Annotated, TypeAlias
33

4-
from models_library.projects import ProjectID
4+
from models_library.projects import NodesDict, ProjectID
55
from models_library.rpc_pagination import PageRpc
66
from pydantic import BaseModel, ConfigDict, Field
77
from pydantic.types import JsonDict
88

99

10-
class ProjectRpcGet(BaseModel):
10+
class ProjectJobRpcGet(BaseModel):
1111
"""
1212
Minimal information about a project that (for now) will fullfill
1313
the needs of the api-server. Specifically, the fields needed in
@@ -24,10 +24,14 @@ class ProjectRpcGet(BaseModel):
2424
]
2525
description: str
2626

27+
workbench: NodesDict
28+
2729
# timestamps
2830
creation_date: datetime
2931
last_change_date: datetime
3032

33+
job_parent_resource_name: str
34+
3135
@staticmethod
3236
def _update_json_schema_extra(schema: JsonDict) -> None:
3337
schema.udpate(
@@ -39,6 +43,8 @@ def _update_json_schema_extra(schema: JsonDict) -> None:
3943
"description": "My project description",
4044
"creation_date": "2023-01-01T00:00:00Z",
4145
"last_change_date": "2023-01-01T00:00:00Z",
46+
"job_parent_resource_name": "solvers/foo/release/1.2.3",
47+
"workbench": {},
4248
},
4349
]
4450
}
@@ -55,5 +61,5 @@ def _update_json_schema_extra(schema: JsonDict) -> None:
5561
# WARNING: keep this definition in models_library and not in the RPC interface
5662
# otherwise the metaclass PageRpc[*] will create *different* classes in server/client side
5763
# and will fail to serialize/deserialize these parameters when transmitted/received
58-
ProjectRpcGet
64+
ProjectJobRpcGet
5965
]

services/api-server/src/simcore_service_api_server/_service_solvers.py

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from fastapi import Depends
55
from models_library.basic_types import VersionStr
66
from models_library.products import ProductName
7+
from models_library.projects_nodes import Node
78
from models_library.rest_pagination import (
89
MAXIMUM_NUMBER_OF_ITEMS_PER_PAGE,
910
PageMetaInfoLimitOffset,
@@ -16,8 +17,9 @@
1617
from packaging.version import Version
1718

1819
from .api.dependencies.webserver_rpc import get_wb_api_rpc_client
19-
from .models.schemas.jobs import Job
20+
from .models.schemas.jobs import JobInputs, JobModel
2021
from .models.schemas.solvers import Solver, SolverKeyId
22+
from .models.solver_job_models_converters import create_job_inputs_from_node_inputs
2123
from .services_rpc.catalog import CatalogService
2224
from .services_rpc.wb_api_server import WbApiRpcClient
2325

@@ -93,7 +95,7 @@ async def list_jobs(
9395
product_name: ProductName,
9496
offset: PageOffsetInt = 0,
9597
limit: PageLimitInt = DEFAULT_PAGINATION_LIMIT,
96-
) -> tuple[list[Job], PageMetaInfoLimitOffset]:
98+
) -> tuple[list[JobModel], PageMetaInfoLimitOffset]:
9799
"""Lists all solver jobs for a user with pagination"""
98100

99101
# NOTE: perhaps we should get comp_tasks instead of projects! or a combinatino of both?
@@ -107,18 +109,28 @@ async def list_jobs(
107109
job_parent_resource_name_filter="solvers", # TODO: project shouldr eturn parent resource name and workbench
108110
)
109111

110-
solver = None # TODO
111-
url_for = None # TODO
112-
113-
jobs: list[Job] = [
114-
Job(
115-
id=prj.uuid,
116-
name=prj.name,
117-
inputs_checksum=prj.inputs_checksum,
118-
created_at=prj.creation_date, # type: ignore[arg-type]
119-
runner_name=prj.job_parent_resource_name,
120-
# TODO: url_ parts missing
112+
jobs: list[JobModel] = []
113+
114+
for prj in projects_page.data:
115+
116+
assert len(prj.workbench) == 1, "Expected only one solver node in workbench"
117+
118+
solver_node: Node = next(iter(prj.workbench.values()))
119+
job_inputs: JobInputs = create_job_inputs_from_node_inputs(
120+
inputs=solver_node.inputs or {}
121121
)
122-
for prj in projects_page.data
123-
]
122+
assert prj.job_parent_resource_name # nosec
123+
124+
jobs.append(
125+
JobModel(
126+
id=prj.uuid,
127+
name=JobModel.compose_resource_name(
128+
prj.job_parent_resource_name, prj.uuid
129+
),
130+
inputs_checksum=job_inputs.compute_checksum(),
131+
created_at=prj.creation_date,
132+
runner_name=prj.job_parent_resource_name,
133+
)
134+
)
135+
124136
return jobs, projects_page.meta

services/api-server/src/simcore_service_api_server/models/schemas/jobs.py

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
ValidationInfo,
2828
field_validator,
2929
)
30+
from pydantic.types import JsonDict
3031
from servicelib.logging_utils import LogLevelInt, LogMessageStr
3132
from starlette.datastructures import Headers
3233

@@ -237,7 +238,7 @@ class JobMetadata(BaseModel):
237238
# "jobs/c2789bd2-7385-4e00-91d3-2f100df41185"
238239

239240

240-
class Job(BaseModel):
241+
class JobModel(BaseModel):
241242
id: JobID
242243
name: RelativeResourceName
243244

@@ -249,6 +250,41 @@ class Job(BaseModel):
249250
..., description="Runner that executes job"
250251
)
251252

253+
@staticmethod
254+
def _update_json_schema_extra(schema: JsonDict) -> None:
255+
schema.udpate(
256+
{
257+
"examples": [
258+
{
259+
"id": "f622946d-fd29-35b9-a193-abdd1095167c",
260+
"name": "solvers/isolve/releases/1.3.4/jobs/f622946d-fd29-35b9-a193-abdd1095167c",
261+
"runner_name": "solvers/isolve/releases/1.3.4",
262+
"inputs_checksum": "12345",
263+
"created_at": "2021-01-22T23:59:52.322176",
264+
},
265+
]
266+
}
267+
)
268+
269+
model_config = ConfigDict(
270+
json_schema_extra=_update_json_schema_extra,
271+
)
272+
273+
@staticmethod
274+
def compose_resource_name(
275+
parent_name: RelativeResourceName, job_id: UUID
276+
) -> RelativeResourceName:
277+
# CAREFUL, this is not guarantee a UNIQUE identifier since the resource
278+
# could have some alias entrypoints and the wrong parent_name might be introduced here
279+
collection_or_resource_ids = [
280+
*split_resource_name(parent_name),
281+
"jobs",
282+
f"{job_id}",
283+
]
284+
return compose_resource_name(*collection_or_resource_ids)
285+
286+
287+
class Job(JobModel):
252288
# Get links to other resources
253289
url: Annotated[HttpUrl, UriSchema()] | None = Field(
254290
..., description="Link to get this resource (self)"
@@ -284,6 +320,11 @@ def _check_name(cls, v, info: ValidationInfo):
284320
raise ValueError(msg)
285321
return v
286322

323+
@property
324+
def resource_name(self) -> str:
325+
"""Relative Resource Name"""
326+
return self.name
327+
287328
# constructors ------
288329

289330
@classmethod
@@ -312,24 +353,6 @@ def create_job_from_solver_or_program(
312353
inputs_checksum=inputs.compute_checksum(),
313354
)
314355

315-
@classmethod
316-
def compose_resource_name(
317-
cls, parent_name: RelativeResourceName, job_id: UUID
318-
) -> RelativeResourceName:
319-
# CAREFUL, this is not guarantee a UNIQUE identifier since the resource
320-
# could have some alias entrypoints and the wrong parent_name might be introduced here
321-
collection_or_resource_ids = [
322-
*split_resource_name(parent_name),
323-
"jobs",
324-
f"{job_id}",
325-
]
326-
return compose_resource_name(*collection_or_resource_ids)
327-
328-
@property
329-
def resource_name(self) -> str:
330-
"""Relative Resource Name"""
331-
return self.name
332-
333356

334357
def get_url(
335358
solver_or_program: Solver | Program, url_for: Callable[..., HttpUrl], job_id: JobID

services/api-server/src/simcore_service_api_server/models/solver_job_models_converters.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
from models_library.basic_types import KeyIDStr
1616
from models_library.projects import Project
1717
from models_library.projects_nodes import InputID
18-
from models_library.rpc.webserver.projects import ProjectRpcGet
1918
from pydantic import HttpUrl, TypeAdapter
2019

2120
from ..services_http.director_v2 import ComputationTaskGet
@@ -183,7 +182,7 @@ def create_new_project_for_job(
183182
def create_job_from_project(
184183
*,
185184
solver_or_program: Solver | Program,
186-
project: ProjectRpcGet | ProjectGet | Project,
185+
project: ProjectGet | Project,
187186
url_for: Callable[..., HttpUrl],
188187
) -> Job:
189188
"""
@@ -198,9 +197,7 @@ def create_job_from_project(
198197
assert solver_or_program.version in project.name # nosec
199198
assert urllib.parse.quote_plus(solver_or_program.id) in project.name # nosec
200199

201-
# get solver node
202-
node_id = next(iter(project.workbench.keys()))
203-
solver_node: Node = project.workbench[node_id]
200+
solver_node: Node = next(iter(project.workbench.values()))
204201
job_inputs: JobInputs = create_job_inputs_from_node_inputs(
205202
inputs=solver_node.inputs or {}
206203
)
@@ -210,7 +207,7 @@ def create_job_from_project(
210207

211208
job_id = project.uuid
212209

213-
job = Job(
210+
return Job(
214211
id=job_id,
215212
name=project.name,
216213
inputs_checksum=job_inputs.compute_checksum(),
@@ -225,8 +222,6 @@ def create_job_from_project(
225222
),
226223
)
227224

228-
return job
229-
230225

231226
def create_jobstatus_from_task(task: ComputationTaskGet) -> JobStatus:
232227
return JobStatus(

services/web/server/src/simcore_service_webserver/projects/_controller/projects_rpc.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from models_library.products import ProductName
44
from models_library.projects import ProjectID
55
from models_library.rest_pagination import PageLimitInt, PageOffsetInt
6-
from models_library.rpc.webserver.projects import PageRpcProjectRpcGet, ProjectRpcGet
6+
from models_library.rpc.webserver.projects import PageRpcProjectRpcGet, ProjectJobRpcGet
77
from models_library.users import UserID
88
from pydantic import ValidationError, validate_call
99
from servicelib.rabbitmq import RPCRouter
@@ -76,12 +76,14 @@ async def list_projects_marked_as_jobs(
7676
)
7777

7878
job_projects = [
79-
ProjectRpcGet(
79+
ProjectJobRpcGet(
8080
uuid=project.uuid,
8181
name=project.name,
8282
description=project.description,
83+
workbench={}, # FIXME: this should be extracted
8384
creation_date=project.creation_date,
8485
last_change_date=project.last_change_date,
86+
job_parent_resource_name=project.job_parent_resource_name,
8587
)
8688
for project in projects
8789
]

services/web/server/tests/unit/with_dbs/02/test_projects_rpc.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from common_library.users_enums import UserRole
1313
from models_library.products import ProductName
1414
from models_library.projects import ProjectID
15-
from models_library.rpc.webserver.projects import PageRpcProjectRpcGet, ProjectRpcGet
15+
from models_library.rpc.webserver.projects import PageRpcProjectRpcGet, ProjectJobRpcGet
1616
from pydantic import ValidationError
1717
from pytest_simcore.helpers.monkeypatch_envs import setenvs_from_dict
1818
from pytest_simcore.helpers.typing_env import EnvVarsDict
@@ -116,7 +116,7 @@ async def test_rpc_client_list_my_projects_marked_as_jobs(
116116

117117
assert page.meta.total == 1
118118
assert page.meta.offset == 0
119-
assert isinstance(page.data[0], ProjectRpcGet)
119+
assert isinstance(page.data[0], ProjectJobRpcGet)
120120
assert page.data[0].uuid == project_uuid
121121

122122

0 commit comments

Comments
 (0)