Skip to content

Commit 1a322be

Browse files
authored
🐛Datcore-Adapter: fix listing files in pennsieve pagination sized 1000 (#7464)
1 parent 020e2df commit 1a322be

File tree

3 files changed

+57
-38
lines changed

3 files changed

+57
-38
lines changed

services/datcore-adapter/src/simcore_service_datcore_adapter/api/rest/datasets.py

Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
import logging
2-
from typing import Annotated, Final
2+
from typing import Annotated, Final, TypeAlias, TypeVar
33

44
from aiocache import cached # type: ignore[import-untyped]
5-
from fastapi import APIRouter, Depends, Header, Request
6-
from fastapi_pagination import Page, Params
5+
from fastapi import APIRouter, Depends, Header, Query, Request
6+
from fastapi_pagination import LimitOffsetPage, Params
77
from fastapi_pagination.api import create_page, resolve_params
88
from fastapi_pagination.bases import RawParams
9+
from fastapi_pagination.customization import CustomizedPage, UseParamsFields
910
from models_library.api_schemas_datcore_adapter.datasets import (
1011
DatasetMetaData,
1112
FileMetaData,
1213
)
14+
from models_library.api_schemas_storage.storage_schemas import (
15+
DEFAULT_NUMBER_OF_PATHS_PER_PAGE,
16+
MAX_NUMBER_OF_PATHS_PER_PAGE,
17+
)
1318
from servicelib.fastapi.requests_decorators import cancel_on_disconnect
1419
from starlette import status
1520

@@ -25,35 +30,47 @@
2530
) # NOTE: this caching time is arbitrary
2631

2732

33+
_T = TypeVar("_T")
34+
_CustomPage = CustomizedPage[
35+
LimitOffsetPage[_T],
36+
UseParamsFields(
37+
limit=Query(
38+
DEFAULT_NUMBER_OF_PATHS_PER_PAGE, ge=1, le=MAX_NUMBER_OF_PATHS_PER_PAGE
39+
),
40+
),
41+
]
42+
43+
_CustomizedPageParams: TypeAlias = _CustomPage.__params_type__ # type: ignore
44+
45+
2846
@router.get(
2947
"/datasets",
3048
summary="list datasets",
3149
status_code=status.HTTP_200_OK,
32-
response_model=Page[DatasetMetaData],
50+
response_model=_CustomPage[DatasetMetaData],
3351
)
3452
@cancel_on_disconnect
3553
@cached(
3654
ttl=_PENNSIEVE_CACHING_TTL_S,
37-
key_builder=lambda f, *args, **kwargs: f"{f.__name__}_{kwargs['x_datcore_api_key']}_{kwargs['x_datcore_api_secret']}_{kwargs['params']}",
55+
key_builder=lambda f, *args, **kwargs: f"{f.__name__}_{kwargs['x_datcore_api_key']}_{kwargs['x_datcore_api_secret']}_{kwargs['page_params']}",
3856
)
3957
async def list_datasets(
4058
request: Request,
4159
x_datcore_api_key: Annotated[str, Header(..., description="Datcore API Key")],
4260
x_datcore_api_secret: Annotated[str, Header(..., description="Datcore API Secret")],
4361
pennsieve_client: Annotated[PennsieveApiClient, Depends(get_pennsieve_api_client)],
44-
params: Annotated[Params, Depends()],
45-
) -> Page[DatasetMetaData]:
62+
page_params: Annotated[_CustomizedPageParams, Depends()],
63+
):
4664
assert request # nosec
47-
raw_params: RawParams = resolve_params(params).to_raw_params()
48-
assert raw_params.limit is not None # nosec
49-
assert raw_params.offset is not None # nosec
65+
assert page_params.limit is not None # nosec
66+
assert page_params.offset is not None # nosec
5067
datasets, total = await pennsieve_client.list_datasets(
5168
api_key=x_datcore_api_key,
5269
api_secret=x_datcore_api_secret,
53-
limit=raw_params.limit,
54-
offset=raw_params.offset,
70+
limit=page_params.limit,
71+
offset=page_params.offset,
5572
)
56-
return create_page(datasets, total=total, params=params) # type: ignore[return-value]
73+
return create_page(datasets, total=total, params=page_params)
5774

5875

5976
@router.get(
@@ -85,46 +102,45 @@ async def get_dataset(
85102
"/datasets/{dataset_id}/files",
86103
summary="list top level files/folders in a dataset",
87104
status_code=status.HTTP_200_OK,
88-
response_model=Page[FileMetaData],
105+
response_model=_CustomPage[FileMetaData],
89106
)
90107
@cancel_on_disconnect
91108
@cached(
92109
ttl=_PENNSIEVE_CACHING_TTL_S,
93-
key_builder=lambda f, *args, **kwargs: f"{f.__name__}_{kwargs['x_datcore_api_key']}_{kwargs['x_datcore_api_secret']}_{kwargs['dataset_id']}_{kwargs['params']}",
110+
key_builder=lambda f, *args, **kwargs: f"{f.__name__}_{kwargs['x_datcore_api_key']}_{kwargs['x_datcore_api_secret']}_{kwargs['dataset_id']}_{kwargs['page_params']}",
94111
)
95112
async def list_dataset_top_level_files(
96113
request: Request,
97114
dataset_id: str,
98115
x_datcore_api_key: Annotated[str, Header(..., description="Datcore API Key")],
99116
x_datcore_api_secret: Annotated[str, Header(..., description="Datcore API Secret")],
100117
pennsieve_client: Annotated[PennsieveApiClient, Depends(get_pennsieve_api_client)],
101-
params: Annotated[Params, Depends()],
102-
) -> Page[FileMetaData]:
118+
page_params: Annotated[_CustomizedPageParams, Depends()],
119+
):
103120
assert request # nosec
104-
raw_params: RawParams = resolve_params(params).to_raw_params()
105121

