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
4 changes: 4 additions & 0 deletions docs/source/api-reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ API Reference
:undoc-members:
:members:

.. automodule:: vws.json_types
:undoc-members:
:members:

.. automodule:: vws.include_target_data
:undoc-members:
:members:
Expand Down
1 change: 1 addition & 0 deletions newsfragments/3223.change.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Type decoded report response dictionaries as JSON values.
4 changes: 1 addition & 3 deletions src/vws/_json_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@

from beartype.door import TypeHint

type JSONValue = (
bool | int | float | str | list[JSONValue] | dict[str, JSONValue] | None
)
from vws.json_types import JSONValue


def _is_json_object(value: object, /) -> TypeGuard[dict[str, JSONValue]]:
Expand Down
3 changes: 2 additions & 1 deletion src/vws/_model_targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from beartype import BeartypeConf, beartype

from vws._json_utils import JSONValue, json_object
from vws._json_utils import json_object
from vws.exceptions.custom_exceptions import ServerError
from vws.exceptions.model_target_exceptions import (
ModelTargetAuthenticationError,
Expand All @@ -18,6 +18,7 @@
UnknownModelTargetDatasetError,
)
from vws.exceptions.vws_exceptions import TooManyRequestsError
from vws.json_types import JSONValue
from vws.model_target_datasets import (
ModelTargetDatasetType,
ModelTargetModel,
Expand Down
2 changes: 1 addition & 1 deletion src/vws/exceptions/model_target_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
from beartype import beartype

from vws._json_utils import (
JSONValue,
json_object,
object_field,
object_list_field,
string_field,
)
from vws.json_types import JSONValue
from vws.reports import ModelTargetGenerationDetail
from vws.response import Response

Expand Down
6 changes: 6 additions & 0 deletions src/vws/json_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""JSON value types used by Vuforia API requests and responses."""

type JSONValue = (
bool | int | float | str | list[JSONValue] | dict[str, JSONValue] | None
)
"""A value which can be represented in a JSON document."""
32 changes: 21 additions & 11 deletions src/vws/reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from beartype import BeartypeConf, beartype
from beartype.door import TypeHint

from vws.json_types import JSONValue


def _checked[T](value: object, hint: type[T], /) -> T:
"""Return a value after checking its runtime type."""
Expand Down Expand Up @@ -64,7 +66,9 @@ class DatabaseSummaryReport:
total_recos: int

@classmethod
def from_response_dict(cls, response_dict: Mapping[str, object]) -> Self:
def from_response_dict(
cls, response_dict: Mapping[str, JSONValue]
) -> Self:
"""Construct from a VWS API response dict."""
return cls(
active_images=int(_number(response_dict["active_images"])),
Expand Down Expand Up @@ -120,7 +124,9 @@ class TargetSummaryReport:
previous_month_recos: int

@classmethod
def from_response_dict(cls, response_dict: Mapping[str, object]) -> Self:
def from_response_dict(
cls, response_dict: Mapping[str, JSONValue]
) -> Self:
"""Construct from a VWS API response dict."""
return cls(
status=TargetStatuses(
Expand Down Expand Up @@ -185,13 +191,13 @@ class QueryResult:
@classmethod
def from_response_dict(
cls,
response_dict: Mapping[str, object],
response_dict: Mapping[str, JSONValue],
) -> Self:
"""Construct from a VWS API query result item dict."""
target_data: TargetData | None = None
if "target_data" in response_dict:
target_data_dict = _checked(
response_dict["target_data"], dict[str, object]
response_dict["target_data"], dict[str, JSONValue]
)
target_timestamp = datetime.datetime.fromtimestamp(
timestamp=_number(target_data_dict["target_timestamp"]),
Expand Down Expand Up @@ -223,11 +229,13 @@ class TargetStatusAndRecord:
target_record: TargetRecord

@classmethod
def from_response_dict(cls, response_dict: Mapping[str, object]) -> Self:
def from_response_dict(
cls, response_dict: Mapping[str, JSONValue]
) -> Self:
"""Construct from a VWS API response dict."""
status = TargetStatuses(value=_checked(response_dict["status"], str))
target_record_dict = _checked(
response_dict["target_record"], dict[str, object]
response_dict["target_record"], dict[str, JSONValue]
)
target_record = TargetRecord(
target_id=_checked(target_record_dict["target_id"], str),
Expand Down Expand Up @@ -260,7 +268,9 @@ class RecoCountsReportRequest:
"""

@classmethod
def from_response_dict(cls, response_dict: Mapping[str, object]) -> Self:
def from_response_dict(
cls, response_dict: Mapping[str, JSONValue]
) -> Self:
"""Construct from a VWS API response dict."""
return cls(
transaction_id=_checked(response_dict["transaction_id"], str),
Expand Down Expand Up @@ -353,12 +363,12 @@ class ModelTargetDatasetStatusReport:
@classmethod
def from_response_dict(
cls,
response_dict: Mapping[str, object],
response_dict: Mapping[str, JSONValue],
) -> Self:
"""Construct from a Model Target Web API response dict."""
error: ModelTargetGenerationError | None = None
if "error" in response_dict:
error_dict = _checked(response_dict["error"], dict[str, object])
error_dict = _checked(response_dict["error"], dict[str, JSONValue])
error = ModelTargetGenerationError(
code=_checked(error_dict["code"], str),
message=_checked(error_dict["message"], str),
Expand All @@ -367,10 +377,10 @@ def from_response_dict(
warning: ModelTargetGenerationWarning | None = None
if "warning" in response_dict:
warning_dict = _checked(
response_dict["warning"], dict[str, object]
response_dict["warning"], dict[str, JSONValue]
)
details = _checked(
warning_dict["details"], list[dict[str, object]]
warning_dict["details"], list[dict[str, JSONValue]]
)
warning = ModelTargetGenerationWarning(
code=_checked(warning_dict["code"], str),
Expand Down
7 changes: 6 additions & 1 deletion tests/test_reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

from vws.reports import QueryResult

type JSONValue = (
bool | int | float | str | list[JSONValue] | dict[str, JSONValue] | None
)


@pytest.mark.parametrize(
argnames="response",
Expand All @@ -28,7 +32,8 @@
],
)
def test_query_result_rejects_invalid_response_values(
*, response: dict[str, object]
*,
response: dict[str, JSONValue],
) -> None:
"""Query reports reject values of the wrong type."""
with pytest.raises(expected_exception=TypeError):
Expand Down