Skip to content

Commit

Permalink
dict or str
Browse files Browse the repository at this point in the history
  • Loading branch information
mjvogelsong committed Nov 9, 2023
1 parent d37b6fd commit 73398c8
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 25 deletions.
2 changes: 1 addition & 1 deletion generated/model.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# generated by datamodel-codegen:
# filename: public-api.yaml
# timestamp: 2023-11-08T22:11:51+00:00
# timestamp: 2023-11-09T05:00:29+00:00

from __future__ import annotations

Expand Down
32 changes: 16 additions & 16 deletions src/groundlight/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ def submit_image_query( # noqa: PLR0913 # pylint: disable=too-many-arguments, t
human_review: Optional[str] = None,
want_async: bool = False,
inspection_id: Optional[str] = None,
metadata: Optional[dict] = None,
metadata: Union[dict, str, None] = None,
) -> ImageQuery:
"""
Evaluates an image with Groundlight.
Expand Down Expand Up @@ -336,10 +336,10 @@ def submit_image_query( # noqa: PLR0913 # pylint: disable=too-many-arguments, t
this is the ID of the inspection to associate with the image query.
:type inspection_id: str
:param metadata: A dictionary of custom key/value metadata to associate with the image
query (limited to 1KB). You can retrieve this metadata later by calling
:param metadata: A dictionary or JSON string of custom key/value metadata to associate with
the image query (limited to 1KB). You can retrieve this metadata later by calling
`get_image_query()`.
:type metadata: dict
:type metadata: dict or str
:return: ImageQuery
:rtype: ImageQuery
Expand Down Expand Up @@ -399,7 +399,7 @@ def ask_confident( # noqa: PLR0913 # pylint: disable=too-many-arguments
image: Union[str, bytes, Image.Image, BytesIO, BufferedReader, np.ndarray],
confidence_threshold: Optional[float] = None,
wait: Optional[float] = None,
metadata: Optional[dict] = None,
metadata: Union[dict, str, None] = None,
) -> ImageQuery:
"""
Evaluates an image with Groundlight waiting until an answer above the confidence threshold
Expand All @@ -425,10 +425,10 @@ def ask_confident( # noqa: PLR0913 # pylint: disable=too-many-arguments
:param wait: How long to wait (in seconds) for a confident answer.
:type wait: float
:param metadata: A dictionary of custom key/value metadata to associate with the image
query (limited to 1KB). You can retrieve this metadata later by calling
:param metadata: A dictionary or JSON string of custom key/value metadata to associate with
the image query (limited to 1KB). You can retrieve this metadata later by calling
`get_image_query()`.
:type metadata: dict
:type metadata: dict or str
:return: ImageQuery
:rtype: ImageQuery
Expand All @@ -448,7 +448,7 @@ def ask_ml(
detector: Union[Detector, str],
image: Union[str, bytes, Image.Image, BytesIO, BufferedReader, np.ndarray],
wait: Optional[float] = None,
metadata: Optional[dict] = None,
metadata: Union[dict, str, None] = None,
) -> ImageQuery:
"""
Evaluates an image with Groundlight, getting the first answer Groundlight can provide.
Expand All @@ -469,10 +469,10 @@ def ask_ml(
:param wait: How long to wait (in seconds) for any answer.
:type wait: float
:param metadata: A dictionary of custom key/value metadata to associate with the image
query (limited to 1KB). You can retrieve this metadata later by calling
:param metadata: A dictionary or JSON string of custom key/value metadata to associate with
the image query (limited to 1KB). You can retrieve this metadata later by calling
`get_image_query()`.
:type metadata: dict
:type metadata: dict or str
:return: ImageQuery
:rtype: ImageQuery
Expand All @@ -495,7 +495,7 @@ def ask_async( # noqa: PLR0913 # pylint: disable=too-many-arguments
patience_time: Optional[float] = None,
confidence_threshold: Optional[float] = None,
human_review: Optional[str] = None,
metadata: Optional[dict] = None,
metadata: Union[dict, str, None] = None,
) -> ImageQuery:
"""
Convenience method for submitting an `ImageQuery` asynchronously. This is equivalent to calling
Expand Down Expand Up @@ -537,10 +537,10 @@ def ask_async( # noqa: PLR0913 # pylint: disable=too-many-arguments
this is the ID of the inspection to associate with the image query.
:type inspection_id: str
:param metadata: A dictionary of custom key/value metadata to associate with the image
query (limited to 1KB). You can retrieve this metadata later by calling
:param metadata: A dictionary or JSON string of custom key/value metadata to associate with
the image query (limited to 1KB). You can retrieve this metadata later by calling
`get_image_query()`.
:type metadata: dict
:type metadata: dict or str
:return: ImageQuery
:rtype: ImageQuery
Expand Down
17 changes: 12 additions & 5 deletions src/groundlight/encodings.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import base64
import json
import sys
from typing import Dict, Optional
from typing import Dict, Optional, Union


def url_encode_dict(maybe_dict: Dict, name: str, size_limit_bytes: Optional[int] = None) -> str:
def url_encode_dict(maybe_dict: Union[Dict, str], name: str, size_limit_bytes: Optional[int] = None) -> str:
"""Encode a dictionary as a URL-safe, base64-encoded JSON string.
:param maybe_dict: The dictionary to encode.
:param maybe_dict: The dictionary or JSON string to encode.
:type maybe_dict: dict
:param name: The name of the dictionary, for use in the error message.
Expand All @@ -17,14 +17,21 @@ def url_encode_dict(maybe_dict: Dict, name: str, size_limit_bytes: Optional[int]
If `None`, no size limit is enforced.
:type size_limit_bytes: int or None
:raises TypeError: If `maybe_dict` is not a dictionary.
:raises TypeError: If `maybe_dict` is not a dictionary or JSON string.
:raises ValueError: If `maybe_dict` is too large.
:return: The URL-safe, base64-encoded JSON string.
:rtype: str
"""
original_type = type(maybe_dict)
if isinstance(maybe_dict, str):
try:
maybe_dict = json.loads(maybe_dict)
except json.JSONDecodeError:
raise TypeError(f"`{name}` must be a dictionary or JSON string: got {original_type}")

if not isinstance(maybe_dict, dict):
raise TypeError(f"`{name}` must be a dictionary: got {type(maybe_dict)}")
raise TypeError(f"`{name}` must be a dictionary or JSON string: got {original_type}")

data_json = json.dumps(maybe_dict)

Expand Down
10 changes: 7 additions & 3 deletions test/integration/test_groundlight.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Optional star-imports are weird and not usually recommended ...
# ruff: noqa: F403,F405
# pylint: disable=wildcard-import,unused-wildcard-import,redefined-outer-name,import-outside-toplevel
import json
import time
from datetime import datetime
from typing import Any, Dict, Optional
Expand Down Expand Up @@ -251,16 +252,19 @@ def test_submit_image_query_with_human_review_param(gl: Groundlight, detector: D
assert is_valid_display_result(_image_query.result)


@pytest.mark.parametrize("metadata", [None, {}, {"a": 1}])
@pytest.mark.parametrize("metadata", [None, {}, {"a": 1}, '{"a": 1}'])
def test_submit_image_query_with_metadata(
gl: Groundlight, detector: Detector, image: str, metadata: Optional[Dict[str, Any]]
):
# We expect the returned value to be a dict
expected_metadata: Optional[Dict] = json.loads(metadata) if isinstance(metadata, str) else metadata

iq = gl.submit_image_query(detector=detector.id, image=image, human_review="NEVER", metadata=metadata)
assert iq.metadata == metadata
assert iq.metadata == expected_metadata

# Test that we can retrieve the metadata from the server at a later time
retrieved_iq = gl.get_image_query(id=iq.id)
assert retrieved_iq.metadata == metadata
assert retrieved_iq.metadata == expected_metadata


def test_ask_methods_with_metadata(gl: Groundlight, detector: Detector, image: str):
Expand Down

0 comments on commit 73398c8

Please sign in to comment.