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
89d7329
✨ Add ServiceFiltersDB model with service type filtering capabilities
pcrespov Apr 15, 2025
fe0d0a2
✨ Implement service type filtering in latest services queries
pcrespov Apr 15, 2025
068bfa0
✨ Add filters parameter to list_latest_catalog_services and list_user…
pcrespov Apr 15, 2025
37d4342
✨ Add ServiceListFilters for service type filtering in paginated serv…
pcrespov Apr 15, 2025
11266ef
✨ Refactor RPC service methods to streamline request handling and imp…
pcrespov Apr 16, 2025
f2740fa
✨ Refactor service key prefixes and enhance service type filtering in…
pcrespov Apr 17, 2025
ba0c3f6
✨ Add service key prefixes and refactor regex patterns for dynamic an…
pcrespov Apr 17, 2025
805253c
✨ Refactor service filters application and enhance service key prefix…
pcrespov Apr 17, 2025
9b3627e
fixes tests
pcrespov Apr 17, 2025
4babc5b
✨ Add service key formats for dynamic, computational, and frontend se…
pcrespov Apr 17, 2025
65ad67e
✨ Refactor service key handling by consolidating key prefixes and reg…
pcrespov Apr 17, 2025
281b939
minor
pcrespov Apr 17, 2025
cabace7
fixes tests
pcrespov Apr 17, 2025
778ca3c
fixes tests
pcrespov Apr 17, 2025
aaa5c67
@sanderegg review: relative imports, doc, private
pcrespov Apr 22, 2025
27debde
@GitHK review: types
pcrespov Apr 22, 2025
a713ee8
@bisgaard-itis review: filters
pcrespov Apr 22, 2025
4b30eb5
@sanderegg review: services constants
pcrespov Apr 22, 2025
0e0a0af
minor
pcrespov Apr 22, 2025
1945d04
fixes mypy
pcrespov Apr 22, 2025
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 .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ branch = True
omit =
*/tests/*
*/generated_code/*
*/_original_fastapi_encoders.py
parallel = True

[report]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from ..boot_options import BootOptions
from ..emails import LowerCaseEmailStr
from ..groups import GroupID
from ..rest_filters import Filters
from ..services_access import ServiceAccessRights, ServiceGroupAccessRightsV2
from ..services_authoring import Author
from ..services_enums import ServiceType
Expand Down Expand Up @@ -376,4 +377,13 @@ class MyServiceGet(CatalogOutputSchema):
my_access_rights: ServiceGroupAccessRightsV2


class ServiceListFilters(Filters):
service_type: Annotated[
ServiceType | None,
Field(
description="Filter only services of a given type. If None, then all types are returned"
),
] = None


__all__: tuple[str, ...] = ("ServiceRelease",)
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from typing import Final

from ..services import ServiceKey
from ..services_constants import FRONTEND_SERVICE_KEY_PREFIX

# NOTE: due to legacy reasons, the name remains with 'frontend' in it but
# it now refers to a more general group: function sections that contains front-end services as well
FUNCTION_SERVICE_KEY_PREFIX: Final[str] = "simcore/services/frontend"
FUNCTION_SERVICE_KEY_PREFIX: Final[str] = FRONTEND_SERVICE_KEY_PREFIX


def is_function_service(service_key: ServiceKey) -> bool:
Expand Down
5 changes: 5 additions & 0 deletions packages/models-library/src/models_library/rpc_filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .rest_filters import Filters

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

# nopycln:file
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
from types import MappingProxyType
from typing import Final

LATEST_INTEGRATION_VERSION: Final[str] = "1.0.0"
from .services_enums import ServiceType

LATEST_INTEGRATION_VERSION: Final[str] = "1.0.0"

ANY_FILETYPE: Final[str] = "data:*/*"

SERVICE_TYPE_TO_NAME_MAP = MappingProxyType(
{
ServiceType.COMPUTATIONAL: "comp",
ServiceType.DYNAMIC: "dynamic",
ServiceType.FRONTEND: "frontend",
}
)


def _create_key_prefix(service_type: ServiceType) -> str:
return f"simcore/services/{SERVICE_TYPE_TO_NAME_MAP[service_type]}"


