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
10 changes: 10 additions & 0 deletions src/vws/_json_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@
import json
from typing import TypeGuard

from beartype import beartype
from beartype.door import TypeHint

from vws.json_types import JSONValue


@beartype
def _is_json_object(value: object, /) -> TypeGuard[dict[str, JSONValue]]:
"""Return whether a decoded JSON value is an object."""
return TypeHint(hint=dict[str, JSONValue]).is_bearable(obj=value)


@beartype
def _is_object_list(value: object, /) -> TypeGuard[list[JSONValue]]:
"""Return whether a decoded JSON value is an array."""
return TypeHint(hint=list[JSONValue]).is_bearable(obj=value)


@beartype
def _validated_object(*, value: object) -> dict[str, JSONValue]:
"""Return a decoded JSON object."""
if not _is_json_object(value):
Expand All @@ -26,19 +30,22 @@ def _validated_object(*, value: object) -> dict[str, JSONValue]:
return value


@beartype
def json_object(*, value: str | bytes | bytearray) -> dict[str, JSONValue]:
"""Decode and validate a JSON object."""
loaded: object = json.loads(s=value)
return _validated_object(value=loaded)


@beartype
def object_field(
*, value: dict[str, JSONValue], name: str
) -> dict[str, JSONValue]:
"""Return a required JSON object field."""
return _validated_object(value=value[name])


@beartype
def string_value(*, value: object, name: str) -> str:
"""Return a JSON value after validating that it is a string."""
if not isinstance(value, str):
Expand All @@ -47,11 +54,13 @@ def string_value(*, value: object, name: str) -> str:
return value


@beartype
def string_field(*, value: dict[str, JSONValue], name: str) -> str:
"""Return a required string field from a JSON object."""
return string_value(value=value[name], name=name)


@beartype
def string_list_field(
*,
value: dict[str, JSONValue],
Expand All @@ -67,6 +76,7 @@ def string_list_field(
return [item for item in items if isinstance(item, str)]


@beartype
def object_list_field(
*,
value: dict[str, JSONValue],
Expand Down
1 change: 1 addition & 0 deletions src/vws/exceptions/vws_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from vws.exceptions.base_exceptions import VWSError


@beartype
def _target_id_from_url(*, url: str) -> str:
"""Return the target ID from a VWS response URL.

Expand Down
2 changes: 2 additions & 0 deletions src/vws/reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def _is_type[T](value: object, hint: type[T], /) -> TypeIs[T]:
return TypeHint(hint=hint).is_bearable(obj=value)


@beartype
def _number(value: object, /) -> int | float:
"""Return a runtime-validated JSON number."""
if isinstance(value, bool) or not isinstance(value, int | float):
Expand All @@ -35,6 +36,7 @@ def _number(value: object, /) -> int | float:
return value


@beartype
def _optional_string(value: object, /) -> str | None:
"""Return a runtime-validated optional string."""
if value is not None and not isinstance(value, str):
Expand Down