Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions newsfragments/3090.change.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add ``QuotaExceededError``, ``LicenseCheckFailedError``, and ``AuthorizationFailedError`` for documented VuMark Generation API result codes.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ optional-dependencies.dev = [
"ty==0.0.65",
"types-requests==2.33.0.20260712",
"vulture==2.16",
"vws-python-mock==2026.8.4.1",
"vws-python-mock==2026.8.4.2",
"vws-test-fixtures==2023.3.5",
"yamlfix==1.19.1",
"zizmor==1.28.0",
Expand Down
3 changes: 3 additions & 0 deletions spelling_private_dict.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
AuthenticationFailure
AuthorizationFailed
BadImage
ConnectionErrorPossiblyImageTooLarge
DateRangeError
Falsy
ImageTooLarge
InactiveProject
JSONDecodeError
LicenseCheckFailed
MatchProcessing
MaxNumResultsOutOfRange
MetadataTooLarge
Expand All @@ -14,6 +16,7 @@ OopsAnErrorOccurredPossiblyBadNameError
ProjectHasNoAPIAccess
ProjectInactive
ProjectSuspended
QuotaExceeded
RequestQuotaReached
RequestTimeTooSkewed
TargetNameExist
Expand Down
6 changes: 6 additions & 0 deletions src/vws/async_vumark_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ async def generate_vumark_instance(
Raises:
~vws.exceptions.vws_exceptions.AuthenticationFailureError: The
secret key is not correct.
~vws.exceptions.vws_exceptions.AuthorizationFailedError: There was
a general authentication problem.
~vws.exceptions.vws_exceptions.FailError: There was an error with
the request. For example, the given access key does not match a
known database.
Expand All @@ -96,6 +98,10 @@ async def generate_vumark_instance(
instance ID is invalid. For example, it may be empty.
~vws.exceptions.vws_exceptions.InvalidTargetTypeError: The target
is not a VuMark template target.
~vws.exceptions.vws_exceptions.LicenseCheckFailedError: The
license state and/or type does not allow this request.
~vws.exceptions.vws_exceptions.QuotaExceededError: No more
instances can be created for the associated license.
~vws.exceptions.vws_exceptions.RequestTimeTooSkewedError: There is
an error with the time sent to Vuforia.
~vws.exceptions.vws_exceptions.TargetStatusNotSuccessError: The
Expand Down
24 changes: 24 additions & 0 deletions src/vws/exceptions/vws_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,31 @@ class InvalidTargetTypeError(VWSError):
"""


@beartype
class QuotaExceededError(VWSError):
"""Exception raised when Vuforia returns a response with a result code
``QuotaExceeded``.
"""


@beartype
class LicenseCheckFailedError(VWSError):
"""Exception raised when Vuforia returns a response with a result code
``LicenseCheckFailed``.
"""


@beartype
class AuthorizationFailedError(VWSError):
"""Exception raised when Vuforia returns a response with a result code
``AuthorizationFailed``.
"""


VWSError.register_exceptions_by_result_code(
exceptions_by_result_code={
"AuthenticationFailure": AuthenticationFailureError,
"AuthorizationFailed": AuthorizationFailedError,
"BadImage": BadImageError,
"BadRequest": BadRequestError,
"DateRangeError": DateRangeError,
Expand All @@ -217,10 +239,12 @@ class InvalidTargetTypeError(VWSError):
"InvalidAcceptHeader": InvalidAcceptHeaderError,
"InvalidInstanceId": InvalidInstanceIdError,
"InvalidTargetType": InvalidTargetTypeError,
"LicenseCheckFailed": LicenseCheckFailedError,
"MetadataTooLarge": MetadataTooLargeError,
"ProjectHasNoAPIAccess": ProjectHasNoAPIAccessError,
"ProjectInactive": ProjectInactiveError,
"ProjectSuspended": ProjectSuspendedError,
"QuotaExceeded": QuotaExceededError,
"RequestQuotaReached": RequestQuotaReachedError,
"RequestTimeTooSkewed": RequestTimeTooSkewedError,
"TargetNameExist": TargetNameExistError,
Expand Down
6 changes: 6 additions & 0 deletions src/vws/vumark_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ def generate_vumark_instance(
Raises:
~vws.exceptions.vws_exceptions.AuthenticationFailureError: The
secret key is not correct.
~vws.exceptions.vws_exceptions.AuthorizationFailedError: There was
a general authentication problem.
~vws.exceptions.vws_exceptions.FailError: There was an error with
the request. For example, the given access key does not match a
known database.
Expand All @@ -80,6 +82,10 @@ def generate_vumark_instance(
instance ID is invalid. For example, it may be empty.
~vws.exceptions.vws_exceptions.InvalidTargetTypeError: The target
is not a VuMark template target.
~vws.exceptions.vws_exceptions.LicenseCheckFailedError: The
license state and/or type does not allow this request.
~vws.exceptions.vws_exceptions.QuotaExceededError: No more
instances can be created for the associated license.
~vws.exceptions.vws_exceptions.RequestTimeTooSkewedError: There is
an error with the time sent to Vuforia.
~vws.exceptions.vws_exceptions.TargetStatusNotSuccessError: The
Expand Down
50 changes: 49 additions & 1 deletion tests/test_async_vws_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from http import HTTPStatus

import pytest
from mock_vws import MockVWS
from mock_vws import MockVWS, VuMarkGenerationFailure
from mock_vws.database import CloudDatabase
from mock_vws.states import States

Expand All @@ -16,14 +16,17 @@
)
from vws.exceptions.vws_exceptions import (
AuthenticationFailureError,
AuthorizationFailedError,
BadImageError,
FailError,
ImageTooLargeError,
InvalidInstanceIdError,
LicenseCheckFailedError,
MetadataTooLargeError,
ProjectHasNoAPIAccessError,
ProjectInactiveError,
ProjectSuspendedError,
QuotaExceededError,
RequestQuotaReachedError,
TargetNameExistError,
TargetQuotaReachedError,
Expand Down Expand Up @@ -377,3 +380,48 @@ async def test_invalid_instance_id(
)

assert exc.value.response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY


@pytest.mark.asyncio
@pytest.mark.parametrize(
argnames=("failure", "exception_type", "status_code"),
argvalues=[
(
VuMarkGenerationFailure.QUOTA_EXCEEDED,
QuotaExceededError,
HTTPStatus.FORBIDDEN,
),
(
VuMarkGenerationFailure.LICENSE_CHECK_FAILED,
LicenseCheckFailedError,
HTTPStatus.FORBIDDEN,
),
(
VuMarkGenerationFailure.AUTHORIZATION_FAILED,
AuthorizationFailedError,
HTTPStatus.UNAUTHORIZED,
),
],
)
async def test_documented_vumark_error_codes(
*,
failure: VuMarkGenerationFailure,
exception_type: type[VWSError],
status_code: HTTPStatus,
) -> None:
"""Documented VuMark failures raise matching exceptions."""
with MockVWS(vumark_generation_failure=failure):
vumark_service = AsyncVuMarkService(
server_access_key=uuid.uuid4().hex,
server_secret_key=uuid.uuid4().hex,
)
with pytest.raises(expected_exception=exception_type) as exc:
await vumark_service.generate_vumark_instance(
target_id="exampletargetid",
instance_id="example_instance_id",
accept=VuMarkAccept.PNG,
)
await vumark_service.aclose()

assert exc.value.response.status_code == status_code
assert failure.value in exc.value.response.text
52 changes: 51 additions & 1 deletion tests/test_vws_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import pytest
from freezegun import freeze_time
from mock_vws import MockVWS
from mock_vws import MockVWS, VuMarkGenerationFailure
from mock_vws.database import CloudDatabase
from mock_vws.states import States

Expand All @@ -17,6 +17,7 @@
)
from vws.exceptions.vws_exceptions import (
AuthenticationFailureError,
AuthorizationFailedError,
BadImageError,
BadRequestError,
DateRangeError,
Expand All @@ -25,10 +26,12 @@
InvalidAcceptHeaderError,
InvalidInstanceIdError,
InvalidTargetTypeError,
LicenseCheckFailedError,
MetadataTooLargeError,
ProjectHasNoAPIAccessError,
ProjectInactiveError,
ProjectSuspendedError,
QuotaExceededError,
RequestQuotaReachedError,
RequestTimeTooSkewedError,
TargetNameExistError,
Expand Down Expand Up @@ -412,6 +415,7 @@ def test_vwsexception_inheritance() -> None:
"""VWS-related exceptions should inherit from VWSException."""
subclasses = [
AuthenticationFailureError,
AuthorizationFailedError,
BadImageError,
BadRequestError,
DateRangeError,
Expand All @@ -420,10 +424,12 @@ def test_vwsexception_inheritance() -> None:
InvalidAcceptHeaderError,
InvalidInstanceIdError,
InvalidTargetTypeError,
LicenseCheckFailedError,
MetadataTooLargeError,
ProjectInactiveError,
ProjectHasNoAPIAccessError,
ProjectSuspendedError,
QuotaExceededError,
RequestQuotaReachedError,
RequestTimeTooSkewedError,
TargetNameExistError,
Expand Down Expand Up @@ -492,6 +498,50 @@ def test_invalid_target_type(
assert exc.value.response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY


@pytest.mark.parametrize(
argnames=("failure", "exception_type", "status_code"),
argvalues=[
(
VuMarkGenerationFailure.QUOTA_EXCEEDED,
QuotaExceededError,
HTTPStatus.FORBIDDEN,
),
(
VuMarkGenerationFailure.LICENSE_CHECK_FAILED,
LicenseCheckFailedError,
HTTPStatus.FORBIDDEN,
),
(
VuMarkGenerationFailure.AUTHORIZATION_FAILED,
AuthorizationFailedError,
HTTPStatus.UNAUTHORIZED,
),
],
)
def test_documented_vumark_error_codes(
*,
failure: VuMarkGenerationFailure,
exception_type: type[VWSError],
status_code: HTTPStatus,
) -> None:
"""Documented VuMark failures raise matching exceptions."""
with MockVWS(vumark_generation_failure=failure):
vumark_service = VuMarkService(
server_access_key=uuid.uuid4().hex,
server_secret_key=uuid.uuid4().hex,
)

with pytest.raises(expected_exception=exception_type) as exc:
vumark_service.generate_vumark_instance(
target_id="exampletargetid",
instance_id="example_instance_id",
accept=VuMarkAccept.PNG,
)

assert exc.value.response.status_code == status_code
assert failure.value in exc.value.response.text


def test_base_exception(
*,
vws_client: VWS,
Expand Down
Loading