Skip to content

Commit a0911f5

Browse files
committed
@sanderegg review: refactor schemas
1 parent a531010 commit a0911f5

File tree

5 files changed

+75
-72
lines changed

5 files changed

+75
-72
lines changed

services/web/server/src/simcore_service_webserver/studies_dispatcher/_redirects_handlers.py renamed to services/web/server/src/simcore_service_webserver/studies_dispatcher/_controller_rest_redirects.py

Lines changed: 8 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,14 @@
22

33
import functools
44
import logging
5-
import urllib.parse
6-
from typing import TypeAlias
75

86
from aiohttp import web
97
from common_library.error_codes import create_error_code
108
from common_library.user_messages import user_message
119
from models_library.function_services_catalog._utils import ServiceNotFound
1210
from models_library.projects import ProjectID
1311
from models_library.projects_nodes_io import NodeID
14-
from models_library.services import ServiceKey, ServiceVersion
15-
from pydantic import BaseModel, ConfigDict, ValidationError, field_validator
12+
from pydantic import ValidationError
1613
from servicelib.aiohttp import status
1714
from servicelib.aiohttp.requests_validation import parse_request_query_parameters_as
1815
from servicelib.aiohttp.typing_extension import Handler
@@ -25,6 +22,12 @@
2522
from ..utils_aiohttp import create_redirect_to_page_response, get_api_base_url
2623
from ._catalog import ValidService, validate_requested_service
2724
from ._constants import MSG_UNEXPECTED_DISPATCH_ERROR
25+
from ._controller_rest_redirects_schemas import (
26+
FileQueryParams,
27+
RedirectionQueryParams,
28+
ServiceAndFileParams,
29+
ServiceQueryParams,
30+
)
2831
from ._core import validate_requested_file, validate_requested_viewer
2932
from ._errors import (
3033
FileToLargeError,
@@ -34,7 +37,7 @@
3437
InvalidRedirectionParamsError,
3538
ProjectWorkbenchMismatchError,
3639
)
37-
from ._models import FileParams, ServiceInfo, ServiceParams, ViewerInfo
40+
from ._models import ServiceInfo, ViewerInfo
3841
from ._projects import (
3942
get_or_create_project_with_file,
4043
get_or_create_project_with_file_and_service,
@@ -218,64 +221,6 @@ async def wrapper(request: web.Request) -> web.StreamResponse:
218221
return wrapper
219222

220223

221-
#
222-
# API ScheMAS
223-
#
224-
225-
226-
class ServiceQueryParams(ServiceParams):
227-
model_config = ConfigDict(extra="forbid")
228-
229-
230-
class FileQueryParams(FileParams):
231-
model_config = ConfigDict(extra="forbid")
232-
233-
@field_validator("file_type")
234-
@classmethod
235-
def _ensure_extension_upper_and_dotless(cls, v):
236-
# NOTE: see filetype constraint-check
237-
if v and isinstance(v, str):
238-
w = urllib.parse.unquote(v)
239-
return w.upper().lstrip(".")
240-
return v
241-
242-
243-
class ServiceAndFileParams(FileQueryParams, ServiceParams): ...
244-
245-
246-
class ViewerQueryParams(BaseModel):
247-
file_type: str | None = None
248-
viewer_key: ServiceKey
249-
viewer_version: ServiceVersion
250-
251-
@staticmethod
252-
def from_viewer(viewer: ViewerInfo) -> "ViewerQueryParams":
253-
# can safely construct w/o validation from a viewer
254-
return ViewerQueryParams.model_construct(
255-
file_type=viewer.filetype,
256-
viewer_key=viewer.key,
257-
viewer_version=viewer.version,
258-
)
259-
260-
@field_validator("file_type")
261-
@classmethod
262-
def _ensure_extension_upper_and_dotless(cls, v):
263-
# NOTE: see filetype constraint-check
264-
if v and isinstance(v, str):
265-
w = urllib.parse.unquote(v)
266-
return w.upper().lstrip(".")
267-
return v
268-
269-
270-
RedirectionQueryParams: TypeAlias = (
271-
# NOTE: Extra.forbid in FileQueryParams, ServiceQueryParams avoids bad casting when
272-
# errors in ServiceAndFileParams
273-
ServiceAndFileParams
274-
| FileQueryParams
275-
| ServiceQueryParams
276-
)
277-
278-
279224
#
280225
# API HANDLERS
281226
#
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import urllib.parse
2+
from typing import TypeAlias
3+
4+
from models_library.services import ServiceKey, ServiceVersion
5+
from pydantic import BaseModel, ConfigDict, field_validator
6+
7+
from ._models import FileParams, ServiceParams, ViewerInfo
8+
9+
10+
class ServiceQueryParams(ServiceParams):
11+
model_config = ConfigDict(extra="forbid")
12+
13+
14+
class FileQueryParams(FileParams):
15+
model_config = ConfigDict(extra="forbid")
16+
17+
@field_validator("file_type")
18+
@classmethod
19+
def _ensure_extension_upper_and_dotless(cls, v):
20+
# NOTE: see filetype constraint-check
21+
if v and isinstance(v, str):
22+
w = urllib.parse.unquote(v)
23+
return w.upper().lstrip(".")
24+
return v
25+
26+
27+
class ServiceAndFileParams(FileQueryParams, ServiceParams): ...
28+
29+
30+
class ViewerQueryParams(BaseModel):
31+
file_type: str | None = None
32+
viewer_key: ServiceKey
33+
viewer_version: ServiceVersion
34+
35+
@staticmethod
36+
def from_viewer(viewer: ViewerInfo) -> "ViewerQueryParams":
37+
# can safely construct w/o validation from a viewer
38+
return ViewerQueryParams.model_construct(
39+
file_type=viewer.filetype,
40+
viewer_key=viewer.key,
41+
viewer_version=viewer.version,
42+
)
43+
44+
@field_validator("file_type")
45+
@classmethod
46+
def _ensure_extension_upper_and_dotless(cls, v):
47+
# NOTE: see filetype constraint-check
48+
if v and isinstance(v, str):
49+
w = urllib.parse.unquote(v)
50+
return w.upper().lstrip(".")
51+
return v
52+
53+
54+
RedirectionQueryParams: TypeAlias = (
55+
# NOTE: Extra.forbid in FileQueryParams, ServiceQueryParams avoids bad casting when
56+
# errors in ServiceAndFileParams
57+
ServiceAndFileParams
58+
| FileQueryParams
59+
| ServiceQueryParams
60+
)

services/web/server/src/simcore_service_webserver/studies_dispatcher/_rest_handlers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
from ..products import products_web
2222
from ..utils_aiohttp import envelope_json_response
2323
from ._catalog import ServiceMetaData, iter_latest_product_services
24+
from ._controller_rest_redirects import ViewerQueryParams
2425
from ._core import list_viewers_info
2526
from ._models import ViewerInfo
26-
from ._redirects_handlers import ViewerQueryParams
2727

2828
_logger = logging.getLogger(__name__)
2929

services/web/server/src/simcore_service_webserver/studies_dispatcher/plugin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
from ..login.decorators import login_required
77
from ..products.plugin import setup_products
88
from . import _rest_handlers
9+
from ._controller_rest_redirects import get_redirection_to_viewer
910
from ._projects_permalinks import setup_projects_permalinks
10-
from ._redirects_handlers import get_redirection_to_viewer
1111
from ._studies_access import get_redirection_to_study_page
1212
from .settings import StudiesDispatcherSettings, get_plugin_settings
1313

services/web/server/tests/unit/isolated/test_studies_dispatcher_models.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@
1313
from models_library.utils.pydantic_tools_extension import parse_obj_or_none
1414
from pydantic import ByteSize, TypeAdapter
1515
from servicelib.aiohttp.requests_validation import parse_request_query_parameters_as
16+
from simcore_service_webserver.studies_dispatcher._controller_rest_redirects_schemas import (
17+
FileQueryParams,
18+
ServiceAndFileParams,
19+
)
1620
from simcore_service_webserver.studies_dispatcher._models import (
1721
FileParams,
1822
ServiceParams,
1923
)
20-
from simcore_service_webserver.studies_dispatcher._redirects_handlers import (
21-
FileQueryParams,
22-
ServiceAndFileParams,
23-
)
2424
from yarl import URL
2525

2626
_SIZEBYTES = TypeAdapter(ByteSize).validate_python("3MiB")
@@ -79,9 +79,7 @@ def test_download_link_validators_2(file_and_service_params: dict[str, Any]):
7979
assert params.download_link
8080

8181
assert params.download_link.host
82-
assert params.download_link.host.endswith(
83-
"s3.amazonaws.com"
84-
)
82+
assert params.download_link.host.endswith("s3.amazonaws.com")
8583

8684
query = parse_qs(params.download_link.query)
8785
assert {"AWSAccessKeyId", "Signature", "Expires", "x-amz-request-payer"} == set(

0 commit comments

Comments
 (0)