Skip to content

Commit 3881d18

Browse files
author
Andrei Neagu
committed
Merge remote-tracking branch 'upstream/master' into pr-osparc-deflate64-zip
2 parents 6d8c10a + 92ff5d5 commit 3881d18

File tree

49 files changed

+1167
-347
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1167
-347
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
""" Helper script to generate OAS automatically
2+
"""
3+
4+
# pylint: disable=redefined-outer-name
5+
# pylint: disable=unused-argument
6+
# pylint: disable=unused-variable
7+
# pylint: disable=too-many-arguments
8+
9+
from typing import Annotated
10+
11+
from _common import as_query
12+
from fastapi import APIRouter, Depends
13+
from models_library.api_schemas_webserver.licensed_items_purchases import (
14+
LicensedItemPurchaseGet,
15+
)
16+
from models_library.generics import Envelope
17+
from models_library.rest_error import EnvelopedError
18+
from models_library.rest_pagination import Page
19+
from simcore_service_webserver._meta import API_VTAG
20+
from simcore_service_webserver.licenses._exceptions_handlers import _TO_HTTP_ERROR_MAP
21+
from simcore_service_webserver.licenses._licensed_items_checkouts_models import (
22+
LicensedItemCheckoutPathParams,
23+
LicensedItemsCheckoutsListQueryParams,
24+
)
25+
from simcore_service_webserver.wallets._handlers import WalletsPathParams
26+
27+
router = APIRouter(
28+
prefix=f"/{API_VTAG}",
29+
tags=[
30+
"licenses",
31+
],
32+
responses={
33+
i.status_code: {"model": EnvelopedError} for i in _TO_HTTP_ERROR_MAP.values()
34+
},
35+
)
36+
37+
38+
@router.get(
39+
"/wallets/{wallet_id}/licensed-items-checkouts",
40+
response_model=Page[LicensedItemPurchaseGet],
41+
tags=["wallets"],
42+
)
43+
async def list_licensed_item_checkouts_for_wallet(
44+
_path: Annotated[WalletsPathParams, Depends()],
45+
_query: Annotated[as_query(LicensedItemsCheckoutsListQueryParams), Depends()],
46+
):
47+
...
48+
49+
50+
@router.get(
51+
"/licensed-items-checkouts/{licensed_item_checkout_id}",
52+
response_model=Envelope[LicensedItemPurchaseGet],
53+
)
54+
async def get_licensed_item_checkout(
55+
_path: Annotated[LicensedItemCheckoutPathParams, Depends()],
56+
):
57+
...

api/specs/web-server/openapi.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"_long_running_tasks",
3939
"_licensed_items",
4040
"_licensed_items_purchases",
41+
"_licensed_items_checkouts",
4142
"_metamodeling",
4243
"_nih_sparc",
4344
"_nih_sparc_redirections",

packages/common-library/src/common_library/unset.py renamed to packages/common-library/src/common_library/exclude.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,7 @@ class UnSet:
1010

1111
def as_dict_exclude_unset(**params) -> dict[str, Any]:
1212
return {k: v for k, v in params.items() if not isinstance(v, UnSet)}
13+
14+
15+
def as_dict_exclude_none(**params) -> dict[str, Any]:
16+
return {k: v for k, v in params.items() if v is not None}

packages/common-library/tests/test_unset.py renamed to packages/common-library/tests/test_exclude.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import Any
22

3-
from common_library.unset import UnSet, as_dict_exclude_unset
3+
from common_library.exclude import UnSet, as_dict_exclude_none, as_dict_exclude_unset
44

55

