Skip to content

Commit bbb848a

Browse files
adamtheturtleclaude
andcommitted
Address PR comments: VuMark target type and target_id fix
- Fix target_id property extraction for /targets/{id}/instances URL pattern - Add InvalidTargetTypeError exception - Add vumark_vws_client and vumark_target_id fixtures using a pre-populated VuMark template target (requires vws-python-mock#2962) - Update tests to use VuMark target instead of a standard cloud target - Add test_invalid_target_type test (requires vws-python-mock#2961) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 7171df9 commit bbb848a

File tree

5 files changed

+93
-26
lines changed

5 files changed

+93
-26
lines changed

src/vws/exceptions/vws_exceptions.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ class UnknownTargetError(VWSError):
2424
def target_id(self) -> str:
2525
"""The unknown target ID."""
2626
path = urlparse(url=self.response.url).path
27-
# Every HTTP path which can raise this error is in the format
28-
# `/something/{target_id}`.
29-
return path.split(sep="/", maxsplit=2)[-1]
27+
# Every HTTP path which can raise this error has the target ID as the
28+
# second path segment, e.g. `/something/{target_id}` or
29+
# `/something/{target_id}/more`.
30+
return path.split(sep="/")[2]
3031

3132

3233
@beartype
@@ -68,9 +69,10 @@ class TargetStatusProcessingError(VWSError):
6869
def target_id(self) -> str:
6970
"""The processing target ID."""
7071
path = urlparse(url=self.response.url).path
71-
# Every HTTP path which can raise this error is in the format
72-
# `/something/{target_id}`.
73-
return path.split(sep="/", maxsplit=2)[-1]
72+
# Every HTTP path which can raise this error has the target ID as the
73+
# second path segment, e.g. `/something/{target_id}` or
74+
# `/something/{target_id}/more`.
75+
return path.split(sep="/")[2]
7476

7577

7678
# This is not simulated by the mock.
@@ -157,9 +159,10 @@ class TargetStatusNotSuccessError(VWSError):
157159
def target_id(self) -> str:
158160
"""The unknown target ID."""
159161
path = urlparse(url=self.response.url).path
160-
# Every HTTP path which can raise this error is in the format
161-
# `/something/{target_id}`.
162-
return path.split(sep="/", maxsplit=2)[-1]
162+
# Every HTTP path which can raise this error has the target ID as the
163+
# second path segment, e.g. `/something/{target_id}` or
164+
# `/something/{target_id}/more`.
165+
return path.split(sep="/")[2]
163166

164167

165168
@beartype
@@ -192,3 +195,10 @@ class BadRequestError(VWSError): # pragma: no cover
192195
"""Exception raised when Vuforia returns a response with a result code
193196
``BadRequest``.
194197
"""
198+
199+
200+
@beartype
201+
class InvalidTargetTypeError(VWSError):
202+
"""Exception raised when Vuforia returns a response with a result code
203+
``InvalidTargetType``.
204+
"""

src/vws/vws.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
ImageTooLargeError,
2727
InvalidAcceptHeaderError,
2828
InvalidInstanceIdError,
29+
InvalidTargetTypeError,
2930
MetadataTooLargeError,
3031
ProjectHasNoAPIAccessError,
3132
ProjectInactiveError,
@@ -244,6 +245,7 @@ def make_request(
244245
"ImageTooLarge": ImageTooLargeError,
245246
"InvalidAcceptHeader": InvalidAcceptHeaderError,
246247
"InvalidInstanceId": InvalidInstanceIdError,
248+
"InvalidTargetType": InvalidTargetTypeError,
247249
"MetadataTooLarge": MetadataTooLargeError,
248250
"ProjectHasNoAPIAccess": ProjectHasNoAPIAccessError,
249251
"ProjectInactive": ProjectInactiveError,
@@ -755,6 +757,8 @@ def generate_vumark_instance(
755757
Accept header value is not supported.
756758
~vws.exceptions.vws_exceptions.InvalidInstanceIdError: The
757759
instance ID is invalid. For example, it may be empty.
760+
~vws.exceptions.vws_exceptions.InvalidTargetTypeError: The target
761+
is not a VuMark template target.
758762
~vws.exceptions.vws_exceptions.RequestTimeTooSkewedError: There is
759763
an error with the time sent to Vuforia.
760764
~vws.exceptions.vws_exceptions.TargetStatusNotSuccessError: The

tests/conftest.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import pytest
99
from mock_vws import MockVWS
1010
from mock_vws.database import VuforiaDatabase
11+
from mock_vws.target import Target
12+
from mock_vws.target_raters import HardcodedTargetTrackingRater
1113

1214
from vws import VWS, CloudRecoService
1315

@@ -22,6 +24,45 @@ def fixture_mock_database() -> Generator[VuforiaDatabase]:
2224
yield database
2325

2426

27+
@pytest.fixture(name="_mock_vumark_database")
28+
def fixture_mock_vumark_database(
29+
high_quality_image: io.BytesIO,
30+
) -> Generator[VuforiaDatabase]:
31+
"""Yield a mock VuMark ``VuforiaDatabase`` with a pre-populated
32+
template target.
33+
"""
34+
vumark_target = Target(
35+
active_flag=True,
36+
application_metadata=None,
37+
image_value=high_quality_image.getvalue(),
38+
is_vumark_template=True,
39+
name="vumark-template",
40+
processing_time_seconds=0,
41+
target_tracking_rater=HardcodedTargetTrackingRater(rating=5),
42+
width=1,
43+
)
44+
with MockVWS() as mock:
45+
database = VuforiaDatabase(targets={vumark_target})
46+
mock.add_database(database=database)
47+
yield database
48+
49+
50+
@pytest.fixture
51+
def vumark_vws_client(_mock_vumark_database: VuforiaDatabase) -> VWS:
52+
"""A VWS client which connects to a mock VuMark database."""
53+
return VWS(
54+
server_access_key=_mock_vumark_database.server_access_key,
55+
server_secret_key=_mock_vumark_database.server_secret_key,
56+
)
57+
58+
59+
@pytest.fixture
60+
def vumark_target_id(_mock_vumark_database: VuforiaDatabase) -> str:
61+
"""The ID of the pre-populated VuMark template target."""
62+
(target,) = _mock_vumark_database.targets
63+
return target.target_id
64+
65+
2566
@pytest.fixture
2667
def vws_client(_mock_database: VuforiaDatabase) -> VWS:
2768
"""A VWS client which connects to a mock database."""

tests/test_vws.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -745,22 +745,14 @@ class TestGenerateVumarkInstance:
745745
],
746746
)
747747
def test_generate_vumark_instance(
748-
vws_client: VWS,
749-
high_quality_image: io.BytesIO,
748+
vumark_vws_client: VWS,
749+
vumark_target_id: str,
750750
accept: VuMarkAccept,
751751
expected_prefix: bytes,
752752
) -> None:
753753
"""The returned bytes match the requested format."""
754-
target_id = vws_client.add_target(
755-
name="x",
756-
width=1,
757-
image=high_quality_image,
758-
active_flag=True,
759-
application_metadata=None,
760-
)
761-
vws_client.wait_for_target_processed(target_id=target_id)
762-
result = vws_client.generate_vumark_instance(
763-
target_id=target_id,
754+
result = vumark_vws_client.generate_vumark_instance(
755+
target_id=vumark_target_id,
764756
instance_id="12345",
765757
accept=accept,
766758
)

tests/test_vws_exceptions.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
ImageTooLargeError,
2525
InvalidAcceptHeaderError,
2626
InvalidInstanceIdError,
27+
InvalidTargetTypeError,
2728
MetadataTooLargeError,
2829
ProjectHasNoAPIAccessError,
2930
ProjectInactiveError,
@@ -349,6 +350,7 @@ def test_vwsexception_inheritance() -> None:
349350
ImageTooLargeError,
350351
InvalidAcceptHeaderError,
351352
InvalidInstanceIdError,
353+
InvalidTargetTypeError,
352354
MetadataTooLargeError,
353355
ProjectInactiveError,
354356
ProjectHasNoAPIAccessError,
@@ -366,13 +368,31 @@ def test_vwsexception_inheritance() -> None:
366368

367369

368370
def test_invalid_instance_id(
369-
vws_client: VWS,
370-
high_quality_image: io.BytesIO,
371+
vumark_vws_client: VWS,
372+
vumark_target_id: str,
371373
) -> None:
372374
"""
373375
An ``InvalidInstanceId`` exception is raised when an empty instance
374376
ID is given.
375377
"""
378+
with pytest.raises(expected_exception=InvalidInstanceIdError) as exc:
379+
vumark_vws_client.generate_vumark_instance(
380+
target_id=vumark_target_id,
381+
instance_id="",
382+
accept=VuMarkAccept.PNG,
383+
)
384+
385+
assert exc.value.response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY
386+
387+
388+
def test_invalid_target_type(
389+
vws_client: VWS,
390+
high_quality_image: io.BytesIO,
391+
) -> None:
392+
"""
393+
An ``InvalidTargetType`` exception is raised when trying to generate
394+
a VuMark instance from a non-VuMark target.
395+
"""
376396
target_id = vws_client.add_target(
377397
name="x",
378398
width=1,
@@ -381,14 +401,14 @@ def test_invalid_instance_id(
381401
application_metadata=None,
382402
)
383403
vws_client.wait_for_target_processed(target_id=target_id)
384-
with pytest.raises(expected_exception=InvalidInstanceIdError) as exc:
404+
with pytest.raises(expected_exception=InvalidTargetTypeError) as exc:
385405
vws_client.generate_vumark_instance(
386406
target_id=target_id,
387-
instance_id="",
407+
instance_id="12345",
388408
accept=VuMarkAccept.PNG,
389409
)
390410

391-
assert exc.value.response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY
411+
assert exc.value.response.status_code == HTTPStatus.FORBIDDEN
392412

393413

394414
def test_base_exception(

0 commit comments

Comments
 (0)