106-
assert raw_params.limit is not None # nosec
107-
assert raw_params.offset is not None # nosec
122+
assert page_params.limit is not None # nosec
123+
assert page_params.offset is not None # nosec
108124
file_metas, total = await pennsieve_client.list_packages_in_dataset(
109125
api_key=x_datcore_api_key,
110126
api_secret=x_datcore_api_secret,
111127
dataset_id=dataset_id,
112-
limit=raw_params.limit,
113-
offset=raw_params.offset,
128+
limit=page_params.limit,
129+
offset=page_params.offset,
114130
)
115-
return create_page(file_metas, total=total, params=params) # type: ignore[return-value]
131+
return create_page(file_metas, total=total, params=page_params)
116132

117133

118134
@router.get(
119135
"/datasets/{dataset_id}/files/{collection_id}",
120136
summary="list top level files/folders in a collection in a dataset",
121137
status_code=status.HTTP_200_OK,
122-
response_model=Page[FileMetaData],
138+
response_model=_CustomPage[FileMetaData],
123139
)
124140
@cancel_on_disconnect
125141
@cached(
126142
ttl=_PENNSIEVE_CACHING_TTL_S,
127-
key_builder=lambda f, *args, **kwargs: f"{f.__name__}_{kwargs['x_datcore_api_key']}_{kwargs['x_datcore_api_secret']}_{kwargs['dataset_id']}_{kwargs['collection_id']}_{kwargs['params']}",
143+
key_builder=lambda f, *args, **kwargs: f"{f.__name__}_{kwargs['x_datcore_api_key']}_{kwargs['x_datcore_api_secret']}_{kwargs['dataset_id']}_{kwargs['collection_id']}_{kwargs['page_params']}",
128144
)
129145
async def list_dataset_collection_files(
130146
request: Request,
@@ -133,21 +149,20 @@ async def list_dataset_collection_files(
133149
x_datcore_api_key: Annotated[str, Header(..., description="Datcore API Key")],
134150
x_datcore_api_secret: Annotated[str, Header(..., description="Datcore API Secret")],
135151
pennsieve_client: Annotated[PennsieveApiClient, Depends(get_pennsieve_api_client)],
136-
params: Annotated[Params, Depends()],
137-
) -> Page[FileMetaData]:
152+
page_params: Annotated[_CustomizedPageParams, Depends()],
153+
):
138154
assert request # nosec
139-
raw_params: RawParams = resolve_params(params).to_raw_params()
140-
assert raw_params.limit is not None # nosec
141-
assert raw_params.offset is not None # nosec
155+
assert page_params.limit is not None # nosec
156+
assert page_params.offset is not None # nosec
142157
file_metas, total = await pennsieve_client.list_packages_in_collection(
143158
api_key=x_datcore_api_key,
144159
api_secret=x_datcore_api_secret,
145-
limit=raw_params.limit,
146-
offset=raw_params.offset,
160+
limit=page_params.limit,
161+
offset=page_params.offset,
147162
dataset_id=dataset_id,
148163
collection_id=collection_id,
149164
)
150-
return create_page(file_metas, total=total, params=params) # type: ignore[return-value]
165+
return create_page(file_metas, total=total, params=page_params)
151166

152167

153168
@router.get(

services/datcore-adapter/src/simcore_service_datcore_adapter/modules/pennsieve.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,11 @@ async def list_datasets(
347347
DatasetMetaData(
348348
id=d["content"]["id"],
349349
display_name=d["content"]["name"],
350-
size=ByteSize(d["storage"]) if d["storage"] > 0 else None,
350+
size=(
351+
ByteSize(sz)
352+
if (sz := d.get("storage", 0)) > 0 # NOSONAR
353+
else None
354+
),
351355
)
352356
for d in dataset_page["datasets"]
353357
],

services/datcore-adapter/tests/unit/test_route_datasets.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import httpx
77
import respx
8-
from fastapi_pagination import Page
8+
from fastapi_pagination import LimitOffsetPage
99
from models_library.api_schemas_datcore_adapter.datasets import (
1010
DatasetMetaData,
1111
FileMetaData,
@@ -44,7 +44,7 @@ async def test_list_datasets_entrypoint(
4444
assert response.status_code == status.HTTP_200_OK
4545
data = response.json()
4646
assert data
47-
TypeAdapter(Page[DatasetMetaData]).validate_python(data)
47+
TypeAdapter(LimitOffsetPage[DatasetMetaData]).validate_python(data)
4848

4949

5050
async def test_list_dataset_files_legacy_entrypoint(
@@ -80,7 +80,7 @@ async def test_list_dataset_top_level_files_entrypoint(
8080
assert response.status_code == status.HTTP_200_OK
8181
data = response.json()
8282
assert data
83-
TypeAdapter(Page[FileMetaData]).validate_python(data)
83+
TypeAdapter(LimitOffsetPage[FileMetaData]).validate_python(data)
8484

8585

8686
async def test_list_dataset_collection_files_entrypoint(
@@ -100,4 +100,4 @@ async def test_list_dataset_collection_files_entrypoint(
100100
assert response.status_code == status.HTTP_200_OK
101101
data = response.json()
102102
assert data
103-
TypeAdapter(Page[FileMetaData]).validate_python(data)
103+
TypeAdapter(LimitOffsetPage[FileMetaData]).validate_python(data)

0 commit comments

Comments
 (0)