Skip to content

Commit

Permalink
fix(embeds): BI-5750 handle the INCORRECT_ENTRY_ID_FOR_EMBED error fr…
Browse files Browse the repository at this point in the history
…om US (#631)
  • Loading branch information
MCPN authored Oct 4, 2024
1 parent f7b2299 commit 733f9ec
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ def bi_error_to_error_data(bi_error: BIError, public_mode: bool, reason: Optiona
)


# noinspection PyDataclass
@attr.s
class DatasetAPIErrorHandler(AIOHTTPErrorHandler):
public_mode: bool = attr.ib(kw_only=True)
Expand Down
10 changes: 1 addition & 9 deletions lib/dl_api_lib/dl_api_lib/api_decorators.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
""" ... """

from __future__ import annotations

from functools import wraps
import json
import logging
Expand All @@ -12,7 +8,6 @@
)

import flask
from flask import current_app as capp
from flask import request
from flask_restx import Namespace
from marshmallow import Schema
Expand Down Expand Up @@ -141,12 +136,9 @@ def wrapper(*args, **kwargs): # type: ignore # TODO: fix
except Exception as err:
_ei = sys.exc_info()

exc_api_prefix = capp.config.get("ERR_CODE_API_PREFIX")
error_schema = RegularAPIErrorSchema(context=dict(api_prefix=exc_api_prefix))

# TODO FIX: Make fallback for exceptions during creating error response
bi_error = BIError.from_exception(err)
error_info = error_schema.dump(bi_error)
error_info = RegularAPIErrorSchema().dump(bi_error)
error_code = bi_error.http_code

if error_code is None:
Expand Down
30 changes: 12 additions & 18 deletions lib/dl_api_lib/dl_api_lib/error_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,44 +192,38 @@ class RegularAPIErrorSchema(Schema):
details = fields.Dict() # In future will be replaced with schemas for each exception
debug = fields.Dict()

def get_api_prefix(self) -> str:
# TODO CONSIDER: Warning in case of no api_prefix in context
return self.context.get("api_prefix") or DEFAULT_ERR_CODE_API_PREFIX

def serialize_error_code(self, data: BIError) -> str:
return ".".join(
itertools.chain(
(
GLOBAL_ERR_PREFIX,
self.get_api_prefix(),
),
(GLOBAL_ERR_PREFIX, DEFAULT_ERR_CODE_API_PREFIX),
data.application_code_stack,
)
)


class PublicAPIErrorSchema(RegularAPIErrorSchema):
class Meta(RegularAPIErrorSchema.Meta):
PUBLIC_FORWARDED_ERROR_CODES: ClassVar[frozenset[tuple[str, ...]]] = frozenset(
(tuple(common_exc.MaterializationNotFinished.err_code),)
PUBLIC_FORWARDED_ERROR_CODES: ClassVar[frozenset[tuple[str, ...]]] = frozenset(
(
tuple(common_exc.MaterializationNotFinished.err_code),
tuple(common_exc.USIncorrectEntryIdForEmbed.err_code),
)
PUBLIC_DEFAULT_MESSAGE = "Something went wrong"
PUBLIC_DEFAULT_ERR_CODE = "ERR.UNKNOWN"
)
PUBLIC_DEFAULT_MESSAGE = "Something went wrong"
PUBLIC_DEFAULT_ERR_CODE = "ERR.UNKNOWN"

message = fields.Method(serialize="serialize_message") # type: ignore # TODO: fix

debug = fields.Constant({}) # type: ignore # TODO: fix
details = fields.Constant({}) # type: ignore # TODO: fix

def serialize_error_code(self, data: BIError) -> str:
if tuple(data.application_code_stack) in self.Meta.PUBLIC_FORWARDED_ERROR_CODES:
if data.application_code_stack in self.PUBLIC_FORWARDED_ERROR_CODES:
return super().serialize_error_code(data)

return self.Meta.PUBLIC_DEFAULT_ERR_CODE
return self.PUBLIC_DEFAULT_ERR_CODE

def serialize_message(self, data: BIError) -> str:
if tuple(data.application_code_stack) in self.Meta.PUBLIC_FORWARDED_ERROR_CODES:
if data.application_code_stack in self.PUBLIC_FORWARDED_ERROR_CODES:
return data.message

else:
return self.Meta.PUBLIC_DEFAULT_MESSAGE
return self.PUBLIC_DEFAULT_MESSAGE
51 changes: 20 additions & 31 deletions lib/dl_api_lib/dl_api_lib_tests/unit/test_error_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,19 +90,12 @@ def test_regular_schema():
)

