Skip to content

Commit 58c5431

Browse files
committed
Handle documented VuMark generation failures
1 parent e166888 commit 58c5431

8 files changed

Lines changed: 140 additions & 3 deletions

File tree

newsfragments/3090.change.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add ``QuotaExceededError``, ``LicenseCheckFailedError``, and ``AuthorizationFailedError`` for documented VuMark Generation API result codes.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ optional-dependencies.dev = [
8484
"ty==0.0.65",
8585
"types-requests==2.33.0.20260712",
8686
"vulture==2.16",
87-
"vws-python-mock==2026.8.4.1",
87+
"vws-python-mock==2026.8.4.2",
8888
"vws-test-fixtures==2023.3.5",
8989
"yamlfix==1.19.1",
9090
"zizmor==1.28.0",

spelling_private_dict.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
AuthenticationFailure
2+
AuthorizationFailed
23
BadImage
34
ConnectionErrorPossiblyImageTooLarge
45
DateRangeError
56
Falsy
67
ImageTooLarge
78
InactiveProject
89
JSONDecodeError
10+
LicenseCheckFailed
911
MatchProcessing
1012
MaxNumResultsOutOfRange
1113
MetadataTooLarge
@@ -14,6 +16,7 @@ OopsAnErrorOccurredPossiblyBadNameError
1416
ProjectHasNoAPIAccess
1517
ProjectInactive
1618
ProjectSuspended
19+
QuotaExceeded
1720
RequestQuotaReached
1821
RequestTimeTooSkewed
1922
TargetNameExist

src/vws/async_vumark_service.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ async def generate_vumark_instance(
8787
Raises:
8888
~vws.exceptions.vws_exceptions.AuthenticationFailureError: The
8989
secret key is not correct.
90+
~vws.exceptions.vws_exceptions.AuthorizationFailedError: There was
91+
a general authentication problem.
9092
~vws.exceptions.vws_exceptions.FailError: There was an error with
9193
the request. For example, the given access key does not match a
9294
known database.
@@ -96,6 +98,10 @@ async def generate_vumark_instance(
9698
instance ID is invalid. For example, it may be empty.
9799
~vws.exceptions.vws_exceptions.InvalidTargetTypeError: The target
98100
is not a VuMark template target.
101+
~vws.exceptions.vws_exceptions.LicenseCheckFailedError: The
102+
license state and/or type does not allow this request.
103+
~vws.exceptions.vws_exceptions.QuotaExceededError: No more
104+
instances can be created for the associated license.
99105
~vws.exceptions.vws_exceptions.RequestTimeTooSkewedError: There is
100106
an error with the time sent to Vuforia.
101107
~vws.exceptions.vws_exceptions.TargetStatusNotSuccessError: The

src/vws/exceptions/vws_exceptions.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,31 @@ class InvalidTargetTypeError(VWSError):
206206
"""
207207

208208

209+
@beartype
210+
class QuotaExceededError(VWSError):
211+
"""Exception raised when Vuforia returns a response with a result code
212+
``QuotaExceeded``.
213+
"""
214+
215+
216+
@beartype
217+
class LicenseCheckFailedError(VWSError):
218+
"""Exception raised when Vuforia returns a response with a result code
219+
``LicenseCheckFailed``.
220+
"""
221+
222+
223+
@beartype
224+
class AuthorizationFailedError(VWSError):
225+
"""Exception raised when Vuforia returns a response with a result code
226+
``AuthorizationFailed``.
227+
"""
228+
229+
209230
VWSError.register_exceptions_by_result_code(
210231
exceptions_by_result_code={
211232
"AuthenticationFailure": AuthenticationFailureError,
233+
"AuthorizationFailed": AuthorizationFailedError,
212234
"BadImage": BadImageError,
213235
"BadRequest": BadRequestError,
214236
"DateRangeError": DateRangeError,
@@ -217,10 +239,12 @@ class InvalidTargetTypeError(VWSError):
217239
"InvalidAcceptHeader": InvalidAcceptHeaderError,
218240
"InvalidInstanceId": InvalidInstanceIdError,
219241
"InvalidTargetType": InvalidTargetTypeError,
242+
"LicenseCheckFailed": LicenseCheckFailedError,
220243
"MetadataTooLarge": MetadataTooLargeError,
221244
"ProjectHasNoAPIAccess": ProjectHasNoAPIAccessError,
222245
"ProjectInactive": ProjectInactiveError,
223246
"ProjectSuspended": ProjectSuspendedError,
247+
"QuotaExceeded": QuotaExceededError,
224248
"RequestQuotaReached": RequestQuotaReachedError,
225249
"RequestTimeTooSkewed": RequestTimeTooSkewedError,
226250
"TargetNameExist": TargetNameExistError,

src/vws/vumark_service.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ def generate_vumark_instance(
7171
Raises:
7272
~vws.exceptions.vws_exceptions.AuthenticationFailureError: The
7373
secret key is not correct.
74+
~vws.exceptions.vws_exceptions.AuthorizationFailedError: There was
75+
a general authentication problem.
7476
~vws.exceptions.vws_exceptions.FailError: There was an error with
7577
the request. For example, the given access key does not match a
7678
known database.
@@ -80,6 +82,10 @@ def generate_vumark_instance(
8082
instance ID is invalid. For example, it may be empty.
8183
~vws.exceptions.vws_exceptions.InvalidTargetTypeError: The target
8284
is not a VuMark template target.
85+
~vws.exceptions.vws_exceptions.LicenseCheckFailedError: The
86+
license state and/or type does not allow this request.
87+
~vws.exceptions.vws_exceptions.QuotaExceededError: No more
88+
instances can be created for the associated license.
8389
~vws.exceptions.vws_exceptions.RequestTimeTooSkewedError: There is
8490
an error with the time sent to Vuforia.
8591
~vws.exceptions.vws_exceptions.TargetStatusNotSuccessError: The

tests/test_async_vws_exceptions.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from http import HTTPStatus
66

77
import pytest
8-
from mock_vws import MockVWS
8+
from mock_vws import MockVWS, VuMarkGenerationFailure
99
from mock_vws.database import CloudDatabase
1010
from mock_vws.states import States
1111

@@ -16,14 +16,17 @@
1616
)
1717
from vws.exceptions.vws_exceptions import (
1818
AuthenticationFailureError,
19+
AuthorizationFailedError,
1920
BadImageError,
2021
FailError,
2122
ImageTooLargeError,
2223
InvalidInstanceIdError,
24+
LicenseCheckFailedError,
2325
MetadataTooLargeError,
2426
ProjectHasNoAPIAccessError,
2527
ProjectInactiveError,
2628
ProjectSuspendedError,
29+
QuotaExceededError,
2730
RequestQuotaReachedError,
2831
TargetNameExistError,
2932
TargetQuotaReachedError,
@@ -377,3 +380,47 @@ async def test_invalid_instance_id(
377380
)
378381

379382
assert exc.value.response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY
383+
384+
385+
@pytest.mark.asyncio
386+
@pytest.mark.parametrize(
387+
argnames=("failure", "exception_type", "status_code"),
388+
argvalues=[
389+
(
390+
VuMarkGenerationFailure.QUOTA_EXCEEDED,
391+
QuotaExceededError,
392+
HTTPStatus.FORBIDDEN,
393+
),
394+
(
395+
VuMarkGenerationFailure.LICENSE_CHECK_FAILED,
396+
LicenseCheckFailedError,
397+
HTTPStatus.FORBIDDEN,
398+
),
399+
(
400+
VuMarkGenerationFailure.AUTHORIZATION_FAILED,
401+
AuthorizationFailedError,
402+
HTTPStatus.UNAUTHORIZED,
403+
),
404+
],
405+
)
406+
async def test_documented_vumark_error_codes(
407+
*,
408+
failure: VuMarkGenerationFailure,
409+
exception_type: type[VWSError],
410+
status_code: HTTPStatus,
411+
) -> None:
412+
"""Documented VuMark failures raise matching exceptions."""
413+
with MockVWS(vumark_generation_failure=failure):
414+
async with AsyncVuMarkService(
415+
server_access_key=uuid.uuid4().hex,
416+
server_secret_key=uuid.uuid4().hex,
417+
) as vumark_service:
418+
with pytest.raises(expected_exception=exception_type) as exc:
419+
await vumark_service.generate_vumark_instance(
420+
target_id="exampletargetid",
421+
instance_id="example_instance_id",
422+
accept=VuMarkAccept.PNG,
423+
)
424+
425+
assert exc.value.response.status_code == status_code
426+
assert failure.value in exc.value.response.text

tests/test_vws_exceptions.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import pytest
88
from freezegun import freeze_time
9-
from mock_vws import MockVWS
9+
from mock_vws import MockVWS, VuMarkGenerationFailure
1010
from mock_vws.database import CloudDatabase
1111
from mock_vws.states import States
1212

@@ -17,6 +17,7 @@
1717
)
1818
from vws.exceptions.vws_exceptions import (
1919
AuthenticationFailureError,
20+
AuthorizationFailedError,
2021
BadImageError,
2122
BadRequestError,
2223
DateRangeError,
@@ -25,10 +26,12 @@
2526
InvalidAcceptHeaderError,
2627
InvalidInstanceIdError,
2728
InvalidTargetTypeError,
29+
LicenseCheckFailedError,
2830
MetadataTooLargeError,
2931
ProjectHasNoAPIAccessError,
3032
ProjectInactiveError,
3133
ProjectSuspendedError,
34+
QuotaExceededError,
3235
RequestQuotaReachedError,
3336
RequestTimeTooSkewedError,
3437
TargetNameExistError,
@@ -412,6 +415,7 @@ def test_vwsexception_inheritance() -> None:
412415
"""VWS-related exceptions should inherit from VWSException."""
413416
subclasses = [
414417
AuthenticationFailureError,
418+
AuthorizationFailedError,
415419
BadImageError,
416420
BadRequestError,
417421
DateRangeError,
@@ -420,10 +424,12 @@ def test_vwsexception_inheritance() -> None:
420424
InvalidAcceptHeaderError,
421425
InvalidInstanceIdError,
422426
InvalidTargetTypeError,
427+
LicenseCheckFailedError,
423428
MetadataTooLargeError,
424429
ProjectInactiveError,
425430
ProjectHasNoAPIAccessError,
426431
ProjectSuspendedError,
432+
QuotaExceededError,
427433
RequestQuotaReachedError,
428434
RequestTimeTooSkewedError,
429435
TargetNameExistError,
@@ -492,6 +498,50 @@ def test_invalid_target_type(
492498
assert exc.value.response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY
493499

494500

501+
@pytest.mark.parametrize(
502+
argnames=("failure", "exception_type", "status_code"),
503+
argvalues=[
504+
(
505+
VuMarkGenerationFailure.QUOTA_EXCEEDED,
506+
QuotaExceededError,
507+
HTTPStatus.FORBIDDEN,
508+
),
509+
(
510+
VuMarkGenerationFailure.LICENSE_CHECK_FAILED,
511+
LicenseCheckFailedError,
512+
HTTPStatus.FORBIDDEN,
513+
),
514+
(
515+
VuMarkGenerationFailure.AUTHORIZATION_FAILED,
516+
AuthorizationFailedError,
517+
HTTPStatus.UNAUTHORIZED,
518+
),
519+
],
520+
)
521+
def test_documented_vumark_error_codes(
522+
*,
523+
failure: VuMarkGenerationFailure,
524+
exception_type: type[VWSError],
525+
status_code: HTTPStatus,
526+
) -> None:
527+
"""Documented VuMark failures raise matching exceptions."""
528+
with MockVWS(vumark_generation_failure=failure):
529+
vumark_service = VuMarkService(
530+
server_access_key=uuid.uuid4().hex,
531+
server_secret_key=uuid.uuid4().hex,
532+
)
533+
534+
with pytest.raises(expected_exception=exception_type) as exc:
535+
vumark_service.generate_vumark_instance(
536+
target_id="exampletargetid",
537+
instance_id="example_instance_id",
538+
accept=VuMarkAccept.PNG,
539+
)
540+
541+
assert exc.value.response.status_code == status_code
542+
assert failure.value in exc.value.response.text
543+
544+
495545
def test_base_exception(
496546
*,
497547
vws_client: VWS,

0 commit comments

Comments
 (0)