Skip to content

Commit b86f633

Browse files
authored
✨ Add Support for Filtering Solver Jobs by Custom Metadata via metadata.any Query Parameter (#7678)
1 parent b422df3 commit b86f633

File tree

21 files changed

+869
-86
lines changed

21 files changed

+869
-86
lines changed

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

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,68 @@
22
from typing import Annotated, TypeAlias
33
from uuid import uuid4
44

5-
from models_library.projects import NodesDict, ProjectID
6-
from models_library.projects_nodes import Node
7-
from models_library.rpc_pagination import PageRpc
85
from pydantic import BaseModel, ConfigDict, Field
96
from pydantic.config import JsonDict
107

8+
from ...projects import NodesDict, ProjectID
9+
from ...projects_nodes import Node
10+
from ...rpc_pagination import PageRpc
11+
12+
13+
class MetadataFilterItem(BaseModel):
14+
name: str
15+
pattern: str
16+
17+
18+
class ListProjectsMarkedAsJobRpcFilters(BaseModel):
19+
"""Filters model for the list_projects_marked_as_jobs RPC.
20+
21+
NOTE: Filters models are used to validate all possible filters in an API early on,
22+
particularly to ensure compatibility and prevent conflicts between different filters.
23+
"""
24+
25+
job_parent_resource_name_prefix: str | None = None
26+
27+
any_custom_metadata: Annotated[
28+
list[MetadataFilterItem] | None,
29+
Field(description="Searchs for matches of any of the custom metadata fields"),
30+
] = None
31+
32+
@staticmethod
33+
def _update_json_schema_extra(schema: JsonDict) -> None:
34+
schema.update(
35+
{
36+
"examples": [
37+
{
38+
"job_parent_resource_name_prefix": "solvers/solver123",
39+
"any_custom_metadata": [
40+
{
41+
"name": "solver_type",
42+
"pattern": "FEM",
43+
},
44+
{
45+
"name": "mesh_cells",
46+
"pattern": "1*",
47+
},
48+
],
49+
},
50+
{
51+
"any_custom_metadata": [
52+
{
53+
"name": "solver_type",
54+
"pattern": "*CFD*",
55+
}
56+
],
57+
},
58+
{"job_parent_resource_name_prefix": "solvers/solver123"},
59+
]
60+
}
61+
)
62+
63+
model_config = ConfigDict(
64+
json_schema_extra=_update_json_schema_extra,
65+
)
66+
1167

1268
class ProjectJobRpcGet(BaseModel):
1369
"""

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from models_library.projects import ProjectID
1010
from models_library.rest_pagination import PageOffsetInt
1111
from models_library.rpc.webserver.projects import (
12+
ListProjectsMarkedAsJobRpcFilters,
1213
PageRpcProjectJobRpcGet,
1314
ProjectJobRpcGet,
1415
)
@@ -56,24 +57,24 @@ async def list_projects_marked_as_jobs(
5657
# pagination
5758
offset: PageOffsetInt = 0,
5859
limit: PageLimitInt = DEFAULT_NUMBER_OF_ITEMS_PER_PAGE,
59-
# filters
60-
job_parent_resource_name_prefix: str | None = None,
60+
filters: ListProjectsMarkedAsJobRpcFilters | None = None,
6161
) -> PageRpcProjectJobRpcGet:
6262
assert rpc_client
6363
assert product_name
6464
assert user_id
6565

66-
if job_parent_resource_name_prefix:
67-
assert not job_parent_resource_name_prefix.startswith("/")
68-
assert not job_parent_resource_name_prefix.endswith("%")
69-
assert not job_parent_resource_name_prefix.startswith("%")
66+
if filters and filters.job_parent_resource_name_prefix:
67+
assert not filters.job_parent_resource_name_prefix.startswith("/")
68+
assert not filters.job_parent_resource_name_prefix.endswith("%")
69+
assert not filters.job_parent_resource_name_prefix.startswith("%")
7070

7171
items = [
7272
item
7373
for item in ProjectJobRpcGet.model_json_schema()["examples"]
74-
if job_parent_resource_name_prefix is None
74+
if filters is None
75+
or filters.job_parent_resource_name_prefix is None
7576
or item.get("job_parent_resource_name").startswith(
76-
job_parent_resource_name_prefix
77+
filters.job_parent_resource_name_prefix
7778
)
7879
]
7980

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
from models_library.projects import ProjectID
77
from models_library.rabbitmq_basic_types import RPCMethodName
88
from models_library.rest_pagination import PageOffsetInt
9-
from models_library.rpc.webserver.projects import PageRpcProjectJobRpcGet
9+
from models_library.rpc.webserver.projects import (
10+
ListProjectsMarkedAsJobRpcFilters,
11+
PageRpcProjectJobRpcGet,
12+
)
1013
from models_library.rpc_pagination import (
1114
DEFAULT_NUMBER_OF_ITEMS_PER_PAGE,
1215
PageLimitInt,
@@ -51,8 +54,7 @@ async def list_projects_marked_as_jobs(
5154
# pagination
5255
offset: PageOffsetInt = 0,
5356
limit: PageLimitInt = DEFAULT_NUMBER_OF_ITEMS_PER_PAGE,
54-
# filters
55-
job_parent_resource_name_prefix: str | None = None,
57+
filters: ListProjectsMarkedAsJobRpcFilters | None = None,
5658
) -> PageRpcProjectJobRpcGet:
5759
result = await rpc_client.request(
5860
WEBSERVER_RPC_NAMESPACE,
@@ -61,7 +63,7 @@ async def list_projects_marked_as_jobs(
6163
user_id=user_id,
6264
offset=offset,
6365
limit=limit,
64-
job_parent_resource_name_prefix=job_parent_resource_name_prefix,
66+
filters=filters,
6567
)
6668
assert TypeAdapter(PageRpcProjectJobRpcGet).validate_python(result) # nosec
6769
return cast(PageRpcProjectJobRpcGet, result)

0 commit comments

Comments
 (0)