Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ The SIM-CORE, named **o<sup>2</sup>S<sup>2</sup>PARC** – **O**pen **O**nline *
The aim of o<sup>2</sup>S<sup>2</sup>PARC is to establish a comprehensive, freely accessible, intuitive, and interactive online platform for simulating peripheral nerve system neuromodulation/ stimulation and its impact on organ physiology in a precise and predictive manner.
To achieve this, the platform will comprise both state-of-the art and highly detailed animal and human anatomical models with realistic tissue property distributions that make it possible to perform simulations ranging from the molecular scale up to the complexity of the human body.


## Getting Started

A production instance of **o<sup>2</sup>S<sup>2</sup>PARC** is running at [oSPARC.io](https://osparc.io).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
FunctionJobCollection,
FunctionJobCollectionID,
FunctionJobCollectionIDNotFoundError,
FunctionJobCollectionsListFilters,
FunctionJobCollectionStatus,
FunctionJobID,
FunctionJobIDNotFoundError,
Expand Down Expand Up @@ -53,6 +54,7 @@
"FunctionJobCollectionID",
"FunctionJobCollectionIDNotFoundError",
"FunctionJobCollectionStatus",
"FunctionJobCollectionsListFilters",
"FunctionJobID",
"FunctionJobIDNotFoundError",
"FunctionJobStatus",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
FunctionJobCollection,
FunctionJobCollectionID,
FunctionJobCollectionIDNotFoundError,
FunctionJobCollectionsListFilters,
FunctionJobCollectionStatus,
FunctionJobID,
FunctionJobIDNotFoundError,
Expand Down Expand Up @@ -70,6 +71,7 @@
"FunctionJobCollectionIDNotFoundError",
"FunctionJobCollectionStatus",
"FunctionJobCollectionStatus",
"FunctionJobCollectionsListFilters",
"FunctionJobID",
"FunctionJobID",
"FunctionJobIDNotFoundError",
Expand Down
12 changes: 12 additions & 0 deletions packages/models-library/src/models_library/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

from common_library.errors_classes import OsparcErrorMixin
from models_library import projects
from models_library.basic_regex import UUID_RE_BASE
from models_library.basic_types import ConstrainedStr
from models_library.services_types import ServiceKey, ServiceVersion
from pydantic import BaseModel, Field

Expand Down Expand Up @@ -274,3 +276,13 @@ class FunctionJobCollectionDB(BaseModel):

class RegisteredFunctionJobCollectionDB(FunctionJobCollectionDB):
uuid: FunctionJobCollectionID


class FunctionIDString(ConstrainedStr):
pattern = UUID_RE_BASE


class FunctionJobCollectionsListFilters(BaseModel):
"""Filters for listing function job collections"""

has_function_id: FunctionIDString | None = None
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
FunctionJob,
FunctionJobCollection,
FunctionJobCollectionID,
FunctionJobCollectionsListFilters,
FunctionJobID,
FunctionOutputSchema,
RegisteredFunction,
Expand Down Expand Up @@ -146,12 +147,14 @@ async def list_function_job_collections(
*,
pagination_limit: int,
pagination_offset: int,
filters: FunctionJobCollectionsListFilters | None = None,
) -> tuple[list[RegisteredFunctionJobCollection], PageMetaInfoLimitOffset]:
result = await rabbitmq_rpc_client.request(
WEBSERVER_RPC_NAMESPACE,
TypeAdapter(RPCMethodName).validate_python("list_function_job_collections"),
pagination_offset=pagination_offset,
pagination_limit=pagination_limit,
filters=filters,
)
return TypeAdapter(
tuple[list[RegisteredFunctionJobCollection], PageMetaInfoLimitOffset]
Expand Down
17 changes: 17 additions & 0 deletions services/api-server/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -5695,6 +5695,23 @@
"default": 0,
"title": "Offset"
}
},
{
"name": "has_function_id",
"in": "query",
"required": false,
"schema": {
"anyOf": [
{
"type": "string",
"pattern": "[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}"
},
{
"type": "null"
}
],
"title": "Has Function Id"
}
}
],
"responses": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from typing import Any

from pydantic.fields import FieldInfo


def _get_query_params(field: FieldInfo) -> dict[str, Any]:
params = {}

if field.description:
params["description"] = field.description
if field.examples:
params["example"] = next(
(example for example in field.examples if "*" in example), field.examples[0]
)
return params
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from typing import Annotated

from fastapi import Query
from models_library.functions import FunctionIDString, FunctionJobCollectionsListFilters

from ._utils import _get_query_params


def get_function_job_collections_filters(
# pylint: disable=unsubscriptable-object
has_function_id: Annotated[
FunctionIDString | None,
Query(
**_get_query_params(
FunctionJobCollectionsListFilters.model_fields["has_function_id"]
)
),
] = None,
) -> FunctionJobCollectionsListFilters:
return FunctionJobCollectionsListFilters(
has_function_id=has_function_id,
)
Original file line number Diff line number Diff line change
@@ -1,22 +1,10 @@
from typing import Annotated, Any
from typing import Annotated

from fastapi import Query
from models_library.basic_types import SafeQueryStr
from pydantic.fields import FieldInfo

from ...models.schemas.solvers_filters import SolversListFilters


def _get_query_params(field: FieldInfo) -> dict[str, Any]:
params = {}

if field.description:
params["description"] = field.description
if field.examples:
params["example"] = next(
(example for example in field.examples if "*" in example), field.examples[0]
)
return params
from ._utils import _get_query_params


