Skip to content

Commit b68340f

Browse files
Merge pull request #3227 from VWS-Python/cover-service-http-statuses
Cover service HTTP status handling
2 parents 05549b2 + bc299e6 commit b68340f

5 files changed

Lines changed: 120 additions & 18 deletions

File tree

src/vws/async_vumark_service.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,16 +133,12 @@ async def generate_vumark_instance(
133133
transport=self._transport,
134134
)
135135

136-
if (
137-
response.status_code == HTTPStatus.TOO_MANY_REQUESTS
138-
): # pragma: no cover
136+
if response.status_code == HTTPStatus.TOO_MANY_REQUESTS:
139137
# The Vuforia API returns a 429 response with no
140138
# JSON body.
141139
raise TooManyRequestsError(response=response)
142140

143-
if (
144-
response.status_code >= HTTPStatus.INTERNAL_SERVER_ERROR
145-
): # pragma: no cover
141+
if response.status_code >= HTTPStatus.INTERNAL_SERVER_ERROR:
146142
raise ServerError(response=response)
147143

148144
if response.status_code == HTTPStatus.OK:

src/vws/async_vws.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,7 @@ async def make_request(
142142
transport=self._transport,
143143
)
144144

145-
if (
146-
response.status_code == HTTPStatus.TOO_MANY_REQUESTS
147-
): # pragma: no cover
145+
if response.status_code == HTTPStatus.TOO_MANY_REQUESTS:
148146
# The Vuforia API returns a 429 response with no JSON body.
149147
raise TooManyRequestsError(response=response)
150148

src/vws/vumark_service.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,11 @@ def generate_vumark_instance(
117117
transport=self._transport,
118118
)
119119

120-
if (
121-
response.status_code == HTTPStatus.TOO_MANY_REQUESTS
122-
): # pragma: no cover
120+
if response.status_code == HTTPStatus.TOO_MANY_REQUESTS:
123121
# The Vuforia API returns a 429 response with no JSON body.
124122
raise TooManyRequestsError(response=response)
125123

126-
if (
127-
response.status_code >= HTTPStatus.INTERNAL_SERVER_ERROR
128-
): # pragma: no cover
124+
if response.status_code >= HTTPStatus.INTERNAL_SERVER_ERROR:
129125
raise ServerError(response=response)
130126

131127
if response.status_code == HTTPStatus.OK:

src/vws/vws.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,7 @@ def make_request(
128128
transport=self._transport,
129129
)
130130

131-
if (
132-
response.status_code == HTTPStatus.TOO_MANY_REQUESTS
133-
): # pragma: no cover
131+
if response.status_code == HTTPStatus.TOO_MANY_REQUESTS:
134132
# The Vuforia API returns a 429 response with no JSON body.
135133
raise TooManyRequestsError(response=response)
136134