COMPUTATIONAL_SERVICE_KEY_PREFIX: Final[str] = _create_key_prefix(
ServiceType.COMPUTATIONAL
)
DYNAMIC_SERVICE_KEY_PREFIX: Final[str] = _create_key_prefix(ServiceType.DYNAMIC)
FRONTEND_SERVICE_KEY_PREFIX: Final[str] = _create_key_prefix(ServiceType.FRONTEND)
62 changes: 48 additions & 14 deletions packages/models-library/src/models_library/services_regex.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import re
from types import MappingProxyType
from typing import Final

from .services_constants import (
COMPUTATIONAL_SERVICE_KEY_PREFIX,
DYNAMIC_SERVICE_KEY_PREFIX,
FRONTEND_SERVICE_KEY_PREFIX,
SERVICE_TYPE_TO_NAME_MAP,
)
from .services_enums import ServiceType

PROPERTY_TYPE_RE = r"^(number|integer|boolean|string|ref_contentSchema|data:([^/\s,]+/[^/\s,]+|\[[^/\s,]+/[^/\s,]+(,[^/\s]+/[^/,\s]+)*\]))$"
PROPERTY_TYPE_TO_PYTHON_TYPE_MAP = {
"integer": int,
Expand All @@ -11,34 +20,59 @@

FILENAME_RE = r".+"


# e.g. simcore/services/comp/opencor
SERVICE_KEY_RE: Final[re.Pattern[str]] = re.compile(
r"^simcore/services/"
r"(?P<type>(comp|dynamic|frontend))/"
rf"(?P<type>({ '|'.join(SERVICE_TYPE_TO_NAME_MAP.values()) }))/"
r"(?P<subdir>[a-z0-9][a-z0-9_.-]*/)*"
r"(?P<name>[a-z0-9-_]+[a-z0-9])$"
)

# e.g. simcore%2Fservices%2Fcomp%2Fopencor
SERVICE_ENCODED_KEY_RE: Final[re.Pattern[str]] = re.compile(
r"^simcore%2Fservices%2F"
r"(?P<type>(comp|dynamic|frontend))%2F"
rf"(?P<type>({'|'.join(SERVICE_TYPE_TO_NAME_MAP.values())}))%2F"
r"(?P<subdir>[a-z0-9][a-z0-9_.-]*%2F)*"
r"(?P<name>[a-z0-9-_]+[a-z0-9])$"
)

DYNAMIC_SERVICE_KEY_RE: Final[re.Pattern[str]] = re.compile(
r"^simcore/services/dynamic/"
r"(?P<subdir>[a-z0-9][a-z0-9_.-]*/)*"
r"(?P<name>[a-z0-9-_]+[a-z0-9])$"

def _create_key_regex(service_type: ServiceType) -> re.Pattern[str]:
return re.compile(
rf"^simcore/services/{SERVICE_TYPE_TO_NAME_MAP[service_type]}/"
r"(?P<subdir>[a-z0-9][a-z0-9_.-]*/)*"
r"(?P<name>[a-z0-9-_]+[a-z0-9])$"
)


def _create_key_format(service_type: ServiceType) -> str:
return f"simcore/services/{SERVICE_TYPE_TO_NAME_MAP[service_type]}/{{service_name}}"


COMPUTATIONAL_SERVICE_KEY_RE: Final[re.Pattern[str]] = _create_key_regex(
ServiceType.COMPUTATIONAL
)
COMPUTATIONAL_SERVICE_KEY_FORMAT: Final[str] = _create_key_format(
ServiceType.COMPUTATIONAL
)
DYNAMIC_SERVICE_KEY_FORMAT = "simcore/services/dynamic/{service_name}"

DYNAMIC_SERVICE_KEY_RE: Final[re.Pattern[str]] = _create_key_regex(ServiceType.DYNAMIC)
DYNAMIC_SERVICE_KEY_FORMAT: Final[str] = _create_key_format(ServiceType.DYNAMIC)

# Computational regex & format
COMPUTATIONAL_SERVICE_KEY_RE: Final[re.Pattern[str]] = re.compile(
r"^simcore/services/comp/"
r"(?P<subdir>[a-z0-9][a-z0-9_.-]*/)*"
r"(?P<name>[a-z0-9-_]+[a-z0-9])$"
FRONTEND_SERVICE_KEY_RE: Final[re.Pattern[str]] = _create_key_regex(
ServiceType.FRONTEND
)
COMPUTATIONAL_SERVICE_KEY_FORMAT: Final[str] = "simcore/services/comp/{service_name}"
FRONTEND_SERVICE_KEY_FORMAT: Final[str] = _create_key_format(ServiceType.FRONTEND)


SERVICE_TYPE_TO_PREFIX_MAP = MappingProxyType(
{
ServiceType.COMPUTATIONAL: COMPUTATIONAL_SERVICE_KEY_PREFIX,
ServiceType.DYNAMIC: DYNAMIC_SERVICE_KEY_PREFIX,
ServiceType.FRONTEND: FRONTEND_SERVICE_KEY_PREFIX,
}
)

assert all( # nosec
not prefix.endswith("/") for prefix in SERVICE_TYPE_TO_PREFIX_MAP.values()
), "Service type prefixes must not end with '/'"
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
# pylint: disable=unused-variable


from models_library.api_schemas_catalog.services import LatestServiceGet, ServiceGetV2
from models_library.api_schemas_catalog.services import (
LatestServiceGet,
ServiceGetV2,
ServiceListFilters,
)
from models_library.api_schemas_webserver.catalog import (
CatalogServiceUpdate,
)
Expand Down Expand Up @@ -34,10 +38,12 @@ async def list_services_paginated(
user_id: UserID,
limit: PageLimitInt,
offset: NonNegativeInt,
filters: ServiceListFilters | None = None,
):
assert rpc_client
assert product_name
assert user_id
assert filters is None, "filters not mocked yet"

items = TypeAdapter(list[LatestServiceGet]).validate_python(
LatestServiceGet.model_json_schema()["examples"],
Expand Down Expand Up @@ -110,12 +116,14 @@ async def list_my_service_history_paginated(
service_key: ServiceKey,
offset: PageOffsetInt,
limit: PageLimitInt,
filters: ServiceListFilters | None = None,
) -> PageRpc[ServiceRelease]:

assert rpc_client
assert product_name
assert user_id
assert service_key
assert filters is None, "filters not mocked yet"

items = TypeAdapter(list[ServiceRelease]).validate_python(
ServiceRelease.model_json_schema()["examples"],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" 'osparc config' is a set of stardard file forms (yaml) that the user fills to describe how his/her service works and
"""'osparc config' is a set of stardard file forms (yaml) that the user fills to describe how his/her service works and
integrates with osparc.

- config files are stored under '.osparc/' folder in the root repo folder (analogous to other configs like .github, .vscode, etc)
Expand Down Expand Up @@ -26,11 +26,7 @@
RestartPolicy,
)
from models_library.service_settings_nat_rule import NATRule
from models_library.services import BootOptions, ServiceMetaDataPublished, ServiceType
from models_library.services_regex import (
COMPUTATIONAL_SERVICE_KEY_FORMAT,
DYNAMIC_SERVICE_KEY_FORMAT,
)
from models_library.services import BootOptions, ServiceMetaDataPublished
from models_library.services_types import ServiceKey
from models_library.utils.labels_annotations import (
OSPARC_LABEL_PREFIXES,
Expand Down Expand Up @@ -62,12 +58,6 @@
OSPARC_CONFIG_RUNTIME_NAME: Final[str] = "runtime.yml"


SERVICE_KEY_FORMATS = {
ServiceType.COMPUTATIONAL: COMPUTATIONAL_SERVICE_KEY_FORMAT,
ServiceType.DYNAMIC: DYNAMIC_SERVICE_KEY_FORMAT,
}


class DockerComposeOverwriteConfig(ComposeSpecification):
"""Content of docker-compose.overwrite.yml configuration file"""

Expand Down Expand Up @@ -231,9 +221,9 @@ class RuntimeConfig(BaseModel):

containers_allowed_outgoing_internet: set[str] | None = None

settings: Annotated[
list[SettingsItem], Field(default_factory=list)
] = DEFAULT_FACTORY
settings: Annotated[list[SettingsItem], Field(default_factory=list)] = (
DEFAULT_FACTORY
)

@model_validator(mode="before")
@classmethod
Expand Down
Loading
Loading