# Ensure all fields passed to output
assert (
{"code": "ERR.SOME_API.A.B", "debug": dict(a="b"), "details": dict(a="b"), "message": "Some message"}
) == RegularAPIErrorSchema(context=dict(api_prefix="SOME_API")).dump(bi_error)

# Ensure default prefix
assert (
{
"code": f"{GLOBAL_ERR_PREFIX}.{DEFAULT_ERR_CODE_API_PREFIX}.A.B",
"debug": dict(a="b"),
"details": dict(a="b"),
"message": "Some message",
}
) == RegularAPIErrorSchema().dump(bi_error)
assert RegularAPIErrorSchema().dump(bi_error) == {
"code": "ERR.DS_API.A.B",
"debug": dict(a="b"),
"details": dict(a="b"),
"message": "Some message",
}


def test_public_schema():
Expand All @@ -114,20 +107,18 @@ def test_public_schema():
details=dict(private_code="Some private value"),
)

assert (
{
"code": PublicAPIErrorSchema.Meta.PUBLIC_DEFAULT_ERR_CODE,
"debug": {},
"details": {},
"message": PublicAPIErrorSchema.Meta.PUBLIC_DEFAULT_MESSAGE,
}
) == PublicAPIErrorSchema().dump(bi_error)
assert PublicAPIErrorSchema().dump(bi_error) == {
"code": PublicAPIErrorSchema.PUBLIC_DEFAULT_ERR_CODE,
"debug": {},
"details": {},
"message": PublicAPIErrorSchema.PUBLIC_DEFAULT_MESSAGE,
}

assert (
len(PublicAPIErrorSchema.Meta.PUBLIC_FORWARDED_ERROR_CODES) > 0
len(PublicAPIErrorSchema.PUBLIC_FORWARDED_ERROR_CODES) == 2
), "Can not perform full public schema test without public whitelisted error codes"

for err_code_stack in PublicAPIErrorSchema.Meta.PUBLIC_FORWARDED_ERROR_CODES:
for err_code_stack in PublicAPIErrorSchema.PUBLIC_FORWARDED_ERROR_CODES:
public_whitelisted_bi_error = BIError(
message="Non user-private message",
http_code=None,
Expand All @@ -136,11 +127,9 @@ def test_public_schema():
details=dict(private_code="Some private value"),
)
# Ensure that message and error code are passed to output for whitelisted errors
assert (
{
"code": ".".join([GLOBAL_ERR_PREFIX, DEFAULT_ERR_CODE_API_PREFIX] + list(err_code_stack)),
"debug": {},
"details": {},
"message": public_whitelisted_bi_error.message,
}
) == PublicAPIErrorSchema().dump(public_whitelisted_bi_error)
assert PublicAPIErrorSchema().dump(public_whitelisted_bi_error) == {
"code": ".".join([GLOBAL_ERR_PREFIX, DEFAULT_ERR_CODE_API_PREFIX] + list(err_code_stack)),
"debug": {},
"details": {},
"message": public_whitelisted_bi_error.message,
}
4 changes: 4 additions & 0 deletions lib/dl_core/dl_core/exc.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,10 @@ class USAlreadyExistsException(USBadRequestException):
err_code = USBadRequestException.err_code + ["ALREADY_EXISTS"]


class USIncorrectEntryIdForEmbed(USBadRequestException):
err_code = USBadRequestException.err_code + ["INCORRECT_ENTRY_ID_FOR_EMBED"]


class USIncorrectTenantIdException(USReqException):
@property
def message(self) -> str:
Expand Down
1 change: 1 addition & 0 deletions lib/dl_core/dl_core/united_storage_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ def json(self) -> dict:
(403, re.compile("Workbook isolation interruption"), exc.USWorkbookIsolationInterruptionException),
(404, None, exc.USObjectNotFoundException),
(409, re.compile("The entry already exists"), exc.USAlreadyExistsException),
(409, re.compile("Incorrect entryId for embed"), exc.USIncorrectEntryIdForEmbed),
(409, None, exc.USIncorrectTenantIdException),
(423, None, exc.USLockUnacquiredException),
(451, None, exc.USReadOnlyModeEnabledException),
Expand Down

0 comments on commit 733f9ec

Please sign in to comment.