def get_solvers_filters(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from models_library.api_schemas_webserver.functions import (
FunctionJobCollection,
FunctionJobCollectionID,
FunctionJobCollectionsListFilters,
FunctionJobCollectionStatus,
RegisteredFunctionJob,
RegisteredFunctionJobCollection,
Expand All @@ -17,6 +18,9 @@
from ...services_http.director_v2 import DirectorV2Api
from ...services_rpc.wb_api_server import WbApiRpcClient
from ..dependencies.authentication import get_current_user_id
from ..dependencies.models_schemas_function_filters import (
get_function_job_collections_filters,
)
from ..dependencies.services import get_api_client
from ..dependencies.webserver_rpc import get_wb_api_rpc_client
from ._constants import FMSG_CHANGELOG_NEW_IN_VERSION, create_route_description
Expand Down Expand Up @@ -48,10 +52,14 @@
async def list_function_job_collections(
wb_api_rpc: Annotated[WbApiRpcClient, Depends(get_wb_api_rpc_client)],
page_params: Annotated[PaginationParams, Depends()],
filters: Annotated[
FunctionJobCollectionsListFilters, Depends(get_function_job_collections_filters)
],
):
function_job_collection_list, meta = await wb_api_rpc.list_function_job_collections(
pagination_offset=page_params.offset,
pagination_limit=page_params.limit,
filters=filters,
)
return create_page(
function_job_collection_list,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
FunctionJob,
FunctionJobCollection,
FunctionJobCollectionID,
FunctionJobCollectionsListFilters,
FunctionJobID,
FunctionOutputSchema,
RegisteredFunction,
Expand Down Expand Up @@ -324,11 +325,13 @@ async def list_function_job_collections(
*,
pagination_offset: PageOffsetInt = 0,
pagination_limit: PageLimitInt = DEFAULT_NUMBER_OF_ITEMS_PER_PAGE,
filters: FunctionJobCollectionsListFilters | None = None,
) -> tuple[list[RegisteredFunctionJobCollection], PageMetaInfoLimitOffset]:
return await functions_rpc_interface.list_function_job_collections(
self._client,
pagination_offset=pagination_offset,
pagination_limit=pagination_limit,
filters=filters,
)

async def run_function(
Expand Down
42 changes: 34 additions & 8 deletions services/api-server/tests/unit/api_functions/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
FunctionClass,
FunctionIDNotFoundError,
FunctionJob,
FunctionJobCollection,
JSONFunctionInputSchema,
JSONFunctionOutputSchema,
ProjectFunction,
Expand All @@ -25,6 +26,7 @@
RegisteredProjectFunction,
RegisteredProjectFunctionJob,
)
from models_library.functions import RegisteredFunctionJobCollection
from models_library.projects import ProjectID
from pytest_mock import MockerFixture
from pytest_simcore.helpers.monkeypatch_envs import setenvs_from_dict
Expand Down Expand Up @@ -98,7 +100,7 @@ def raise_function_id_not_found() -> FunctionIDNotFoundError:


@pytest.fixture
def sample_function(
def mock_function(
project_id: ProjectID,
sample_input_schema: JSONFunctionInputSchema,
sample_output_schema: JSONFunctionOutputSchema,
Expand All @@ -116,14 +118,14 @@ def sample_function(


@pytest.fixture
def sample_registered_function(sample_function: Function) -> RegisteredFunction:
return RegisteredProjectFunction(**{**sample_function.dict(), "uid": str(uuid4())})
def mock_registered_function(mock_function: Function) -> RegisteredFunction:
return RegisteredProjectFunction(**{**mock_function.dict(), "uid": str(uuid4())})


@pytest.fixture
def sample_function_job(sample_registered_function: RegisteredFunction) -> FunctionJob:
def mock_function_job(mock_registered_function: RegisteredFunction) -> FunctionJob:
mock_function_job = {
"function_uid": sample_registered_function.uid,
"function_uid": mock_registered_function.uid,
"title": "Test Function Job",
"description": "A test function job",
"inputs": {"key": "value"},
Expand All @@ -135,11 +137,35 @@ def sample_function_job(sample_registered_function: RegisteredFunction) -> Funct


@pytest.fixture
def sample_registered_function_job(
sample_function_job: FunctionJob,
def mock_registered_function_job(
mock_function_job: FunctionJob,
) -> RegisteredFunctionJob:
return RegisteredProjectFunctionJob(
**{**sample_function_job.dict(), "uid": str(uuid4())}
**{**mock_function_job.dict(), "uid": str(uuid4())}
)


@pytest.fixture
def mock_function_job_collection(
mock_registered_function_job: RegisteredFunctionJob,
) -> FunctionJobCollection:
mock_function_job_collection = {
"title": "Test Function Job Collection",
"description": "A test function job collection",
"function_uid": mock_registered_function_job.function_uid,
"function_class": FunctionClass.PROJECT,
"project_id": str(uuid4()),
"function_job_ids": [mock_registered_function_job.uid for _ in range(5)],
}
return FunctionJobCollection(**mock_function_job_collection)


@pytest.fixture
def mock_registered_function_job_collection(
mock_function_job_collection: FunctionJobCollection,
) -> RegisteredFunctionJobCollection:
return RegisteredFunctionJobCollection(
**{**mock_function_job_collection.model_dump(), "uid": str(uuid4())}
)


Expand Down
Loading
Loading