Skip to content

Commit 17a5abb

Browse files
authored
Merge branch 'master' into feature/more-plus-button
2 parents 9a2aad8 + d7e9263 commit 17a5abb

33 files changed

+953
-360
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# pylint: disable=redefined-outer-name
2+
# pylint: disable=unused-argument
3+
# pylint: disable=unused-variable
4+
# pylint: disable=too-many-arguments
5+
6+
7+
from typing import Annotated
8+
9+
from fastapi import APIRouter, Depends, status
10+
from models_library.generics import Envelope
11+
from servicelib.aiohttp.long_running_tasks._routes import _PathParam
12+
from servicelib.long_running_tasks._models import TaskGet, TaskStatus
13+
from simcore_service_webserver._meta import API_VTAG
14+
15+
router = APIRouter(
16+
prefix=f"/{API_VTAG}/tasks-legacy",
17+
tags=[
18+
"long-running-tasks-legacy",
19+
],
20+
)
21+
22+
23+
@router.get(
24+
"",
25+
response_model=Envelope[list[TaskGet]],
26+
name="list_tasks",
27+
description="Lists all long running tasks",
28+
)
29+
def list_tasks(): ...
30+
31+
32+
@router.get(
33+
"/{task_id}",
34+
response_model=Envelope[TaskStatus],
35+
name="get_task_status",
36+
description="Retrieves the status of a task",
37+
)
38+
def get_task_status(
39+
_path_params: Annotated[_PathParam, Depends()],
40+
): ...
41+
42+
43+
@router.delete(
44+
"/{task_id}",
45+
name="cancel_and_delete_task",
46+
description="Cancels and deletes a task",
47+
status_code=status.HTTP_204_NO_CONTENT,
48+
)
49+
def cancel_and_delete_task(
50+
_path_params: Annotated[_PathParam, Depends()],
51+
): ...
52+
53+
54+
@router.get(
55+
"/{task_id}/result",
56+
name="get_task_result",
57+
description="Retrieves the result of a task",
58+
)
59+
def get_task_result(
60+
_path_params: Annotated[_PathParam, Depends()],
61+
): ...

api/specs/web-server/openapi.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"_exporter",
3737
"_folders",
3838
"_long_running_tasks",
39+
"_long_running_tasks_legacy",
3940
"_licensed_items",
4041
"_licensed_items_purchases",
4142
"_licensed_items_checkouts",