66
def test_as_dict_exclude_unset():
@@ -13,3 +13,10 @@ def f(
1313
assert f(par1="hi") == {"par1": "hi"}
1414
assert f(par2=4) == {"par2": 4}
1515
assert f(par1="hi", par2=4) == {"par1": "hi", "par2": 4}
16+
17+
# still expected behavior
18+
assert as_dict_exclude_unset(par1=None) == {"par1": None}
19+
20+
21+
def test_as_dict_exclude_none():
22+
assert as_dict_exclude_none(par1=None) == {}
Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from datetime import datetime
22
from typing import NamedTuple
33

4-
from pydantic import PositiveInt
4+
from pydantic import BaseModel, PositiveInt
55

66
from ..licensed_items import LicensedItemID
77
from ..products import ProductName
@@ -10,8 +10,29 @@
1010
from ..wallets import WalletID
1111
from ._base import OutputSchema
1212

13+
# RPC
1314

14-
class LicensedItemCheckoutGet(OutputSchema):
15+
16+
class LicensedItemCheckoutRpcGet(BaseModel):
17+
licensed_item_checkout_id: LicensedItemCheckoutID
18+
licensed_item_id: LicensedItemID
19+
wallet_id: WalletID
20+
user_id: UserID
21+
product_name: ProductName
22+
started_at: datetime
23+
stopped_at: datetime | None
24+
num_of_seats: int
25+
26+
27+
class LicensedItemCheckoutRpcGetPage(NamedTuple):
28+
items: list[LicensedItemCheckoutRpcGet]
29+
total: PositiveInt
30+
31+
32+
# Rest
33+
34+
35+
class LicensedItemCheckoutRestGet(OutputSchema):
1536
licensed_item_checkout_id: LicensedItemCheckoutID
1637
licensed_item_id: LicensedItemID
1738
wallet_id: WalletID
@@ -22,6 +43,6 @@ class LicensedItemCheckoutGet(OutputSchema):
2243
num_of_seats: int
2344

2445

25-
class LicensedItemUsageGetPage(NamedTuple):
26-
items: list[LicensedItemCheckoutGet]
46+
class LicensedItemCheckoutRestGetPage(NamedTuple):
47+
items: list[LicensedItemCheckoutRestGet]
2748
total: PositiveInt
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""add deprecated submit column
2+
3+
Revision ID: 307017ee1a49
4+
Revises: 1e3c9c804fec
5+
Create Date: 2025-01-06 12:53:51.604189+00:00
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = '307017ee1a49'
14+
down_revision = '1e3c9c804fec'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.add_column('comp_tasks', sa.Column('submit', sa.DateTime(timezone=True), server_default=sa.text("'1900-01-01T00:00:00Z'::timestamptz"), nullable=True))
22+
# ### end Alembic commands ###
23+
24+
25+
def downgrade():
26+
# ### commands auto generated by Alembic - please adjust! ###
27+
op.drop_column('comp_tasks', 'submit')
28+
# ### end Alembic commands ###

packages/postgres-database/src/simcore_postgres_database/models/comp_tasks.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
""" Computational Tasks Table
2-
3-
"""
1+
"""Computational Tasks Table"""
42

53
import enum
64

@@ -102,6 +100,14 @@ class NodeClass(enum.Enum):
102100
nullable=True,
103101
doc="Harware information of this task",
104102
),
103+
# deprecated columns must be kept due to legacy services
104+
# utc timestamps for submission/start/end
105+
sa.Column(
106+
"submit",
107+
sa.DateTime(timezone=True),
108+
server_default=sa.text("'1900-01-01T00:00:00Z'::timestamptz"),
109+
doc="[DEPRECATED unused but kept for legacy services and must be filled with a default value of 1 January 1900]",
110+
),
105111
# ------
106112
sa.UniqueConstraint("project_id", "node_id", name="project_node_uniqueness"),
107113
)

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
LicensedItemGetPage,
77
)
88
from models_library.api_schemas_webserver.licensed_items_checkouts import (
9-
LicensedItemCheckoutGet,
9+
LicensedItemCheckoutRpcGet,
1010
)
1111
from models_library.licensed_items import LicensedItemID
1212
from models_library.products import ProductName
@@ -78,7 +78,7 @@ async def checkout_licensed_item_for_wallet(
7878
licensed_item_id: LicensedItemID,
7979
num_of_seats: int,
8080
service_run_id: ServiceRunID,
81-
) -> LicensedItemCheckoutGet:
81+
) -> LicensedItemCheckoutRpcGet:
8282
result = await rabbitmq_rpc_client.request(
8383
WEBSERVER_RPC_NAMESPACE,
8484
TypeAdapter(RPCMethodName).validate_python("checkout_licensed_item_for_wallet"),
@@ -89,7 +89,7 @@ async def checkout_licensed_item_for_wallet(
8989
num_of_seats=num_of_seats,
9090
service_run_id=service_run_id,
9191
)
92-
assert isinstance(result, LicensedItemCheckoutGet) # nosec
92+
assert isinstance(result, LicensedItemCheckoutRpcGet) # nosec
9393
return result
9494

9595

@@ -100,13 +100,13 @@ async def release_licensed_item_for_wallet(
100100
product_name: ProductName,
101101
user_id: UserID,
102102
licensed_item_checkout_id: LicensedItemCheckoutID,
103-
) -> LicensedItemCheckoutGet:
103+
) -> LicensedItemCheckoutRpcGet:
104104
result = await rabbitmq_rpc_client.request(
105105
WEBSERVER_RPC_NAMESPACE,
106106
TypeAdapter(RPCMethodName).validate_python("release_licensed_item_for_wallet"),
107107
product_name=product_name,
108108
user_id=user_id,
109109
licensed_item_checkout_id=licensed_item_checkout_id,
110110
)
111-
assert isinstance(result, LicensedItemCheckoutGet) # nosec
111+
assert isinstance(result, LicensedItemCheckoutRpcGet) # nosec
112112
return result

