Skip to content

Commit 68d8fe5

Browse files
committed
Split function route files and solve other comments
1 parent b61d3c8 commit 68d8fe5

File tree

10 files changed

+406
-395
lines changed

10 files changed

+406
-395
lines changed

packages/postgres-database/src/simcore_postgres_database/models/funcapi_function_job_collections_table.py

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import uuid
22

33
import sqlalchemy as sa
4+
from simcore_postgres_database.models._common import (
5+
column_created_datetime,
6+
column_modified_datetime,
7+
)
48
from sqlalchemy.dialects.postgresql import UUID
5-
from sqlalchemy.sql import func
69

710
from .base import metadata
811

@@ -27,20 +30,7 @@
2730
sa.String,
2831
doc="Description of the function job collection",
2932
),
30-
sa.Column(
31-
"created",
32-
sa.DateTime(),
33-
nullable=False,
34-
server_default=func.now(),
35-
doc="Timestamp auto-generated upon creation",
36-
),
37-
sa.Column(
38-
"modified",
39-
sa.DateTime(),
40-
nullable=False,
41-
server_default=func.now(),
42-
onupdate=func.now(),
43-
doc="Automaticaly updates on modification of the row",
44-
),
33+
column_created_datetime(),
34+
column_modified_datetime(),
4535
sa.PrimaryKeyConstraint("uuid", name="funcapi_function_job_collections_pk"),
4636
)