tests/test_transports.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
ModelTargetService,
2525
VuMarkService,
2626
)
27+
from vws.exceptions.custom_exceptions import ServerError
28+
from vws.exceptions.vws_exceptions import TooManyRequestsError
2729
from vws.model_target_datasets import (
2830
ModelTargetDatasetType,
2931
ModelTargetModel,
@@ -430,6 +432,118 @@ async def test_falsy_async_transport_is_retained(
430432
)
431433

432434

435+
@pytest.mark.parametrize(
436+
argnames=("status_code", "exception_type"),
437+
argvalues=[
438+
(HTTPStatus.TOO_MANY_REQUESTS, TooManyRequestsError),
439+
(HTTPStatus.INTERNAL_SERVER_ERROR, ServerError),
440+
],
441+
)
442+
@respx.mock
443+
def test_vumark_service_handles_bodyless_http_errors(
444+
*,
445+
status_code: HTTPStatus,
446+
exception_type: type[ServerError | TooManyRequestsError],
447+
) -> None:
448+
"""VuMark HTTP errors which have no JSON body remain meaningful."""
449+
route = respx.post(
450+
url="https://example.com/targets/target/instances"
451+
).mock(return_value=httpx.Response(status_code=status_code))
452+
453+
with HTTPXTransport() as transport:
454+
service = VuMarkService(
455+
server_access_key="access-key",
456+
server_secret_key=uuid.uuid4().hex,
457+
base_vws_url="https://example.com",
458+
transport=transport,
459+
)
460+
with pytest.raises(expected_exception=exception_type):
461+
_ = service.generate_vumark_instance(
462+
target_id="target",
463+
instance_id="instance",
464+
accept=VuMarkAccept.PNG,
465+
)
466+
467+
assert route.called
468+
469+
470+
@respx.mock
471+
def test_vws_handles_bodyless_rate_limit_response() -> None:
472+
"""A body-less target-manager rate limit raises its specific error."""
473+
route = respx.get(url="https://example.com/targets").mock(
474+
return_value=httpx.Response(status_code=HTTPStatus.TOO_MANY_REQUESTS)
475+
)
476+
477+
with HTTPXTransport() as transport:
478+
service = VWS(
479+
server_access_key="access-key",
480+
server_secret_key=uuid.uuid4().hex,
481+
base_vws_url="https://example.com",
482+
transport=transport,
483+
)
484+
with pytest.raises(expected_exception=TooManyRequestsError):
485+
_ = service.list_targets()
486+
487+
assert route.called
488+
489+
490+
@pytest.mark.asyncio
491+
@pytest.mark.parametrize(
492+
argnames=("status_code", "exception_type"),
493+
argvalues=[
494+
(HTTPStatus.TOO_MANY_REQUESTS, TooManyRequestsError),
495+
(HTTPStatus.INTERNAL_SERVER_ERROR, ServerError),
496+
],
497+
)
498+
@respx.mock
499+
async def test_async_vumark_service_handles_bodyless_http_errors(
500+
*,
501+
status_code: HTTPStatus,
502+
exception_type: type[ServerError | TooManyRequestsError],
503+
) -> None:
504+
"""Async VuMark HTTP errors without JSON remain meaningful."""
505+
route = respx.post(
506+
url="https://example.com/targets/target/instances"
507+
).mock(return_value=httpx.Response(status_code=status_code))
508+
509+
async with AsyncHTTPXTransport() as transport:
510+
service = AsyncVuMarkService(
511+
server_access_key="access-key",
512+
server_secret_key=uuid.uuid4().hex,
513+
base_vws_url="https://example.com",
514+
transport=transport,
515+
)
516+
with pytest.raises(expected_exception=exception_type):
517+
_ = await service.generate_vumark_instance(
518+
target_id="target",
519+
instance_id="instance",
520+
accept=VuMarkAccept.PNG,
521+
)
522+
523+
assert route.called
524+
525+
526+
@pytest.mark.asyncio
527+
@respx.mock
528+
async def test_async_vws_handles_bodyless_rate_limit_response() -> None:
529+
"""An async target-manager rate limit raises its specific error."""
530+
route = respx.get(url="https://example.com/targets").mock(
531+
return_value=httpx.Response(status_code=HTTPStatus.TOO_MANY_REQUESTS)
532+
)
533+
534+
async with AsyncHTTPXTransport() as transport:
535+
service = AsyncVWS(
536+
server_access_key="access-key",
537+
server_secret_key=uuid.uuid4().hex,
538+
base_vws_url="https://example.com",
539+
transport=transport,
540+
)
541+
with pytest.raises(expected_exception=TooManyRequestsError):
542+
_ = await service.list_targets()
543+
544+
assert route.called
545+
546+
433547
# The mock accepts one hard-coded pair of Model Target Web API OAuth2
434548
# credentials, which it does not expose.
435549
_MODEL_TARGET_CLIENT_ID = "client-id"

0 commit comments

Comments
 (0)