From ba1d67e74a22c0b4d4943ccb08025a32bd05c110 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Wed, 25 Feb 2026 10:31:33 +0000 Subject: [PATCH] Add VWSError result code factory --- src/vws/async_vumark_service.py | 33 ++++--------------- src/vws/async_vws.py | 47 ++++----------------------- src/vws/exceptions/base_exceptions.py | 25 ++++++++++++++ src/vws/exceptions/vws_exceptions.py | 26 +++++++++++++++ src/vws/vumark_service.py | 33 ++++--------------- src/vws/vws.py | 47 ++++----------------------- tests/test_vws_exceptions.py | 22 +++++++++++++ 7 files changed, 97 insertions(+), 136 deletions(-) diff --git a/src/vws/async_vumark_service.py b/src/vws/async_vumark_service.py index c1e189eeb..a104f49c0 100644 --- a/src/vws/async_vumark_service.py +++ b/src/vws/async_vumark_service.py @@ -7,20 +7,9 @@ from beartype import BeartypeConf, beartype from vws._async_vws_request import async_target_api_request +from vws.exceptions.base_exceptions import VWSError from vws.exceptions.custom_exceptions import ServerError -from vws.exceptions.vws_exceptions import ( - AuthenticationFailureError, - BadRequestError, - DateRangeError, - FailError, - InvalidAcceptHeaderError, - InvalidInstanceIdError, - InvalidTargetTypeError, - RequestTimeTooSkewedError, - TargetStatusNotSuccessError, - TooManyRequestsError, - UnknownTargetError, -) +from vws.exceptions.vws_exceptions import TooManyRequestsError from vws.transports import AsyncHTTPXTransport, AsyncTransport from vws.vumark_accept import VuMarkAccept @@ -154,17 +143,7 @@ async def generate_vumark_instance( result_code = json.loads(s=response.text)["result_code"] - exception = { - "AuthenticationFailure": (AuthenticationFailureError), - "BadRequest": BadRequestError, - "DateRangeError": DateRangeError, - "Fail": FailError, - "InvalidAcceptHeader": InvalidAcceptHeaderError, - "InvalidInstanceId": InvalidInstanceIdError, - "InvalidTargetType": InvalidTargetTypeError, - "RequestTimeTooSkewed": RequestTimeTooSkewedError, - "TargetStatusNotSuccess": (TargetStatusNotSuccessError), - "UnknownTarget": UnknownTargetError, - }[result_code] - - raise exception(response=response) + raise VWSError.from_result_code( + result_code=result_code, + response=response, + ) diff --git a/src/vws/async_vws.py b/src/vws/async_vws.py index 55c2aa1dd..feba724de 100644 --- a/src/vws/async_vws.py +++ b/src/vws/async_vws.py @@ -11,30 +11,12 @@ from vws._async_vws_request import async_target_api_request from vws._image_utils import ImageType as _ImageType from vws._image_utils import get_image_data as _get_image_data +from vws.exceptions.base_exceptions import VWSError from vws.exceptions.custom_exceptions import ( ServerError, TargetProcessingTimeoutError, ) -from vws.exceptions.vws_exceptions import ( - AuthenticationFailureError, - BadImageError, - BadRequestError, - DateRangeError, - FailError, - ImageTooLargeError, - MetadataTooLargeError, - ProjectHasNoAPIAccessError, - ProjectInactiveError, - ProjectSuspendedError, - RequestQuotaReachedError, - RequestTimeTooSkewedError, - TargetNameExistError, - TargetQuotaReachedError, - TargetStatusNotSuccessError, - TargetStatusProcessingError, - TooManyRequestsError, - UnknownTargetError, -) +from vws.exceptions.vws_exceptions import TooManyRequestsError from vws.reports import ( DatabaseSummaryReport, TargetStatusAndRecord, @@ -158,27 +140,10 @@ async def make_request( if result_code == expected_result_code: return response - exception = { - "AuthenticationFailure": AuthenticationFailureError, - "BadImage": BadImageError, - "BadRequest": BadRequestError, - "DateRangeError": DateRangeError, - "Fail": FailError, - "ImageTooLarge": ImageTooLargeError, - "MetadataTooLarge": MetadataTooLargeError, - "ProjectHasNoAPIAccess": ProjectHasNoAPIAccessError, - "ProjectInactive": ProjectInactiveError, - "ProjectSuspended": ProjectSuspendedError, - "RequestQuotaReached": RequestQuotaReachedError, - "RequestTimeTooSkewed": RequestTimeTooSkewedError, - "TargetNameExist": TargetNameExistError, - "TargetQuotaReached": TargetQuotaReachedError, - "TargetStatusNotSuccess": TargetStatusNotSuccessError, - "TargetStatusProcessing": TargetStatusProcessingError, - "UnknownTarget": UnknownTargetError, - }[result_code] - - raise exception(response=response) + raise VWSError.from_result_code( + result_code=result_code, + response=response, + ) async def add_target( self, diff --git a/src/vws/exceptions/base_exceptions.py b/src/vws/exceptions/base_exceptions.py index fa031838a..4b8727e79 100644 --- a/src/vws/exceptions/base_exceptions.py +++ b/src/vws/exceptions/base_exceptions.py @@ -4,6 +4,9 @@ Cloud Recognition Web API. """ +from collections.abc import Mapping +from typing import ClassVar + from beartype import beartype from vws.response import Response @@ -35,6 +38,8 @@ class VWSError(Exception): https://developer.vuforia.com/library/web-api/cloud-targets-web-services-api#result-codes. """ + _exceptions_by_result_code: ClassVar[dict[str, type["VWSError"]]] = {} + def __init__(self, response: Response) -> None: """ Args: @@ -43,6 +48,26 @@ def __init__(self, response: Response) -> None: super().__init__() self._response = response + @classmethod + def register_exceptions_by_result_code( + cls, + *, + exceptions_by_result_code: Mapping[str, type["VWSError"]], + ) -> None: + """Register ``result_code`` to exception mappings.""" + cls._exceptions_by_result_code.update(exceptions_by_result_code) + + @classmethod + def from_result_code( + cls, + *, + result_code: str, + response: Response, + ) -> "VWSError": + """Create the mapped exception for a VWS ``result_code``.""" + exception_type = cls._exceptions_by_result_code[result_code] + return exception_type(response=response) + @property def response(self) -> Response: """The response returned by Vuforia which included this error.""" diff --git a/src/vws/exceptions/vws_exceptions.py b/src/vws/exceptions/vws_exceptions.py index 865d2372c..de09cdeaa 100644 --- a/src/vws/exceptions/vws_exceptions.py +++ b/src/vws/exceptions/vws_exceptions.py @@ -202,3 +202,29 @@ class InvalidTargetTypeError(VWSError): """Exception raised when Vuforia returns a response with a result code ``InvalidTargetType``. """ + + +VWSError.register_exceptions_by_result_code( + exceptions_by_result_code={ + "AuthenticationFailure": AuthenticationFailureError, + "BadImage": BadImageError, + "BadRequest": BadRequestError, + "DateRangeError": DateRangeError, + "Fail": FailError, + "ImageTooLarge": ImageTooLargeError, + "InvalidAcceptHeader": InvalidAcceptHeaderError, + "InvalidInstanceId": InvalidInstanceIdError, + "InvalidTargetType": InvalidTargetTypeError, + "MetadataTooLarge": MetadataTooLargeError, + "ProjectHasNoAPIAccess": ProjectHasNoAPIAccessError, + "ProjectInactive": ProjectInactiveError, + "ProjectSuspended": ProjectSuspendedError, + "RequestQuotaReached": RequestQuotaReachedError, + "RequestTimeTooSkewed": RequestTimeTooSkewedError, + "TargetNameExist": TargetNameExistError, + "TargetQuotaReached": TargetQuotaReachedError, + "TargetStatusNotSuccess": TargetStatusNotSuccessError, + "TargetStatusProcessing": TargetStatusProcessingError, + "UnknownTarget": UnknownTargetError, + }, +) diff --git a/src/vws/vumark_service.py b/src/vws/vumark_service.py index 47d68d942..f4b04152f 100644 --- a/src/vws/vumark_service.py +++ b/src/vws/vumark_service.py @@ -6,20 +6,9 @@ from beartype import BeartypeConf, beartype from vws._vws_request import target_api_request +from vws.exceptions.base_exceptions import VWSError from vws.exceptions.custom_exceptions import ServerError -from vws.exceptions.vws_exceptions import ( - AuthenticationFailureError, - BadRequestError, - DateRangeError, - FailError, - InvalidAcceptHeaderError, - InvalidInstanceIdError, - InvalidTargetTypeError, - RequestTimeTooSkewedError, - TargetStatusNotSuccessError, - TooManyRequestsError, - UnknownTargetError, -) +from vws.exceptions.vws_exceptions import TooManyRequestsError from vws.transports import RequestsTransport, Transport from vws.vumark_accept import VuMarkAccept @@ -135,17 +124,7 @@ def generate_vumark_instance( result_code = json.loads(s=response.text)["result_code"] - exception = { - "AuthenticationFailure": AuthenticationFailureError, - "BadRequest": BadRequestError, - "DateRangeError": DateRangeError, - "Fail": FailError, - "InvalidAcceptHeader": InvalidAcceptHeaderError, - "InvalidInstanceId": InvalidInstanceIdError, - "InvalidTargetType": InvalidTargetTypeError, - "RequestTimeTooSkewed": RequestTimeTooSkewedError, - "TargetStatusNotSuccess": TargetStatusNotSuccessError, - "UnknownTarget": UnknownTargetError, - }[result_code] - - raise exception(response=response) + raise VWSError.from_result_code( + result_code=result_code, + response=response, + ) diff --git a/src/vws/vws.py b/src/vws/vws.py index c93a9da8b..7eda102fe 100644 --- a/src/vws/vws.py +++ b/src/vws/vws.py @@ -10,30 +10,12 @@ from vws._image_utils import ImageType as _ImageType from vws._image_utils import get_image_data as _get_image_data from vws._vws_request import target_api_request +from vws.exceptions.base_exceptions import VWSError from vws.exceptions.custom_exceptions import ( ServerError, TargetProcessingTimeoutError, ) -from vws.exceptions.vws_exceptions import ( - AuthenticationFailureError, - BadImageError, - BadRequestError, - DateRangeError, - FailError, - ImageTooLargeError, - MetadataTooLargeError, - ProjectHasNoAPIAccessError, - ProjectInactiveError, - ProjectSuspendedError, - RequestQuotaReachedError, - RequestTimeTooSkewedError, - TargetNameExistError, - TargetQuotaReachedError, - TargetStatusNotSuccessError, - TargetStatusProcessingError, - TooManyRequestsError, - UnknownTargetError, -) +from vws.exceptions.vws_exceptions import TooManyRequestsError from vws.reports import ( DatabaseSummaryReport, TargetStatusAndRecord, @@ -143,27 +125,10 @@ def make_request( if result_code == expected_result_code: return response - exception = { - "AuthenticationFailure": AuthenticationFailureError, - "BadImage": BadImageError, - "BadRequest": BadRequestError, - "DateRangeError": DateRangeError, - "Fail": FailError, - "ImageTooLarge": ImageTooLargeError, - "MetadataTooLarge": MetadataTooLargeError, - "ProjectHasNoAPIAccess": ProjectHasNoAPIAccessError, - "ProjectInactive": ProjectInactiveError, - "ProjectSuspended": ProjectSuspendedError, - "RequestQuotaReached": RequestQuotaReachedError, - "RequestTimeTooSkewed": RequestTimeTooSkewedError, - "TargetNameExist": TargetNameExistError, - "TargetQuotaReached": TargetQuotaReachedError, - "TargetStatusNotSuccess": TargetStatusNotSuccessError, - "TargetStatusProcessing": TargetStatusProcessingError, - "UnknownTarget": UnknownTargetError, - }[result_code] - - raise exception(response=response) + raise VWSError.from_result_code( + result_code=result_code, + response=response, + ) def add_target( self, diff --git a/tests/test_vws_exceptions.py b/tests/test_vws_exceptions.py index 617016257..798d15f71 100644 --- a/tests/test_vws_exceptions.py +++ b/tests/test_vws_exceptions.py @@ -37,6 +37,7 @@ TargetStatusProcessingError, UnknownTargetError, ) +from vws.response import Response from vws.vumark_accept import VuMarkAccept @@ -451,3 +452,24 @@ def test_base_exception( active_flag=True, application_metadata=None, ) + + +def test_vwserror_from_result_code() -> None: + """``VWSError.from_result_code`` returns the mapped exception.""" + response = Response( + text='{"result_code":"UnknownTarget"}', + url="https://example.com/targets/123", + status_code=HTTPStatus.NOT_FOUND, + headers={}, + request_body=None, + tell_position=0, + content=b"", + ) + + exception = VWSError.from_result_code( + result_code="UnknownTarget", + response=response, + ) + + assert isinstance(exception, UnknownTargetError) + assert exception.response is response