packages/postgres-database/src/simcore_postgres_database/models/funcapi_function_job_collections_to_function_jobs_table.py

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44
"""
55

66
import sqlalchemy as sa
7-
from sqlalchemy.sql import func
87

9-
from ._common import RefActions
8+
from ._common import RefActions, column_created_datetime, column_modified_datetime
109
from .base import metadata
1110
from .funcapi_function_job_collections_table import function_job_collections_table
1211
from .funcapi_function_jobs_table import function_jobs_table
@@ -22,6 +21,7 @@
2221
ondelete=RefActions.CASCADE,
2322
name="fk_func_job_coll_to_func_jobs_to_func_job_coll_uuid",
2423
),
24+
nullable=False,
2525
doc="Unique identifier of the function job collection",
2626
),
2727
sa.Column(
@@ -32,21 +32,14 @@
3232
ondelete=RefActions.CASCADE,
3333
name="fk_func_job_coll_to_func_jobs_to_func_job_uuid",
3434
),
35-
doc="Unique identifier of the function job",
36-
),
37-
sa.Column(
38-
"created",
39-
sa.DateTime(),
4035
nullable=False,
41-
server_default=func.now(),
42-
doc="Timestamp auto-generated upon creation",
36+
doc="Unique identifier of the function job",
4337
),
44-
sa.Column(
45-
"modified",
46-
sa.DateTime(),
47-
nullable=False,
48-
server_default=func.now(),
49-
onupdate=func.now(),
50-
doc="Automaticaly updates on modification of the row",
38+
column_created_datetime(),
39+
column_modified_datetime(),
40+
sa.PrimaryKeyConstraint(
41+
"function_job_collection_uuid",
42+
"function_job_uuid",
43+
name="funcapi_function_job_collections_to_function_jobs_pk",
5144
),
5245
)

packages/postgres-database/src/simcore_postgres_database/models/funcapi_function_jobs_table.py

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77

88
import sqlalchemy as sa
99
from sqlalchemy.dialects.postgresql import UUID
10-
from sqlalchemy.sql import func
1110

12-
from ._common import RefActions
11+
from ._common import RefActions, column_created_datetime, column_modified_datetime
1312
from .base import metadata
1413
from .funcapi_functions_table import functions_table
1514

@@ -72,20 +71,7 @@
7271
nullable=True,
7372
doc="Fields specific for a function class",
7473
),
75-
sa.Column(
76-
"created",
77-
sa.DateTime(),
78-
nullable=False,
79-
server_default=func.now(),
80-
doc="Timestamp auto-generated upon creation",
81-
),
82-
sa.Column(
83-
"modified",
84-
sa.DateTime(),
85-
nullable=False,
86-
server_default=func.now(),
87-
onupdate=func.now(),
88-
doc="Automaticaly updates on modification of the row",
89-
),
74+
column_created_datetime(),
75+
column_modified_datetime(),
9076
sa.PrimaryKeyConstraint("uuid", name="funcapi_function_jobs_pk"),
9177
)

packages/postgres-database/src/simcore_postgres_database/models/funcapi_functions_table.py

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
import uuid
77

88
import sqlalchemy as sa
9+
from simcore_postgres_database.models._common import (
10+
column_created_datetime,
11+
column_modified_datetime,
12+
)
913
from sqlalchemy.dialects.postgresql import UUID
1014

1115
from .base import metadata
@@ -70,20 +74,7 @@
7074
nullable=True,
7175
doc="Default inputs of the function",
7276
),
73-
sa.Column(
74-
"created",
75-
sa.DateTime,
76-
nullable=False,
77-
server_default=sa.func.now(),
78-
doc="Creation timestamp of the function",
79-
),
80-
sa.Column(
81-
"modified",
82-
sa.DateTime,
83-
nullable=False,
84-
server_default=sa.func.now(),
85-
onupdate=sa.func.now(),
86-
doc="Last update timestamp of the function",
87-
),
77+
column_created_datetime(),
78+
column_modified_datetime(),
8879
sa.PrimaryKeyConstraint("uuid", name="funcapi_functions_pk"),
8980
)

packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/webserver/functions/functions_rpc_interface.py

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,9 @@ async def list_functions(
113113
pagination_limit=pagination_limit,
114114
)
115115
)
116-
assert isinstance(result, tuple)
117-
TypeAdapter(list[RegisteredFunction]).validate_python(
118-
result[0]
119-
) # Validates the result as a list of RegisteredFunctions
120-
assert isinstance(result[1], PageMetaInfoLimitOffset) # nosec
121-
return result
116+
return TypeAdapter(
117+
tuple[list[RegisteredFunction], PageMetaInfoLimitOffset]
118+
).validate_python(result)
122119

123120

124121
@log_decorator(_logger, level=logging.DEBUG)
@@ -136,16 +133,9 @@ async def list_function_jobs(
136133
pagination_limit=pagination_limit,
137134
)
138135
)
139-
assert isinstance(result, tuple) # nosec
140-
assert isinstance(result[0], list) # nosec
141-
assert all(
142-
TypeAdapter(RegisteredFunctionJob).validate_python(item) for item in result[0]
143-
) # nosec
144-
assert isinstance(result[1], PageMetaInfoLimitOffset) # nosec
145-
return (
146-
TypeAdapter(list[RegisteredFunctionJob]).validate_python(result[0]),
147-
TypeAdapter(PageMetaInfoLimitOffset).validate_python(result[1]),
148-
)
136+
return TypeAdapter(
137+
tuple[list[RegisteredFunctionJob], PageMetaInfoLimitOffset]
138+
).validate_python(result)
149139

150140

151141
@log_decorator(_logger, level=logging.DEBUG)

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
from .routes import credits as _credits
77
from .routes import (
88
files,
9+
function_job_collections_routes,
10+
function_jobs_routes,
911
functions_routes,
1012
health,
1113
licensed_items,
@@ -46,12 +48,12 @@ def create_router(settings: ApplicationSettings):
4648
router.include_router(studies.router, tags=["studies"], prefix="/studies")
4749
router.include_router(studies_jobs.router, tags=["studies"], prefix="/studies")
4850
router.include_router(
49-
functions_routes.function_job_router,
51+
function_jobs_routes.function_job_router,
5052
tags=["function_jobs"],
5153
prefix=_FUNCTION_JOBS_PREFIX,
5254
)
5355
router.include_router(
54-
functions_routes.function_job_collections_router,
56+
function_job_collections_routes.function_job_collections_router,
5557
tags=["function_job_collections"],
5658
prefix=_FUNCTION_JOB_COLLECTIONS_PREFIX,
5759
)
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import asyncio
2+
from typing import Annotated, Final
3+
4+
from fastapi import APIRouter, Depends, status
5+
from fastapi_pagination.api import create_page
6+
from models_library.api_schemas_webserver.functions_wb_schema import (
7+
FunctionJobCollection,
8+
FunctionJobCollectionID,
9+
FunctionJobCollectionStatus,
10+
RegisteredFunctionJob,
11+
RegisteredFunctionJobCollection,
12+
)
13+
from pydantic import PositiveInt
14+
15+
from ...models.pagination import Page, PaginationParams
16+
from ...models.schemas.errors import ErrorGet
17+
from ...services_http.director_v2 import DirectorV2Api
18+
from ...services_rpc.wb_api_server import WbApiRpcClient
19+
from ..dependencies.authentication import get_current_user_id
20+
from ..dependencies.services import get_api_client
21+
from ..dependencies.webserver_rpc import get_wb_api_rpc_client
22+
from .function_jobs_routes import function_job_status, get_function_job
23+
24+
# pylint: disable=too-many-arguments
25+
26+
function_job_collections_router = APIRouter()
27+
28+
29+
_COMMON_FUNCTION_JOB_COLLECTION_ERROR_RESPONSES: Final[dict] = {
30+
status.HTTP_404_NOT_FOUND: {
31+
"description": "Function job collection not found",
32+
"model": ErrorGet,
33+
},
34+
}
35+
36+
37+
@function_job_collections_router.get(
38+
"",
39+
response_model=Page[RegisteredFunctionJobCollection],
40+
description="List function job collections",
41+
)
42+
async def list_function_job_collections(
43+
wb_api_rpc: Annotated[WbApiRpcClient, Depends(get_wb_api_rpc_client)],
44+
page_params: Annotated[PaginationParams, Depends()],
45+
):
46+
function_job_collection_list, meta = await wb_api_rpc.list_function_job_collections(
47+
pagination_offset=page_params.offset,
48+
pagination_limit=page_params.limit,
49+
)
50+
return create_page(
51+
function_job_collection_list,
52+
total=meta.total,
53+
params=page_params,
54+
)
55+
56+
57+
@function_job_collections_router.get(
58+
"/{function_job_collection_id:uuid}",
59+
response_model=RegisteredFunctionJobCollection,
60+
responses={**_COMMON_FUNCTION_JOB_COLLECTION_ERROR_RESPONSES},
61+
description="Get function job collection",
62+
)
63+
async def get_function_job_collection(
64+
function_job_collection_id: FunctionJobCollectionID,
65+
wb_api_rpc: Annotated[WbApiRpcClient, Depends(get_wb_api_rpc_client)],
66+
) -> RegisteredFunctionJobCollection:
67+
return await wb_api_rpc.get_function_job_collection(
68+
function_job_collection_id=function_job_collection_id
69+
)
70+
71+
72+
@function_job_collections_router.post(
73+
"",
74+
response_model=RegisteredFunctionJobCollection,
75+
description="Register function job collection",
76+
)
77+
async def register_function_job_collection(
78+
function_job_collection: FunctionJobCollection,
79+
wb_api_rpc: Annotated[WbApiRpcClient, Depends(get_wb_api_rpc_client)],
80+
) -> RegisteredFunctionJobCollection:
81+
return await wb_api_rpc.register_function_job_collection(
82+
function_job_collection=function_job_collection
83+
)
84+
85+
86+
@function_job_collections_router.delete(
87+
"/{function_job_collection_id:uuid}",
88+
response_model=None,
89+
responses={**_COMMON_FUNCTION_JOB_COLLECTION_ERROR_RESPONSES},
90+
description="Delete function job collection",
91+
)
92+
async def delete_function_job_collection(
93+
function_job_collection_id: FunctionJobCollectionID,
94+
wb_api_rpc: Annotated[WbApiRpcClient, Depends(get_wb_api_rpc_client)],
95+
) -> None:
96+
return await wb_api_rpc.delete_function_job_collection(
97+
function_job_collection_id=function_job_collection_id
98+
)
99+
100+
101+
@function_job_collections_router.get(
102+
"/{function_job_collection_id:uuid}/function_jobs",
103+
response_model=list[RegisteredFunctionJob],
104+
responses={**_COMMON_FUNCTION_JOB_COLLECTION_ERROR_RESPONSES},
105+
description="Get the function jobs in function job collection",
106+
)
107+
async def function_job_collection_list_function_jobs(
108+
function_job_collection_id: FunctionJobCollectionID,
109+
wb_api_rpc: Annotated[WbApiRpcClient, Depends(get_wb_api_rpc_client)],
110+
) -> list[RegisteredFunctionJob]:
111+
function_job_collection = await get_function_job_collection(
112+
function_job_collection_id=function_job_collection_id,
113+
wb_api_rpc=wb_api_rpc,
114+
)
115+
return [
116+
await get_function_job(
117+
job_id,
118+
wb_api_rpc=wb_api_rpc,
119+
)
120+
for job_id in function_job_collection.job_ids
121+
]
122+
123+
124+
@function_job_collections_router.get(
125+
"/{function_job_collection_id:uuid}/status",
126+
response_model=FunctionJobCollectionStatus,
127+
responses={**_COMMON_FUNCTION_JOB_COLLECTION_ERROR_RESPONSES},
128+
description="Get function job collection status",
129+
)
130+
async def function_job_collection_status(
131+
function_job_collection_id: FunctionJobCollectionID,
132+
wb_api_rpc: Annotated[WbApiRpcClient, Depends(get_wb_api_rpc_client)],
133+
director2_api: Annotated[DirectorV2Api, Depends(get_api_client(DirectorV2Api))],
134+
user_id: Annotated[PositiveInt, Depends(get_current_user_id)],
135+
) -> FunctionJobCollectionStatus:
136+
function_job_collection = await get_function_job_collection(
137+
function_job_collection_id=function_job_collection_id,
138+
wb_api_rpc=wb_api_rpc,
139+
)
140+
141+
job_statuses = await asyncio.gather(
142+
*[
143+
function_job_status(
144+
job_id,
145+
wb_api_rpc=wb_api_rpc,
146+
director2_api=director2_api,
147+
user_id=user_id,
148+
)
149+
for job_id in function_job_collection.job_ids
150+
]
151+
)
152+
return FunctionJobCollectionStatus(
153+
status=[job_status.status for job_status in job_statuses]
154+
)

0 commit comments

Comments
 (0)