Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into pr-osparc-deflate…
Browse files Browse the repository at this point in the history
…64-zip
  • Loading branch information
Andrei Neagu committed Jan 7, 2025
2 parents 6d8c10a + 92ff5d5 commit 3881d18
Show file tree
Hide file tree
Showing 49 changed files with 1,167 additions and 347 deletions.
57 changes: 57 additions & 0 deletions api/specs/web-server/_licensed_items_checkouts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
""" Helper script to generate OAS automatically
"""

# pylint: disable=redefined-outer-name
# pylint: disable=unused-argument
# pylint: disable=unused-variable
# pylint: disable=too-many-arguments

from typing import Annotated

from _common import as_query
from fastapi import APIRouter, Depends
from models_library.api_schemas_webserver.licensed_items_purchases import (
LicensedItemPurchaseGet,
)
from models_library.generics import Envelope
from models_library.rest_error import EnvelopedError
from models_library.rest_pagination import Page
from simcore_service_webserver._meta import API_VTAG
from simcore_service_webserver.licenses._exceptions_handlers import _TO_HTTP_ERROR_MAP
from simcore_service_webserver.licenses._licensed_items_checkouts_models import (
LicensedItemCheckoutPathParams,
LicensedItemsCheckoutsListQueryParams,
)
from simcore_service_webserver.wallets._handlers import WalletsPathParams

router = APIRouter(
prefix=f"/{API_VTAG}",
tags=[
"licenses",
],
responses={
i.status_code: {"model": EnvelopedError} for i in _TO_HTTP_ERROR_MAP.values()
},
)


@router.get(
"/wallets/{wallet_id}/licensed-items-checkouts",
response_model=Page[LicensedItemPurchaseGet],
tags=["wallets"],
)
async def list_licensed_item_checkouts_for_wallet(
_path: Annotated[WalletsPathParams, Depends()],
_query: Annotated[as_query(LicensedItemsCheckoutsListQueryParams), Depends()],
):
...


@router.get(
"/licensed-items-checkouts/{licensed_item_checkout_id}",
response_model=Envelope[LicensedItemPurchaseGet],
)
async def get_licensed_item_checkout(
_path: Annotated[LicensedItemCheckoutPathParams, Depends()],
):
...
1 change: 1 addition & 0 deletions api/specs/web-server/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"_long_running_tasks",
"_licensed_items",
"_licensed_items_purchases",
"_licensed_items_checkouts",
"_metamodeling",
"_nih_sparc",
"_nih_sparc_redirections",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ class UnSet:

def as_dict_exclude_unset(**params) -> dict[str, Any]:
return {k: v for k, v in params.items() if not isinstance(v, UnSet)}


def as_dict_exclude_none(**params) -> dict[str, Any]:
return {k: v for k, v in params.items() if v is not None}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Any

from common_library.unset import UnSet, as_dict_exclude_unset
from common_library.exclude import UnSet, as_dict_exclude_none, as_dict_exclude_unset


