Skip to content

Commit 002a969

Browse files
authored
Merge branch 'master' into feature/pending-users
2 parents bcaa361 + b46a1dd commit 002a969

File tree

29 files changed

+603
-139
lines changed

29 files changed

+603
-139
lines changed

packages/models-library/src/models_library/api_schemas_catalog/services.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,5 +385,19 @@ class ServiceListFilters(Filters):
385385
),
386386
] = None
387387

388+
service_key_pattern: Annotated[
389+
str | None,
390+
Field(
391+
description="Filter services by key pattern (e.g. 'simcore/services/comp/itis/*')",
392+
),
393+
] = None
394+
395+
version_display_pattern: Annotated[
396+
str | None,
397+
Field(
398+
description="Filter services by version display pattern (e.g. '*2023*')",
399+
),
400+
] = None
401+
388402

389403
__all__: tuple[str, ...] = ("ServiceRelease",)

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

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# pylint: disable=unused-variable
77

88

9+
import fnmatch
910
from dataclasses import dataclass
1011

1112
from models_library.api_schemas_catalog.services import (
@@ -31,7 +32,9 @@
3132
from servicelib.rabbitmq._client_rpc import RabbitMQRPCClient
3233

3334
assert ServiceListFilters.model_json_schema()["properties"].keys() == {
34-
"service_type"
35+
"service_type",
36+
"service_key_pattern",
37+
"version_display_pattern",
3538
}, (
3639
"ServiceListFilters is expected to only have the key 'service_type'. "
3740
"Please update the mock if the schema changes."
@@ -55,18 +58,40 @@ async def list_services_paginated(
5558
assert product_name
5659
assert user_id
5760

58-
items = TypeAdapter(list[LatestServiceGet]).validate_python(
61+
services_list = TypeAdapter(list[LatestServiceGet]).validate_python(
5962
LatestServiceGet.model_json_schema()["examples"],
6063
)
6164
if filters:
62-
items = [
63-
item for item in items if item.service_type == filters.service_type
64-
]
6565

66-
total_count = len(items)
66+
filtered_services = []
67+
for src in services_list:
68+
# Match service type if specified
69+
if filters.service_type and src.service_type != filters.service_type:
70+
continue
71+
72+
# Match service key pattern if specified
73+
if filters.service_key_pattern and not fnmatch.fnmatch(
74+
src.key, filters.service_key_pattern
75+
):
76+
continue
77+
78+
# Match version display pattern if specified
79+
if filters.version_display_pattern and (
80+
src.version_display is None
81+
or not fnmatch.fnmatch(
82+
src.version_display, filters.version_display_pattern
83+
)
84+
):
85+
continue
86+
87+
filtered_services.append(src)
88+
89+
services_list = filtered_services
90+
91+
total_count = len(services_list)
6792

6893
return PageRpc[LatestServiceGet].create(
69-
items[offset : offset + limit],
94+
services_list[offset : offset + limit],
7095
total=total_count,
7196
limit=limit,
7297
offset=offset,

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ def __call__(
2020
team_access: str | None = None,
2121
everyone_access: str | None = None,
2222
product: ProductName = "osparc",
23+
# DB overrides
2324
deprecated: datetime | None = None, # DB column
25+
version_display: str | None = None, # DB column
2426
) -> tuple[dict[str, Any], ...]: # type: ignore
2527
"""
2628
Returns a fake factory that creates catalog DATA that can be used to fill

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

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,14 +156,36 @@ async def solver_release_history(
156156
async def latest_solvers(
157157
self,
158158
*,
159-
offset: NonNegativeInt,
160-
limit: PositiveInt,
159+
pagination_offset: NonNegativeInt,
160+
pagination_limit: PositiveInt,
161+
filter_by_solver_id: str | None = None,
162+
filter_by_version_display: str | None = None,
161163
) -> tuple[list[Solver], PageMetaInfoLimitOffset]:
162-
"""Lists the latest solvers with pagination."""
164+
"""Lists the latest solvers with pagination and filtering.
165+
166+
Args:
167+
offset: Pagination offset
168+
limit: Pagination limit
169+
solver_id_pattern: Optional pattern to filter solvers by ID
170+
version_display_pattern: Optional pattern to filter by version display
171+
172+
Returns:
173+
A tuple with the list of filtered solvers and pagination metadata
174+
"""
175+
filters = ServiceListFilters(service_type=ServiceType.COMPUTATIONAL)
176+
177+
# Add key_pattern filter for solver ID if provided
178+
if filter_by_solver_id:
179+
filters.service_key_pattern = filter_by_solver_id
180+
181+
# Add version_display_pattern filter if provided
182+
if filter_by_version_display:
183+
filters.version_display_pattern = filter_by_version_display
184+
163185
services, page_meta = await self.catalog_service.list_latest_releases(
164-
pagination_offset=offset,
165-
pagination_limit=limit,
166-
filters=ServiceListFilters(service_type=ServiceType.COMPUTATIONAL),
186+
pagination_offset=pagination_offset,
187+
pagination_limit=pagination_limit,
188+
filters=filters,
167189
)
168190

169191
solvers = [Solver.create_from_service(service) for service in services]
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from typing import Annotated, Any
2+
3+
from fastapi import Query
4+
from pydantic.fields import FieldInfo
5+
6+
from ...models.schemas.solvers_filters import SolversListFilters
7+
8+
9+
def _get_query_params(field: FieldInfo) -> dict[str, Any]:
10+
params = {}
11+
12+
if field.description:
13+
params["description"] = field.description
14+
if field.examples:
15+
params["example"] = next(
16+
(example for example in field.examples if "*" in example), field.examples[0]
17+
)
18+
return params
19+
20+
21+
def get_solvers_filters(
22+
# pylint: disable=unsubscriptable-object
23+
solver_id: Annotated[
24+
str | None,
25+
Query(**_get_query_params(SolversListFilters.model_fields["solver_id"])),
26+
] = None,
27+
version_display: Annotated[
28+
str | None,
29+
Query(**_get_query_params(SolversListFilters.model_fields["version_display"])),
30+
] = None,
31+
) -> SolversListFilters:
32+
return SolversListFilters(
33+
solver_id=solver_id,
34+
version_display=version_display,
35+
)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
programs,
1616
solvers,
1717
solvers_jobs,
18-
solvers_jobs_getters,
18+
solvers_jobs_read,
1919
studies,
2020
studies_jobs,
2121
users,
@@ -43,7 +43,7 @@ def create_router(settings: ApplicationSettings):
4343
router.include_router(solvers.router, tags=["solvers"], prefix=_SOLVERS_PREFIX)
4444
router.include_router(solvers_jobs.router, tags=["solvers"], prefix=_SOLVERS_PREFIX)
4545
router.include_router(
46-
solvers_jobs_getters.router, tags=["solvers"], prefix=_SOLVERS_PREFIX
46+
solvers_jobs_read.router, tags=["solvers"], prefix=_SOLVERS_PREFIX
4747
)
4848
router.include_router(studies.router, tags=["studies"], prefix="/studies")
4949
router.include_router(studies_jobs.router, tags=["studies"], prefix="/studies")

services/api-server/src/simcore_service_api_server/api/routes/function_jobs_routes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
from ..dependencies.services import get_api_client
2828
from ..dependencies.webserver_http import get_webserver_session
2929
from ..dependencies.webserver_rpc import get_wb_api_rpc_client
30-
from . import solvers_jobs, solvers_jobs_getters, studies_jobs
30+
from . import solvers_jobs, solvers_jobs_read, studies_jobs
3131

3232
# pylint: disable=too-many-arguments
3333
# pylint: disable=cyclic-import
@@ -203,7 +203,7 @@ async def function_job_outputs(
203203
):
204204
return dict(
205205
(
206-
await solvers_jobs_getters.get_job_outputs(
206+
await solvers_jobs_read.get_job_outputs(
207207
solver_key=function.solver_key,
208208
version=function.solver_version,
209209
job_id=function_job.solver_job_id,

services/api-server/src/simcore_service_api_server/api/routes/solvers.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
from ...models.schemas.errors import ErrorGet
2020
from ...models.schemas.model_adapter import ServicePricingPlanGetLegacy
2121
from ...models.schemas.solvers import Solver, SolverKeyId, SolverPort
22+
from ...models.schemas.solvers_filters import SolversListFilters
2223
from ...services_rpc.catalog import CatalogService
2324
from ..dependencies.application import get_reverse_url_mapper
2425
from ..dependencies.authentication import get_current_user_id, get_product_name
26+
from ..dependencies.models_schemas_solvers_filters import get_solvers_filters
2527
from ..dependencies.services import get_catalog_service, get_solver_service
2628
from ..dependencies.webserver_http import AuthSession, get_webserver_session
2729
from ._constants import (
@@ -90,11 +92,14 @@ async def list_solvers(
9092
async def get_solvers_page(
9193
page_params: Annotated[PaginationParams, Depends()],
9294
solver_service: Annotated[SolverService, Depends(get_solver_service)],
95+
filters: Annotated[SolversListFilters, Depends(get_solvers_filters)],
9396
url_for: Annotated[Callable, Depends(get_reverse_url_mapper)],
9497
):
9598
solvers, page_meta = await solver_service.latest_solvers(
96-
offset=page_params.offset,
97-
limit=page_params.limit,
99+
pagination_offset=page_params.offset,
100+
pagination_limit=page_params.limit,
101+
filter_by_solver_id=filters.solver_id,
102+
filter_by_version_display=filters.version_display,
98103
)
99104

100105
for solver in solvers:
@@ -129,8 +134,8 @@ async def list_solvers_releases(
129134
latest_solvers: list[Solver] = []
130135
for page_params in iter_pagination_params(limit=DEFAULT_PAGINATION_LIMIT):
131136
solvers, page_meta = await solver_service.latest_solvers(
132-
offset=page_params.offset,
133-
limit=page_params.limit,
137+
pagination_offset=page_params.offset,
138+
pagination_limit=page_params.limit,
134139
)
135140
page_params.total_number_of_items = page_meta.total
136141
latest_solvers.extend(solvers)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
from ..dependencies.application import get_reverse_url_mapper
5757
from ..dependencies.authentication import get_current_user_id
5858
from ..dependencies.database import get_db_asyncpg_engine
59-
from ..dependencies.models_schemas_job_filters import get_job_metadata_filter
59+
from ..dependencies.models_schemas_jobs_filters import get_job_metadata_filter
6060
from ..dependencies.rabbitmq import get_log_check_timeout, get_log_distributor
6161
from ..dependencies.services import get_api_client, get_solver_service
6262
from ..dependencies.webserver_http import AuthSession, get_webserver_session

0 commit comments

Comments
 (0)