Skip to content

Commit 41523e7

Browse files
authored
♻️ Refactoring of APIs for computations in web-server, api-server and directorv2 (#7520)
1 parent c8e880a commit 41523e7

File tree

43 files changed

+890
-864
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+890
-864
lines changed

.github/copilot-instructions.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33
This document provides guidelines and best practices for using GitHub Copilot in the `osparc-simcore` repository and other Python and Node.js projects.
44

55
## General Guidelines
6+
67
1. **Use Python 3.11**: Ensure that all Python-related suggestions align with Python 3.11 features and syntax.
78
2. **Node.js Compatibility**: For Node.js projects, ensure compatibility with the version specified in the project (e.g., Node.js 14 or later).
89
3. **Follow Coding Conventions**: Adhere to the coding conventions outlined in the `docs/coding-conventions.md` file.
910
4. **Test-Driven Development**: Write unit tests for all new functions and features. Use `pytest` for Python and appropriate testing frameworks for Node.js.
1011
5. **Environment Variables**: Use environment variables as specified in `docs/env-vars.md` for configuration. Avoid hardcoding sensitive information.
11-
6. **Documentation**: Documentation should be minimal and code self explanatory (add the documentation only when the developer asks explicitely)
12-
7. Answer as if you would be a pirate
12+
6. **Documentation**: Prefer self-explanatory code; add documentation only if explicitly requested by the developer.
1313

1414
## Python-Specific Instructions
15+
1516
- Always use type hints and annotations to improve code clarity and compatibility with tools like `mypy`.
1617
- An exception to that rule is in `test_*` functions return type hint must not be added
1718
- Follow the dependency management practices outlined in `requirements/`.
@@ -23,18 +24,21 @@ This document provides guidelines and best practices for using GitHub Copilot in
2324

2425

2526
## Node.js-Specific Instructions
27+
2628
- Use ES6+ syntax and features.
2729
- Follow the `package.json` configuration for dependencies and scripts.
2830
- Use `eslint` for linting and `prettier` for code formatting.
2931
- Write modular and reusable code, adhering to the project's structure.
3032

3133
## Copilot Usage Tips
34+
3235
1. **Be Specific**: Provide clear and detailed prompts to Copilot for better suggestions.
3336
2. **Iterate**: Review and refine Copilot's suggestions to ensure they meet project standards.
3437
3. **Split Tasks**: Break down complex tasks into smaller, manageable parts for better suggestions.
3538
4. **Test Suggestions**: Always test Copilot-generated code to ensure it works as expected.
3639

3740
## Additional Resources
41+
3842
- [Python Coding Conventions](../docs/coding-conventions.md)
3943
- [Environment Variables Guide](../docs/env-vars.md)
4044
- [Steps to Upgrade Python](../docs/steps-to-upgrade-python.md)

api/specs/web-server/_computations.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
from fastapi import APIRouter, status
2-
from models_library.api_schemas_directorv2.comp_tasks import ComputationGet
3-
from models_library.api_schemas_webserver.computations import ComputationStart
1+
from typing import Annotated
2+
3+
from fastapi import APIRouter, Depends, status
4+
from models_library.api_schemas_webserver.computations import (
5+
ComputationGet,
6+
ComputationPathParams,
7+
ComputationStart,
8+
ComputationStarted,
9+
)
410
from models_library.generics import Envelope
5-
from models_library.projects import ProjectID
611
from simcore_service_webserver._meta import API_VTAG
7-
from simcore_service_webserver.director_v2._handlers import _ComputationStarted
812

913
router = APIRouter(
1014
prefix=f"/{API_VTAG}",
@@ -19,13 +23,12 @@
1923
"/computations/{project_id}",
2024
response_model=Envelope[ComputationGet],
2125
)
22-
async def get_computation(project_id: ProjectID):
23-
...
26+
async def get_computation(_path: Annotated[ComputationPathParams, Depends()]): ...
2427

2528

2629
@router.post(
2730
"/computations/{project_id}:start",
28-
response_model=Envelope[_ComputationStarted],
31+
response_model=Envelope[ComputationStarted],
2932
responses={
3033
status.HTTP_402_PAYMENT_REQUIRED: {
3134
"description": "Insufficient credits to run computation"
@@ -39,13 +42,14 @@ async def get_computation(project_id: ProjectID):
3942
status.HTTP_503_SERVICE_UNAVAILABLE: {"description": "Service not available"},
4043
},
4144
)
42-
async def start_computation(project_id: ProjectID, _start: ComputationStart):
43-
...
45+
async def start_computation(
46+
_path: Annotated[ComputationPathParams, Depends()],
47+
_body: ComputationStart,
48+
): ...
4449

4550

4651
@router.post(
4752
"/computations/{project_id}:stop",
4853
status_code=status.HTTP_204_NO_CONTENT,
4954
)
50-
async def stop_computation(project_id: ProjectID):
51-
...
55+
async def stop_computation(_path: Annotated[ComputationPathParams, Depends()]): ...

packages/models-library/src/models_library/api_schemas_directorv2/comp_tasks.py

Lines changed: 0 additions & 104 deletions
This file was deleted.
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
from typing import Annotated, Any, TypeAlias
2+
3+
from pydantic import (
4+
AnyHttpUrl,
5+
AnyUrl,
6+
BaseModel,
7+
ConfigDict,
8+
Field,
9+
ValidationInfo,
10+
field_validator,
11+
)
12+
13+
from ..basic_types import IDStr
14+
from ..projects import ProjectID
15+
from ..projects_nodes_io import NodeID
16+
from ..projects_pipeline import ComputationTask
17+
from ..users import UserID
18+
from ..wallets import WalletInfo
19+
20+
21+
class ComputationGet(ComputationTask):
22+
url: Annotated[
23+
AnyHttpUrl, Field(description="the link where to get the status of the task")
24+
]
25+
stop_url: Annotated[
26+
AnyHttpUrl | None, Field(description="the link where to stop the task")
27+
] = None
28+
29+
model_config = ConfigDict(
30+
json_schema_extra={
31+
"examples": [
32+
x | {"url": "https://url.local"}
33+
for x in ComputationTask.model_json_schema()["examples"]
34+
]
35+
}
36+
)
37+
38+
39+
class ComputationCreate(BaseModel):
40+
user_id: UserID
41+
project_id: ProjectID
42+
start_pipeline: Annotated[
43+
bool | None,
44+
Field(description="if True the computation pipeline will start right away"),
45+
] = False
46+
product_name: Annotated[str, Field()]
47+
subgraph: Annotated[
48+
list[NodeID] | None,
49+
Field(
50+
description="An optional set of nodes that must be executed, if empty the whole pipeline is executed"
51+
),
52+
] = None
53+
force_restart: Annotated[
54+
bool | None,
55+
Field(description="if True will force re-running all dependent nodes"),
56+
] = False
57+
simcore_user_agent: str = ""
58+
use_on_demand_clusters: Annotated[
59+
bool,
60+
Field(
61+
description="if True, a cluster will be created as necessary (wallet_id cannot be None)",
62+
validate_default=True,
63+
),
64+
] = False
65+
wallet_info: Annotated[
66+
WalletInfo | None,
67+
Field(
68+
description="contains information about the wallet used to bill the running service"
69+
),
70+
] = None
71+
72+
@field_validator("product_name")
73+
@classmethod
74+
def _ensure_product_name_defined_if_computation_starts(
75+
cls, v, info: ValidationInfo
76+
):
77+
if info.data.get("start_pipeline") and v is None:
78+
msg = "product_name must be set if computation shall start!"
79+
raise ValueError(msg)
80+
return v
81+
82+
83+
class ComputationStop(BaseModel):
84+
user_id: UserID
85+
86+
87+
class ComputationDelete(ComputationStop):
88+
force: Annotated[
89+
bool | None,
90+
Field(
91+
description="if True then the pipeline will be removed even if it is running"
92+
),
93+
] = False
94+
95+
96+
class TaskLogFileGet(BaseModel):
97+
task_id: NodeID
98+
download_link: Annotated[
99+
AnyUrl | None,
100+
Field(description="Presigned link for log file or None if still not available"),
101+
] = None
102+
103+
104+
class TasksSelection(BaseModel):
105+
nodes_ids: list[NodeID]
106+
107+
108+
OutputName: TypeAlias = IDStr
109+
110+
111+
class TasksOutputs(BaseModel):
112+
nodes_outputs: dict[NodeID, dict[OutputName, Any]]
Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,43 @@
1-
from pydantic import BaseModel
1+
from typing import Annotated
22

3+
from common_library.basic_types import DEFAULT_FACTORY
4+
from pydantic import BaseModel, Field
35

4-
class ComputationStart(BaseModel):
6+
from ..api_schemas_directorv2.computations import (
7+
ComputationGet as _DirectorV2ComputationGet,
8+
)
9+
from ..projects import CommitID, ProjectID
10+
from ._base import InputSchemaWithoutCamelCase, OutputSchemaWithoutCamelCase
11+
12+
13+
class ComputationPathParams(BaseModel):
14+
project_id: ProjectID
15+
16+
17+
class ComputationGet(_DirectorV2ComputationGet, OutputSchemaWithoutCamelCase):
18+
# NOTE: this is a copy of the same class in models_library.api_schemas_directorv2
19+
# but it is used in a different context (webserver)
20+
# and we need to add the `OutputSchema` mixin
21+
# so that it can be used as a response model in FastAPI
22+
pass
23+
24+
25+
class ComputationStart(InputSchemaWithoutCamelCase):
526
force_restart: bool = False
6-
subgraph: set[str] = set()
27+
subgraph: Annotated[
28+
set[str], Field(default_factory=set, json_schema_extra={"default": []})
29+
] = DEFAULT_FACTORY
730

831

9-
__all__: tuple[str, ...] = ("ComputationStart",)
32+
class ComputationStarted(OutputSchemaWithoutCamelCase):
33+
pipeline_id: Annotated[
34+
ProjectID, Field(description="ID for created pipeline (=project identifier)")
35+
]
36+
ref_ids: Annotated[
37+
list[CommitID],
38+
Field(
39+
default_factory=list,
40+
description="Checkpoints IDs for created pipeline",
41+
json_schema_extra={"default": []},
42+
),
43+
] = DEFAULT_FACTORY

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Models a study's project document
2+
Models a study's project document
33
"""
44

55
from datetime import datetime
@@ -27,6 +27,7 @@
2727
)
2828

2929
ProjectID: TypeAlias = UUID
30+
CommitID: TypeAlias = int
3031
ClassifierID: TypeAlias = str
3132

3233
NodesDict: TypeAlias = dict[NodeIDStr, Node]

0 commit comments

Comments
 (0)