packages/pytest-simcore/src/pytest_simcore/helpers/catalog_rpc_server.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@
1212
from models_library.products import ProductName
1313
from models_library.rest_pagination import PageOffsetInt
1414
from models_library.rpc_pagination import PageLimitInt, PageRpc
15+
from models_library.services_enums import ServiceType
1516
from models_library.services_history import ServiceRelease
17+
from models_library.services_regex import (
18+
COMPUTATIONAL_SERVICE_KEY_RE,
19+
DYNAMIC_SERVICE_KEY_RE,
20+
)
1621
from models_library.services_types import ServiceKey, ServiceVersion
1722
from models_library.users import UserID
1823
from pydantic import NonNegativeInt, TypeAdapter
@@ -65,6 +70,14 @@ async def get_service(
6570
got.version = service_version
6671
got.key = service_key
6772

73+
if DYNAMIC_SERVICE_KEY_RE.match(got.key):
74+
got.service_type = ServiceType.DYNAMIC
75+
elif COMPUTATIONAL_SERVICE_KEY_RE.match(got.key):
76+
got.service_type = ServiceType.COMPUTATIONAL
77+
else:
78+
msg = "Service type not recognized. Please extend the mock yourself"
79+
raise RuntimeError(msg)
80+
6881
return got
6982

7083
async def update_service(

packages/pytest-simcore/src/pytest_simcore/helpers/httpx_calls_capture_parameters.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77

88
class CapturedParameterSchema(BaseModel):
99
title: str | None = None
10-
type_: Literal["str", "int", "float", "bool"] | None = Field(None, alias="type")
10+
type_: Literal["str", "int", "float", "bool", "null"] | None = Field(
11+
None, alias="type"
12+
)
1113
pattern: str | None = None
1214
format_: Literal["uuid"] | None = Field(None, alias="format")
1315
exclusiveMinimum: bool | None = None

services/api-server/openapi.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@
223223
"files"
224224
],
225225
"summary": "List Files",
226-
"description": "Lists all files stored in the system\n\nSEE `get_files_page` for a paginated version of this function",
226+
"description": "\ud83d\udea8 **Deprecated**: This endpoint is deprecated and will be removed in a future release.\nPlease use `GET /v0/files/page` instead.\n\n\n\nLists all files stored in the system\n\nAdded in *version 0.5*: \n\nRemoved in *version 0.7*: This endpoint is deprecated and will be removed in a future version",
227227
"operationId": "list_files",
228228
"responses": {
229229
"200": {
@@ -1414,7 +1414,7 @@
14141414
"solvers"
14151415
],
14161416
"summary": "List Solvers",
1417-
"description": "Lists all available solvers (latest version)\n\nSEE get_solvers_page for paginated version of this function",
1417+
"description": "\ud83d\udea8 **Deprecated**: This endpoint is deprecated and will be removed in a future release.\nPlease use `GET /v0/solvers/page` instead.\n\n\n\nLists all available solvers (latest version)\n\nNew in *version 0.5.0*\n\nRemoved in *version 0.7*: This endpoint is deprecated and will be removed in a future version",
14181418
"operationId": "list_solvers",
14191419
"responses": {
14201420
"200": {
@@ -2356,7 +2356,7 @@
23562356
"solvers"
23572357
],
23582358
"summary": "List Jobs",
2359-
"description": "List of jobs in a specific released solver (limited to 20 jobs)\n\n- DEPRECATION: This implementation and returned values are deprecated and the will be replaced by that of get_jobs_page\n- SEE `get_jobs_page` for paginated version of this function",
2359+
"description": "\ud83d\udea8 **Deprecated**: This endpoint is deprecated and will be removed in a future release.\nPlease use `GET /{solver_key}/releases/{version}/jobs/page` instead.\n\n\n\nList of jobs in a specific released solver\n\nNew in *version 0.5*\n\nRemoved in *version 0.7*: This endpoint is deprecated and will be removed in a future version",
23602360
"operationId": "list_jobs",
23612361
"security": [
23622362
{

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

Lines changed: 0 additions & 58 deletions
This file was deleted.
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import logging
2+
from collections.abc import Callable
3+
from typing import Annotated
4+
5+
from fastapi import Depends
6+
from models_library.api_schemas_webserver.projects import ProjectCreateNew, ProjectGet
7+
from models_library.projects import ProjectID
8+
from models_library.projects_nodes_io import NodeID
9+
from pydantic import HttpUrl
10+
from servicelib.fastapi.app_state import SingletonInAppStateMixin
11+
from servicelib.logging_utils import log_context
12+
13+
from .api.dependencies.webserver_http import get_webserver_session
14+
from .models.schemas.jobs import Job, JobInputs
15+
from .models.schemas.programs import Program
16+
from .models.schemas.solvers import Solver
17+
from .services_http.solver_job_models_converters import (
18+
create_job_from_project,
19+
create_new_project_for_job,
20+
)
21+
from .services_http.webserver import AuthSession
22+
23+
_logger = logging.getLogger(__name__)
24+
25+
26+
class JobService(SingletonInAppStateMixin):
27+
app_state_name = "JobService"
28+
_web_rest_api: AuthSession
29+
30+
def __init__(
31+
self, web_rest_api: Annotated[AuthSession, Depends(get_webserver_session)]
32+
):
33+
self._web_rest_api = web_rest_api
34+
35+
async def create_job(
36+
self,
37+
*,
38+
solver_or_program: Solver | Program,
39+
inputs: JobInputs,
40+
parent_project_uuid: ProjectID | None,
41+
parent_node_id: NodeID | None,
42+
url_for: Callable[..., HttpUrl],
43+
hidden: bool,
44+
) -> tuple[Job, ProjectGet]:
45+
# creates NEW job as prototype
46+
pre_job = Job.create_job_from_solver_or_program(
47+
solver_or_program_name=solver_or_program.name, inputs=inputs
48+
)
49+
with log_context(
50+
logger=_logger, level=logging.DEBUG, msg=f"Creating job {pre_job.name}"
51+
):
52+
project_in: ProjectCreateNew = create_new_project_for_job(
53+
solver_or_program, pre_job, inputs
54+
)
55+
new_project: ProjectGet = await self._web_rest_api.create_project(
56+
project_in,
57+
is_hidden=hidden,
58+
parent_project_uuid=parent_project_uuid,
59+
parent_node_id=parent_node_id,
60+
)
61+
62+
assert new_project # nosec
63+
assert new_project.uuid == pre_job.id # nosec
64+
65+
# for consistency, it rebuild job
66+
job = create_job_from_project(
67+
solver_or_program=solver_or_program, project=new_project, url_for=url_for
68+
)
69+
assert job.id == pre_job.id # nosec
70+
assert job.name == pre_job.name # nosec
71+
assert job.name == Job.compose_resource_name(
72+
parent_name=solver_or_program.resource_name,
73+
job_id=job.id,
74+
)
75+
return job, new_project
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from typing import Annotated
2+
3+
from fastapi import Depends
4+
from models_library.basic_types import VersionStr
5+
from models_library.services_enums import ServiceType
6+
7+
from .models.schemas.programs import Program, ProgramKeyId
8+
from .services_rpc.catalog import CatalogService
9+
10+
11+
class ProgramService:
12+
_catalog_service: CatalogService
13+
14+
def __init__(self, _catalog_service: Annotated[CatalogService, Depends()]):
15+
self._catalog_service = _catalog_service
16+
17+
async def get_program(
18+
self,
19+
*,
20+
user_id: int,
21+
name: ProgramKeyId,
22+
version: VersionStr,
23+
product_name: str,
24+
) -> Program:
25+
service = await self._catalog_service.get(
26+
user_id=user_id,
27+
name=name,
28+
version=version,
29+
product_name=product_name,
30+
)
31+
assert service.service_type == ServiceType.DYNAMIC # nosec
32+
33+
return Program.create_from_service(service)
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from typing import Annotated
2+
3+
from common_library.pagination_tools import iter_pagination_params
4+
from fastapi import Depends
5+
from models_library.basic_types import VersionStr
6+
from models_library.products import ProductName
7+
from models_library.rest_pagination import MAXIMUM_NUMBER_OF_ITEMS_PER_PAGE
8+
from models_library.services_enums import ServiceType
9+
from models_library.services_history import ServiceRelease
10+
from models_library.users import UserID
11+
from packaging.version import Version
12+
13+
from .models.schemas.solvers import Solver, SolverKeyId
14+
from .services_rpc.catalog import CatalogService
15+
16+
DEFAULT_PAGINATION_LIMIT = MAXIMUM_NUMBER_OF_ITEMS_PER_PAGE - 1
17+
18+
19+
class SolverService:
20+
_catalog_service: CatalogService
21+
22+
def __init__(self, catalog_service: Annotated[CatalogService, Depends()]):
23+
self._catalog_service = catalog_service
24+
25+
async def get_solver(
26+
self,
27+
*,
28+
user_id: UserID,
29+
name: SolverKeyId,
30+
version: VersionStr,
31+
product_name: ProductName,
32+
) -> Solver:
33+
service = await self._catalog_service.get(
34+
user_id=user_id,
35+
name=name,
36+
version=version,
37+
product_name=product_name,
38+
)
39+
assert ( # nosec
40+
service.service_type == ServiceType.COMPUTATIONAL
41+
), "Expected by SolverName regex"
42+
43+
return Solver.create_from_service(service)
44+
45+
async def get_latest_release(
46+
self,
47+
*,
48+
user_id: int,
49+
solver_key: SolverKeyId,
50+
product_name: str,
51+
) -> Solver:
52+
service_releases: list[ServiceRelease] = []
53+
for page_params in iter_pagination_params(limit=DEFAULT_PAGINATION_LIMIT):
54+
releases, page_meta = await self._catalog_service.list_release_history(
55+
user_id=user_id,
56+
service_key=solver_key,
57+
product_name=product_name,
58+
offset=page_params.offset,
59+
limit=page_params.limit,
60+
)
61+
page_params.total_number_of_items = page_meta.total
62+
service_releases.extend(releases)
63+
64+
release = sorted(service_releases, key=lambda s: Version(s.version))[-1]
65+
service = await self._catalog_service.get(
66+
user_id=user_id,
67+
name=solver_key,
68+
version=release.version,
69+
product_name=product_name,
70+
)
71+
72+
return Solver.create_from_service(service)

0 commit comments

Comments
 (0)