services/director-v2/src/simcore_service_director_v2/models/comp_tasks.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ class CompTaskAtDB(BaseModel):
150150
pricing_info: dict | None
151151
hardware_info: HardwareInfo
152152

153+
submit: dt.datetime | None = Field(
154+
default=None, deprecated=True, description="Required for legacy services"
155+
)
156+
153157
@field_validator("state", mode="before")
154158
@classmethod
155159
def _convert_state_from_state_type_enum_if_needed(cls, v):
@@ -238,7 +242,9 @@ def to_db_model(self, **exclusion_rules) -> dict[str, Any]:
238242
"pricing_unit_id": 1,
239243
"pricing_unit_cost_id": 1,
240244
},
241-
"hardware_info": next(iter(HardwareInfo.model_config["json_schema_extra"]["examples"])), # type: ignore
245+
"hardware_info": next(
246+
iter(HardwareInfo.model_config["json_schema_extra"]["examples"]) # type: ignore
247+
),
242248
}
243249
for image_example in Image.model_config["json_schema_extra"]["examples"] # type: ignore
244250
]

services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v2/_thin_client.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import datetime
22
from typing import cast
33

4+
from common_library.exclude import as_dict_exclude_none
45
from common_library.json_serialization import json_dumps
5-
from common_library.unset import UnSet, as_dict_exclude_unset
66
from fastapi import FastAPI, status
77
from httpx import Response, Timeout
88
from models_library.api_schemas_dynamic_scheduler.dynamic_services import (
@@ -133,14 +133,11 @@ async def dynamic_service_retrieve(
133133
@retry_on_errors()
134134
@expect_status(status.HTTP_200_OK)
135135
async def get_dynamic_services(
136-
self,
137-
*,
138-
user_id: UserID | None | UnSet = UnSet.VALUE,
139-
project_id: ProjectID | None | UnSet = UnSet.VALUE,
136+
self, *, user_id: UserID | None = None, project_id: ProjectID | None = None
140137
) -> Response:
141138
return await self.client.get(
142139
"/dynamic_services",
143-
params=as_dict_exclude_unset(user_id=user_id, project_id=project_id),
140+
params=as_dict_exclude_none(user_id=user_id, project_id=project_id),
144141
)
145142

146143
@retry_on_errors()

0 commit comments

Comments
 (0)