def test_as_dict_exclude_unset():
Expand All @@ -13,3 +13,10 @@ def f(
assert f(par1="hi") == {"par1": "hi"}
assert f(par2=4) == {"par2": 4}
assert f(par1="hi", par2=4) == {"par1": "hi", "par2": 4}

# still expected behavior
assert as_dict_exclude_unset(par1=None) == {"par1": None}


def test_as_dict_exclude_none():
assert as_dict_exclude_none(par1=None) == {}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from datetime import datetime
from typing import NamedTuple

from pydantic import PositiveInt
from pydantic import BaseModel, PositiveInt

from ..licensed_items import LicensedItemID
from ..products import ProductName
Expand All @@ -10,8 +10,29 @@
from ..wallets import WalletID
from ._base import OutputSchema

# RPC

class LicensedItemCheckoutGet(OutputSchema):

class LicensedItemCheckoutRpcGet(BaseModel):
licensed_item_checkout_id: LicensedItemCheckoutID
licensed_item_id: LicensedItemID
wallet_id: WalletID
user_id: UserID
product_name: ProductName
started_at: datetime
stopped_at: datetime | None
num_of_seats: int


class LicensedItemCheckoutRpcGetPage(NamedTuple):
items: list[LicensedItemCheckoutRpcGet]
total: PositiveInt


# Rest


class LicensedItemCheckoutRestGet(OutputSchema):
licensed_item_checkout_id: LicensedItemCheckoutID
licensed_item_id: LicensedItemID
wallet_id: WalletID
Expand All @@ -22,6 +43,6 @@ class LicensedItemCheckoutGet(OutputSchema):
num_of_seats: int


class LicensedItemUsageGetPage(NamedTuple):
items: list[LicensedItemCheckoutGet]
class LicensedItemCheckoutRestGetPage(NamedTuple):
items: list[LicensedItemCheckoutRestGet]
total: PositiveInt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""add deprecated submit column
Revision ID: 307017ee1a49
Revises: 1e3c9c804fec
Create Date: 2025-01-06 12:53:51.604189+00:00
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '307017ee1a49'
down_revision = '1e3c9c804fec'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('comp_tasks', sa.Column('submit', sa.DateTime(timezone=True), server_default=sa.text("'1900-01-01T00:00:00Z'::timestamptz"), nullable=True))
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('comp_tasks', 'submit')
# ### end Alembic commands ###
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
""" Computational Tasks Table
"""
"""Computational Tasks Table"""

import enum

Expand Down Expand Up @@ -102,6 +100,14 @@ class NodeClass(enum.Enum):
nullable=True,
doc="Harware information of this task",
),
# deprecated columns must be kept due to legacy services
# utc timestamps for submission/start/end
sa.Column(
"submit",
sa.DateTime(timezone=True),
server_default=sa.text("'1900-01-01T00:00:00Z'::timestamptz"),
doc="[DEPRECATED unused but kept for legacy services and must be filled with a default value of 1 January 1900]",
),
# ------
sa.UniqueConstraint("project_id", "node_id", name="project_node_uniqueness"),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
LicensedItemGetPage,
)
from models_library.api_schemas_webserver.licensed_items_checkouts import (
LicensedItemCheckoutGet,
LicensedItemCheckoutRpcGet,
)
from models_library.licensed_items import LicensedItemID
from models_library.products import ProductName
Expand Down Expand Up @@ -78,7 +78,7 @@ async def checkout_licensed_item_for_wallet(
licensed_item_id: LicensedItemID,
num_of_seats: int,
service_run_id: ServiceRunID,
) -> LicensedItemCheckoutGet:
) -> LicensedItemCheckoutRpcGet:
result = await rabbitmq_rpc_client.request(
WEBSERVER_RPC_NAMESPACE,
TypeAdapter(RPCMethodName).validate_python("checkout_licensed_item_for_wallet"),
Expand All @@ -89,7 +89,7 @@ async def checkout_licensed_item_for_wallet(
num_of_seats=num_of_seats,
service_run_id=service_run_id,
)
assert isinstance(result, LicensedItemCheckoutGet) # nosec
assert isinstance(result, LicensedItemCheckoutRpcGet) # nosec
return result


Expand All @@ -100,13 +100,13 @@ async def release_licensed_item_for_wallet(
product_name: ProductName,
user_id: UserID,
licensed_item_checkout_id: LicensedItemCheckoutID,
) -> LicensedItemCheckoutGet:
) -> LicensedItemCheckoutRpcGet:
result = await rabbitmq_rpc_client.request(
WEBSERVER_RPC_NAMESPACE,
TypeAdapter(RPCMethodName).validate_python("release_licensed_item_for_wallet"),
product_name=product_name,
user_id=user_id,
licensed_item_checkout_id=licensed_item_checkout_id,
)
assert isinstance(result, LicensedItemCheckoutGet) # nosec
assert isinstance(result, LicensedItemCheckoutRpcGet) # nosec
return result
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ class CompTaskAtDB(BaseModel):
pricing_info: dict | None
hardware_info: HardwareInfo

submit: dt.datetime | None = Field(
default=None, deprecated=True, description="Required for legacy services"
)

@field_validator("state", mode="before")
@classmethod
def _convert_state_from_state_type_enum_if_needed(cls, v):
Expand Down Expand Up @@ -238,7 +242,9 @@ def to_db_model(self, **exclusion_rules) -> dict[str, Any]:
"pricing_unit_id": 1,
"pricing_unit_cost_id": 1,
},
"hardware_info": next(iter(HardwareInfo.model_config["json_schema_extra"]["examples"])), # type: ignore
"hardware_info": next(
iter(HardwareInfo.model_config["json_schema_extra"]["examples"]) # type: ignore
),
}
for image_example in Image.model_config["json_schema_extra"]["examples"] # type: ignore
]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import datetime
from typing import cast

from common_library.exclude import as_dict_exclude_none
from common_library.json_serialization import json_dumps
from common_library.unset import UnSet, as_dict_exclude_unset
from fastapi import FastAPI, status
from httpx import Response, Timeout
from models_library.api_schemas_dynamic_scheduler.dynamic_services import (
Expand Down Expand Up @@ -133,14 +133,11 @@ async def dynamic_service_retrieve(
@retry_on_errors()
@expect_status(status.HTTP_200_OK)
async def get_dynamic_services(
self,
*,
user_id: UserID | None | UnSet = UnSet.VALUE,
project_id: ProjectID | None | UnSet = UnSet.VALUE,
self, *, user_id: UserID | None = None, project_id: ProjectID | None = None
) -> Response:
return await self.client.get(
"/dynamic_services",
params=as_dict_exclude_unset(user_id=user_id, project_id=project_id),
params=as_dict_exclude_none(user_id=user_id, project_id=project_id),
)

@retry_on_errors()
Expand Down
Loading

0 comments on commit 3881d18

Please sign in to comment.