Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -323,11 +323,20 @@ def _update_json_schema_extra(schema: JsonDict) -> None:
)


PageRpcServicesGetV2: TypeAlias = PageRpc[
PageRpcLatestServiceGet: TypeAlias = PageRpc[
# WARNING: keep this definition in models_library and not in the RPC interface
# otherwise the metaclass PageRpc[*] will create *different* classes in server/client side
# and will fail to serialize/deserialize these parameters when transmitted/received
LatestServiceGet
]

PageRpcServiceRelease: TypeAlias = PageRpc[
# WARNING: keep this definition in models_library and not in the RPC interface
# otherwise the metaclass PageRpc[*] will create *different* classes in server/client side
# and will fail to serialize/deserialize these parameters when transmitted/received
ServiceRelease
]

ServiceResourcesGet: TypeAlias = ServiceResourcesDict


Expand Down Expand Up @@ -365,3 +374,6 @@ class MyServiceGet(CatalogOutputSchema):

owner: GroupID | None
my_access_rights: ServiceGroupAccessRightsV2


__all__: tuple[str, ...] = ("ServiceRelease",)
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

PageOffsetInt: TypeAlias = NonNegativeInt

PageTotalCount: TypeAlias = NonNegativeInt

DEFAULT_NUMBER_OF_ITEMS_PER_PAGE: Final[PageLimitInt] = TypeAdapter(
PageLimitInt
).validate_python(20)
Expand Down Expand Up @@ -70,7 +72,7 @@ class PageQueryParameters(RequestParameters):

class PageMetaInfoLimitOffset(BaseModel):
limit: PositiveInt = DEFAULT_NUMBER_OF_ITEMS_PER_PAGE
total: NonNegativeInt
total: PageTotalCount
offset: NonNegativeInt = 0
count: NonNegativeInt

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# pylint: disable=not-context-manager
# pylint: disable=protected-access
# pylint: disable=redefined-outer-name
# pylint: disable=unused-argument
# pylint: disable=unused-variable


from models_library.api_schemas_catalog.services import LatestServiceGet, ServiceGetV2
from models_library.api_schemas_webserver.catalog import (
CatalogServiceUpdate,
)
from models_library.products import ProductName
from models_library.rest_pagination import PageOffsetInt
from models_library.rpc_pagination import PageLimitInt, PageRpc
from models_library.services_history import ServiceRelease
from models_library.services_types import ServiceKey, ServiceVersion
from models_library.users import UserID
from pydantic import NonNegativeInt, TypeAdapter
from servicelib.rabbitmq._client_rpc import RabbitMQRPCClient


class CatalogRpcSideEffects:
# pylint: disable=no-self-use
async def list_services_paginated(
self,
rpc_client: RabbitMQRPCClient,
*,
product_name: ProductName,
user_id: UserID,
limit: PageLimitInt,
offset: NonNegativeInt,
):
assert rpc_client
assert product_name
assert user_id

items = TypeAdapter(list[LatestServiceGet]).validate_python(
LatestServiceGet.model_json_schema()["examples"],
)
total_count = len(items)

return PageRpc[LatestServiceGet].create(
items[offset : offset + limit],
total=total_count,
limit=limit,
offset=offset,
)

async def get_service(
self,
rpc_client: RabbitMQRPCClient,
*,
product_name: ProductName,
user_id: UserID,
service_key: ServiceKey,
service_version: ServiceVersion,
):
assert rpc_client
assert product_name
assert user_id

got = ServiceGetV2.model_validate(
ServiceGetV2.model_json_schema()["examples"][0]
)
got.version = service_version
got.key = service_key

return got

async def update_service(
self,
rpc_client: RabbitMQRPCClient,
*,
product_name: ProductName,
user_id: UserID,
service_key: ServiceKey,
service_version: ServiceVersion,
update: CatalogServiceUpdate,
):
assert rpc_client
assert product_name
assert user_id

got = ServiceGetV2.model_validate(
ServiceGetV2.model_json_schema()["examples"][0]
)
got.version = service_version
got.key = service_key
return got.model_copy(update=update.model_dump(exclude_unset=True))

async def list_my_service_history_paginated(
self,
rpc_client: RabbitMQRPCClient,
*,
product_name: ProductName,
user_id: UserID,
service_key: ServiceKey,
offset: PageOffsetInt,
limit: PageLimitInt,
) -> PageRpc[ServiceRelease]:

assert rpc_client
assert product_name
assert user_id
assert service_key

items = TypeAdapter(list[ServiceRelease]).validate_python(
ServiceRelease.model_json_schema()["examples"],
)
total_count = len(items)

return PageRpc[ServiceRelease].create(
items[offset : offset + limit],
total=total_count,
limit=limit,
offset=offset,
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,23 @@
from models_library.api_schemas_catalog.services import (
LatestServiceGet,
MyServiceGet,
PageRpcLatestServiceGet,
PageRpcServiceRelease,
ServiceGetV2,
ServiceRelease,
ServiceUpdateV2,
)
from models_library.products import ProductName
from models_library.rabbitmq_basic_types import RPCMethodName
from models_library.rest_pagination import PageOffsetInt
from models_library.rpc_pagination import (
DEFAULT_NUMBER_OF_ITEMS_PER_PAGE,
PageLimitInt,
PageRpc,
)
from models_library.services_types import ServiceKey, ServiceVersion
from models_library.users import UserID
from pydantic import NonNegativeInt, TypeAdapter, validate_call
from pydantic import TypeAdapter, validate_call
from servicelib.logging_utils import log_decorator
from servicelib.rabbitmq._constants import RPC_REQUEST_DEFAULT_TIMEOUT_S

Expand All @@ -34,8 +38,8 @@ async def list_services_paginated( # pylint: disable=too-many-arguments
product_name: ProductName,
user_id: UserID,
limit: PageLimitInt = DEFAULT_NUMBER_OF_ITEMS_PER_PAGE,
offset: NonNegativeInt = 0,
) -> PageRpc[LatestServiceGet]:
offset: PageOffsetInt = 0,
) -> PageRpcLatestServiceGet:
"""
Raises:
ValidationError: on invalid arguments
Expand All @@ -47,7 +51,7 @@ async def _call(
product_name: ProductName,
user_id: UserID,
limit: PageLimitInt,
offset: NonNegativeInt,
offset: PageOffsetInt,
):
return await rpc_client.request(
CATALOG_RPC_NAMESPACE,
Expand Down Expand Up @@ -235,3 +239,51 @@ async def _call(
result = await _call(product_name=product_name, user_id=user_id, ids=ids)
assert TypeAdapter(list[MyServiceGet]).validate_python(result) is not None # nosec
return cast(list[MyServiceGet], result)


async def list_my_service_history_paginated( # pylint: disable=too-many-arguments
rpc_client: RabbitMQRPCClient,
*,
product_name: ProductName,
user_id: UserID,
service_key: ServiceKey,
limit: PageLimitInt = DEFAULT_NUMBER_OF_ITEMS_PER_PAGE,
offset: PageOffsetInt = 0,
) -> PageRpcServiceRelease:
"""
Raises:
ValidationError: on invalid arguments
"""

@validate_call()
async def _call(
product_name: ProductName,
user_id: UserID,
service_key: ServiceKey,
limit: PageLimitInt,
offset: PageOffsetInt,
):
return await rpc_client.request(
CATALOG_RPC_NAMESPACE,
TypeAdapter(RPCMethodName).validate_python(
"list_my_service_history_paginated"
),
product_name=product_name,
user_id=user_id,
service_key=service_key,
limit=limit,
offset=offset,
)

result = await _call(
product_name=product_name,
user_id=user_id,
service_key=service_key,
limit=limit,
offset=offset,
)

assert ( # nosec
TypeAdapter(PageRpcServiceRelease).validate_python(result) is not None
)
return cast(PageRpc[ServiceRelease], result)
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@

from fastapi import FastAPI, status
from models_library.emails import LowerCaseEmailStr
from models_library.products import ProductName
from models_library.services import ServiceMetaDataPublished, ServiceType
from models_library.users import UserID
from pydantic import ConfigDict, TypeAdapter, ValidationError
from settings_library.catalog import CatalogSettings
from settings_library.tracing import TracingSettings
Expand Down Expand Up @@ -70,9 +72,9 @@ def to_solver(self) -> Solver:

_exception_mapper = partial(service_exception_mapper, service_name="Catalog")

TruncatedCatalogServiceOutAdapter: Final[
TypeAdapter[TruncatedCatalogServiceOut]
] = TypeAdapter(TruncatedCatalogServiceOut)
TruncatedCatalogServiceOutAdapter: Final[TypeAdapter[TruncatedCatalogServiceOut]] = (
TypeAdapter(TruncatedCatalogServiceOut)
)
TruncatedCatalogServiceOutListAdapter: Final[
TypeAdapter[list[TruncatedCatalogServiceOut]]
] = TypeAdapter(list[TruncatedCatalogServiceOut])
Expand All @@ -97,8 +99,8 @@ class CatalogApi(BaseServiceClientApi):
async def list_solvers(
self,
*,
user_id: int,
product_name: str,
user_id: UserID,
product_name: ProductName,
predicate: Callable[[Solver], bool] | None = None,
) -> list[Solver]:

Expand Down Expand Up @@ -140,7 +142,12 @@ async def list_solvers(
http_status_map={status.HTTP_404_NOT_FOUND: SolverOrStudyNotFoundError}
)
async def get_service(
self, *, user_id: int, name: SolverKeyId, version: VersionStr, product_name: str
self,
*,
user_id: UserID,
name: SolverKeyId,
version: VersionStr,
product_name: ProductName,
) -> Solver:

assert version != LATEST_VERSION # nosec
Expand Down Expand Up @@ -171,8 +178,13 @@ async def get_service(
http_status_map={status.HTTP_404_NOT_FOUND: SolverOrStudyNotFoundError}
)
async def get_service_ports(
self, *, user_id: int, name: SolverKeyId, version: VersionStr, product_name: str
):
self,
*,
user_id: UserID,
name: SolverKeyId,
version: VersionStr,
product_name: ProductName,
) -> list[SolverPort]:

assert version != LATEST_VERSION # nosec

Expand All @@ -190,7 +202,7 @@ async def get_service_ports(
return TypeAdapter(list[SolverPort]).validate_python(response.json())

async def list_latest_releases(
self, *, user_id: int, product_name: str
self, *, user_id: UserID, product_name: ProductName
) -> list[Solver]:
solvers: list[Solver] = await self.list_solvers(
user_id=user_id, product_name=product_name
Expand All @@ -205,7 +217,7 @@ async def list_latest_releases(
return list(latest_releases.values())

async def list_solver_releases(
self, *, user_id: int, solver_key: SolverKeyId, product_name: str
self, *, user_id: UserID, solver_key: SolverKeyId, product_name: ProductName
) -> list[Solver]:
def _this_solver(solver: Solver) -> bool:
return solver.id == solver_key
Expand All @@ -216,7 +228,7 @@ def _this_solver(solver: Solver) -> bool:
return releases

async def get_latest_release(
self, *, user_id: int, solver_key: SolverKeyId, product_name: str
self, *, user_id: UserID, solver_key: SolverKeyId, product_name: ProductName
) -> Solver:
releases = await self.list_solver_releases(
user_id=user_id, solver_key=solver_key, product_name=product_name
Expand Down
Loading
Loading