Skip to content

Commit 51ef078

Browse files
committed
require input input names in exception mapper
1 parent 542b80b commit 51ef078

File tree

5 files changed

+66
-41
lines changed

5 files changed

+66
-41
lines changed

services/api-server/src/simcore_service_api_server/exceptions/service_errors_utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ def service_exception_handler(
128128

129129

130130
def service_exception_mapper(
131+
*,
131132
service_name: str,
132133
http_status_map: HttpStatusMap,
133134
) -> Callable[

services/api-server/src/simcore_service_api_server/services_http/catalog.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def to_solver(self) -> Solver:
6868
# - Error handling: What do we reraise, suppress, transform???
6969
#
7070

71-
_exception_mapper = partial(service_exception_mapper, "Catalog")
71+
_exception_mapper = partial(service_exception_mapper, service_name="Catalog")
7272

7373
TruncatedCatalogServiceOutAdapter: Final[
7474
TypeAdapter[TruncatedCatalogServiceOut]
@@ -91,7 +91,9 @@ class CatalogApi(BaseServiceClientApi):
9191
SEE osparc-simcore/services/catalog/openapi.json
9292
"""
9393

94-
@_exception_mapper({status.HTTP_404_NOT_FOUND: ListSolversOrStudiesError})
94+
@_exception_mapper(
95+
http_status_map={status.HTTP_404_NOT_FOUND: ListSolversOrStudiesError}
96+
)
9597
async def list_solvers(
9698
self,
9799
*,
@@ -134,7 +136,9 @@ async def list_solvers(
134136
)
135137
return solvers
136138

137-
@_exception_mapper({status.HTTP_404_NOT_FOUND: SolverOrStudyNotFoundError})
139+
@_exception_mapper(
140+
http_status_map={status.HTTP_404_NOT_FOUND: SolverOrStudyNotFoundError}
141+
)
138142
async def get_service(
139143
self, *, user_id: int, name: SolverKeyId, version: VersionStr, product_name: str
140144
) -> Solver:
@@ -163,7 +167,9 @@ async def get_service(
163167
solver: Solver = service.to_solver()
164168
return solver
165169

166-
@_exception_mapper({status.HTTP_404_NOT_FOUND: SolverOrStudyNotFoundError})
170+
@_exception_mapper(
171+
http_status_map={status.HTTP_404_NOT_FOUND: SolverOrStudyNotFoundError}
172+
)
167173
async def get_service_ports(
168174
self, *, user_id: int, name: SolverKeyId, version: VersionStr, product_name: str
169175
):

services/api-server/src/simcore_service_api_server/services_http/director_v2.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@ class TaskLogFileGet(BaseModel):
6060

6161
# API CLASS ---------------------------------------------
6262

63-
_exception_mapper = partial(service_exception_mapper, "Director V2")
63+
_exception_mapper = partial(service_exception_mapper, service_name="Director V2")
6464

6565

6666
class DirectorV2Api(BaseServiceClientApi):
67-
@_exception_mapper({})
67+
@_exception_mapper(http_status_map={})
6868
async def create_computation(
6969
self,
7070
*,
@@ -85,7 +85,7 @@ async def create_computation(
8585
task: ComputationTaskGet = ComputationTaskGet.model_validate_json(response.text)
8686
return task
8787

88-
@_exception_mapper({})
88+
@_exception_mapper(http_status_map={})
8989
async def start_computation(
9090
self,
9191
*,
@@ -115,7 +115,7 @@ async def start_computation(
115115
task: ComputationTaskGet = ComputationTaskGet.model_validate_json(response.text)
116116
return task
117117

118-
@_exception_mapper({status.HTTP_404_NOT_FOUND: JobNotFoundError})
118+
@_exception_mapper(http_status_map={status.HTTP_404_NOT_FOUND: JobNotFoundError})
119119
async def get_computation(
120120
self, *, project_id: UUID, user_id: PositiveInt
121121
) -> ComputationTaskGet:
@@ -129,7 +129,7 @@ async def get_computation(
129129
task: ComputationTaskGet = ComputationTaskGet.model_validate_json(response.text)
130130
return task
131131

132-
@_exception_mapper({status.HTTP_404_NOT_FOUND: JobNotFoundError})
132+
@_exception_mapper(http_status_map={status.HTTP_404_NOT_FOUND: JobNotFoundError})
133133
async def stop_computation(
134134
self, *, project_id: UUID, user_id: PositiveInt
135135
) -> ComputationTaskGet:
@@ -143,7 +143,7 @@ async def stop_computation(
143143
task: ComputationTaskGet = ComputationTaskGet.model_validate_json(response.text)
144144
return task
145145

146-
@_exception_mapper({status.HTTP_404_NOT_FOUND: JobNotFoundError})
146+
@_exception_mapper(http_status_map={status.HTTP_404_NOT_FOUND: JobNotFoundError})
147147
async def delete_computation(self, *, project_id: UUID, user_id: PositiveInt):
148148
response = await self.client.request(
149149
"DELETE",
@@ -155,7 +155,9 @@ async def delete_computation(self, *, project_id: UUID, user_id: PositiveInt):
155155
)
156156
response.raise_for_status()
157157

158-
@_exception_mapper({status.HTTP_404_NOT_FOUND: LogFileNotFoundError})
158+
@_exception_mapper(
159+
http_status_map={status.HTTP_404_NOT_FOUND: LogFileNotFoundError}
160+
)
159161
async def get_computation_logs(
160162
self, *, user_id: PositiveInt, project_id: UUID
161163
) -> JobLogsMap:

services/api-server/src/simcore_service_api_server/services_http/storage.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
_logger = logging.getLogger(__name__)
2626

27-
_exception_mapper = partial(service_exception_mapper, "Storage")
27+
_exception_mapper = partial(service_exception_mapper, service_name="Storage")
2828

2929
_FILE_ID_PATTERN = re.compile(r"^api\/(?P<file_id>[\w-]+)\/(?P<filename>.+)$")
3030
AccessRight = Literal["read", "write"]
@@ -54,7 +54,7 @@ class StorageApi(BaseServiceClientApi):
5454
#
5555
SIMCORE_S3_ID = 0
5656

57-
@_exception_mapper({})
57+
@_exception_mapper(http_status_map={})
5858
async def list_files(
5959
self,
6060
*,
@@ -81,7 +81,7 @@ async def list_files(
8181
)
8282
return files
8383

84-
@_exception_mapper({})
84+
@_exception_mapper(http_status_map={})
8585
async def search_owned_files(
8686
self,
8787
*,
@@ -119,7 +119,7 @@ async def search_owned_files(
119119
assert len(files) <= limit if limit else True # nosec
120120
return files
121121

122-
@_exception_mapper({})
122+
@_exception_mapper(http_status_map={})
123123
async def get_download_link(
124124
self, *, user_id: int, file_id: UUID, file_name: str
125125
) -> AnyUrl:
@@ -138,15 +138,15 @@ async def get_download_link(
138138
link: AnyUrl = presigned_link.link
139139
return link
140140

141-
@_exception_mapper({})
141+
@_exception_mapper(http_status_map={})
142142
async def delete_file(self, *, user_id: int, quoted_storage_file_id: str) -> None:
143143
response = await self.client.delete(
144144
f"/locations/{self.SIMCORE_S3_ID}/files/{quoted_storage_file_id}",
145145
params={"user_id": user_id},
146146
)
147147
response.raise_for_status()
148148

149-
@_exception_mapper({})
149+
@_exception_mapper(http_status_map={})
150150
async def get_upload_links(
151151
self, *, user_id: int, file_id: UUID, file_name: str
152152
) -> FileUploadSchema:
@@ -183,7 +183,7 @@ async def create_abort_upload_link(
183183
url = url.include_query_params(**query)
184184
return url
185185

186-
@_exception_mapper({})
186+
@_exception_mapper(http_status_map={})
187187
async def create_soft_link(
188188
self, *, user_id: int, target_s3_path: str, as_file_id: UUID
189189
) -> File:

services/api-server/src/simcore_service_api_server/services_http/webserver.py

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888

8989
_logger = logging.getLogger(__name__)
9090

91-
_exception_mapper = partial(service_exception_mapper, "Webserver")
91+
_exception_mapper = partial(service_exception_mapper, service_name="Webserver")
9292

9393
_JOB_STATUS_MAP = {
9494
status.HTTP_402_PAYMENT_REQUIRED: PaymentRequiredError,
@@ -243,7 +243,7 @@ async def _wait_for_long_running_task_results(self, lrt_response: httpx.Response
243243

244244
# PROFILE --------------------------------------------------
245245

246-
@_exception_mapper(_PROFILE_STATUS_MAP)
246+
@_exception_mapper(http_status_map=_PROFILE_STATUS_MAP)
247247
async def get_me(self) -> Profile:
248248
response = await self.client.get("/me", cookies=self.session_cookies)
249249
response.raise_for_status()
@@ -263,7 +263,7 @@ async def get_me(self) -> Profile:
263263
gravatar_id=got.gravatar_id,
264264
)
265265

266-
@_exception_mapper(_PROFILE_STATUS_MAP)
266+
@_exception_mapper(http_status_map=_PROFILE_STATUS_MAP)
267267
async def update_me(self, *, profile_update: ProfileUpdate) -> Profile:
268268

269269
update = WebProfileUpdate.model_construct(
@@ -283,7 +283,7 @@ async def update_me(self, *, profile_update: ProfileUpdate) -> Profile:
283283

284284
# PROJECTS -------------------------------------------------
285285

286-
@_exception_mapper({})
286+
@_exception_mapper(http_status_map={})
287287
async def create_project(
288288
self,
289289
project: ProjectCreateNew,
@@ -308,7 +308,7 @@ async def create_project(
308308
result = await self._wait_for_long_running_task_results(response)
309309
return ProjectGet.model_validate(result)
310310

311-
@_exception_mapper(_JOB_STATUS_MAP)
311+
@_exception_mapper(http_status_map=_JOB_STATUS_MAP)
312312
async def clone_project(
313313
self,
314314
*,
@@ -333,7 +333,7 @@ async def clone_project(
333333
result = await self._wait_for_long_running_task_results(response)
334334
return ProjectGet.model_validate(result)
335335

336-
@_exception_mapper(_JOB_STATUS_MAP)
336+
@_exception_mapper(http_status_map=_JOB_STATUS_MAP)
337337
async def get_project(self, *, project_id: UUID) -> ProjectGet:
338338
response = await self.client.get(
339339
f"/projects/{project_id}",
@@ -363,15 +363,17 @@ async def get_projects_page(self, *, limit: int, offset: int):
363363
show_hidden=False,
364364
)
365365

366-
@_exception_mapper(_JOB_STATUS_MAP)
366+
@_exception_mapper(http_status_map=_JOB_STATUS_MAP)
367367
async def delete_project(self, *, project_id: ProjectID) -> None:
368368
response = await self.client.delete(
369369
f"/projects/{project_id}",
370370
cookies=self.session_cookies,
371371
)
372372
response.raise_for_status()
373373

374-
@_exception_mapper({status.HTTP_404_NOT_FOUND: ProjectPortsNotFoundError})
374+
@_exception_mapper(
375+
http_status_map={status.HTTP_404_NOT_FOUND: ProjectPortsNotFoundError}
376+
)
375377
async def get_project_metadata_ports(
376378
self, *, project_id: ProjectID
377379
) -> list[StudyPort]:
@@ -389,7 +391,9 @@ async def get_project_metadata_ports(
389391
assert isinstance(data, list) # nosec
390392
return data
391393

392-
@_exception_mapper({status.HTTP_404_NOT_FOUND: ProjectMetadataNotFoundError})
394+
@_exception_mapper(
395+
http_status_map={status.HTTP_404_NOT_FOUND: ProjectMetadataNotFoundError}
396+
)
393397
async def get_project_metadata(
394398
self, *, project_id: ProjectID
395399
) -> ProjectMetadataGet:
@@ -402,7 +406,7 @@ async def get_project_metadata(
402406
assert data is not None # nosec
403407
return data
404408

405-
@_exception_mapper(_JOB_STATUS_MAP)
409+
@_exception_mapper(http_status_map=_JOB_STATUS_MAP)
406410
async def patch_project(self, *, project_id: UUID, patch_params: ProjectPatch):
407411
response = await self.client.patch(
408412
f"/projects/{project_id}",
@@ -411,7 +415,9 @@ async def patch_project(self, *, project_id: UUID, patch_params: ProjectPatch):
411415
)
412416
response.raise_for_status()
413417

414-
@_exception_mapper({status.HTTP_404_NOT_FOUND: ProjectMetadataNotFoundError})
418+
@_exception_mapper(
419+
http_status_map={status.HTTP_404_NOT_FOUND: ProjectMetadataNotFoundError}
420+
)
415421
async def update_project_metadata(
416422
self, *, project_id: ProjectID, metadata: dict[str, MetaValueType]
417423
) -> ProjectMetadataGet:
@@ -425,7 +431,9 @@ async def update_project_metadata(
425431
assert data is not None # nosec
426432
return data
427433

428-
@_exception_mapper({status.HTTP_404_NOT_FOUND: PricingUnitNotFoundError})
434+
@_exception_mapper(
435+
http_status_map={status.HTTP_404_NOT_FOUND: PricingUnitNotFoundError}
436+
)
429437
async def get_project_node_pricing_unit(
430438
self, *, project_id: UUID, node_id: UUID
431439
) -> PricingUnitGetLegacy:
@@ -439,7 +447,9 @@ async def get_project_node_pricing_unit(
439447
assert data is not None # nosec
440448
return data
441449

442-
@_exception_mapper({status.HTTP_404_NOT_FOUND: PricingUnitNotFoundError})
450+
@_exception_mapper(
451+
http_status_map={status.HTTP_404_NOT_FOUND: PricingUnitNotFoundError}
452+
)
443453
async def connect_pricing_unit_to_project_node(
444454
self,
445455
*,
@@ -455,7 +465,7 @@ async def connect_pricing_unit_to_project_node(
455465
response.raise_for_status()
456466

457467
@_exception_mapper(
458-
_JOB_STATUS_MAP
468+
http_status_map=_JOB_STATUS_MAP
459469
| {
460470
status.HTTP_409_CONFLICT: ProjectAlreadyStartedError,
461471
status.HTTP_406_NOT_ACCEPTABLE: ClusterNotFoundError,
@@ -477,7 +487,7 @@ async def start_project(
477487
)
478488
response.raise_for_status()
479489

480-
@_exception_mapper({})
490+
@_exception_mapper(http_status_map={})
481491
async def update_project_inputs(
482492
self,
483493
*,
@@ -498,7 +508,7 @@ async def update_project_inputs(
498508
assert data is not None # nosec
499509
return data
500510

501-
@_exception_mapper({})
511+
@_exception_mapper(http_status_map={})
502512
async def get_project_inputs(
503513
self, *, project_id: ProjectID
504514
) -> dict[NodeID, ProjectInputGet]:
@@ -517,7 +527,9 @@ async def get_project_inputs(
517527
assert data is not None # nosec
518528
return data
519529

520-
@_exception_mapper({status.HTTP_404_NOT_FOUND: SolverOutputNotFoundError})
530+
@_exception_mapper(
531+
http_status_map={status.HTTP_404_NOT_FOUND: SolverOutputNotFoundError}
532+
)
521533
async def get_project_outputs(
522534
self, *, project_id: ProjectID
523535
) -> dict[NodeID, dict[str, Any]]:
@@ -536,7 +548,7 @@ async def get_project_outputs(
536548
assert data is not None # nosec
537549
return data
538550

539-
@_exception_mapper({})
551+
@_exception_mapper(http_status_map={})
540552
async def update_node_outputs(
541553
self, *, project_id: UUID, node_id: UUID, new_node_outputs: NodeOutputs
542554
) -> None:
@@ -549,7 +561,7 @@ async def update_node_outputs(
549561

550562
# WALLETS -------------------------------------------------
551563

552-
@_exception_mapper(_WALLET_STATUS_MAP)
564+
@_exception_mapper(http_status_map=_WALLET_STATUS_MAP)
553565
async def get_default_wallet(self) -> WalletGetWithAvailableCreditsLegacy:
554566
response = await self.client.get(
555567
"/wallets/default",
@@ -564,7 +576,7 @@ async def get_default_wallet(self) -> WalletGetWithAvailableCreditsLegacy:
564576
assert data is not None # nosec
565577
return data
566578

567-
@_exception_mapper(_WALLET_STATUS_MAP)
579+
@_exception_mapper(http_status_map=_WALLET_STATUS_MAP)
568580
async def get_wallet(
569581
self, *, wallet_id: int
570582
) -> WalletGetWithAvailableCreditsLegacy:
@@ -581,7 +593,7 @@ async def get_wallet(
581593
assert data is not None # nosec
582594
return data
583595

584-
@_exception_mapper(_WALLET_STATUS_MAP)
596+
@_exception_mapper(http_status_map=_WALLET_STATUS_MAP)
585597
async def get_project_wallet(self, *, project_id: ProjectID) -> WalletGet:
586598
response = await self.client.get(
587599
f"/projects/{project_id}/wallet",
@@ -594,7 +606,9 @@ async def get_project_wallet(self, *, project_id: ProjectID) -> WalletGet:
594606

595607
# PRODUCTS -------------------------------------------------
596608

597-
@_exception_mapper({status.HTTP_404_NOT_FOUND: ProductPriceNotFoundError})
609+
@_exception_mapper(
610+
http_status_map={status.HTTP_404_NOT_FOUND: ProductPriceNotFoundError}
611+
)
598612
async def get_product_price(self) -> GetCreditPriceLegacy:
599613
response = await self.client.get(
600614
"/credits-price",
@@ -607,7 +621,9 @@ async def get_product_price(self) -> GetCreditPriceLegacy:
607621

608622
# SERVICES -------------------------------------------------
609623

610-
@_exception_mapper({status.HTTP_404_NOT_FOUND: PricingPlanNotFoundError})
624+
@_exception_mapper(
625+
http_status_map={status.HTTP_404_NOT_FOUND: PricingPlanNotFoundError}
626+
)
611627
async def get_service_pricing_plan(
612628
self, *, solver_key: SolverKeyId, version: VersionStr
613629
) -> ServicePricingPlanGet | None:

0 commit comments

Comments
 (0)