Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allows for filtering iqs by detector_id #294

Merged
merged 5 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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: 3 additions & 1 deletion generated/docs/ImageQueriesApi.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,12 @@ with groundlight_openapi_client.ApiClient(configuration) as api_client:
api_instance = image_queries_api.ImageQueriesApi(api_client)
page = 1 # int | A page number within the paginated result set. (optional)
page_size = 1 # int | Number of items to return per page. (optional)
predictor_id = "predictor_id_example" # str | Optionally filter image queries by detector ID. (optional)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: predictor_id -> detector_id


# example passing only required values which don't have defaults set
# and optional values
try:
api_response = api_instance.list_image_queries(page=page, page_size=page_size)
api_response = api_instance.list_image_queries(page=page, page_size=page_size, predictor_id=predictor_id)
pprint(api_response)
except groundlight_openapi_client.ApiException as e:
print("Exception when calling ImageQueriesApi->list_image_queries: %s\n" % e)
Expand All @@ -220,6 +221,7 @@ Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**page** | **int**| A page number within the paginated result set. | [optional]
**page_size** | **int**| Number of items to return per page. | [optional]
**predictor_id** | **str**| Optionally filter image queries by detector ID. | [optional]

### Return type

Expand Down
5 changes: 5 additions & 0 deletions generated/groundlight_openapi_client/api/image_queries_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ def __init__(self, api_client=None):
"all": [
"page",
"page_size",
"predictor_id",
],
"required": [],
"nullable": [],
Expand All @@ -141,14 +142,17 @@ def __init__(self, api_client=None):
"openapi_types": {
"page": (int,),
"page_size": (int,),
"predictor_id": (str,),
},
"attribute_map": {
"page": "page",
"page_size": "page_size",
"predictor_id": "predictor_id",
},
"location_map": {
"page": "query",
"page_size": "query",
"predictor_id": "query",
},
"collection_format_map": {},
},
Expand Down Expand Up @@ -375,6 +379,7 @@ def list_image_queries(self, **kwargs):
Keyword Args:
page (int): A page number within the paginated result set.. [optional]
page_size (int): Number of items to return per page.. [optional]
predictor_id (str): Optionally filter image queries by detector ID.. [optional]
_return_http_data_only (bool): response data without head status
code and headers. Default is True.
_preload_content (bool): if False, the urllib3.HTTPResponse object
Expand Down
151 changes: 93 additions & 58 deletions generated/groundlight_openapi_client/model/patched_detector_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
Generated by: https://openapi-generator.tech
"""


import re # noqa: F401
import sys # noqa: F401

Expand All @@ -25,7 +24,7 @@
file_type,
none_type,
validate_get_composed_info,
OpenApiModel
OpenApiModel,
)
from groundlight_openapi_client.exceptions import ApiAttributeError

Expand All @@ -34,9 +33,10 @@ def lazy_import():
from groundlight_openapi_client.model.blank_enum import BlankEnum
from groundlight_openapi_client.model.escalation_type_enum import EscalationTypeEnum
from groundlight_openapi_client.model.status_enum import StatusEnum
globals()['BlankEnum'] = BlankEnum
globals()['EscalationTypeEnum'] = EscalationTypeEnum
globals()['StatusEnum'] = StatusEnum

globals()["BlankEnum"] = BlankEnum
globals()["EscalationTypeEnum"] = EscalationTypeEnum
globals()["StatusEnum"] = StatusEnum


class PatchedDetectorRequest(ModelNormal):
Expand All @@ -63,21 +63,20 @@ class PatchedDetectorRequest(ModelNormal):
as additional properties values.
"""

allowed_values = {
}
allowed_values = {}

validations = {
('name',): {
'max_length': 200,
'min_length': 1,
("name",): {
"max_length": 200,
"min_length": 1,
},
('confidence_threshold',): {
'inclusive_maximum': 1.0,
'inclusive_minimum': 0.0,
("confidence_threshold",): {
"inclusive_maximum": 1.0,
"inclusive_minimum": 0.0,
},
('patience_time',): {
'inclusive_maximum': 3600,
'inclusive_minimum': 0,
("patience_time",): {
"inclusive_maximum": 3600,
"inclusive_minimum": 0,
},
}

Expand All @@ -88,7 +87,17 @@ def additional_properties_type():
of type self, this must run after the class is loaded
"""
lazy_import()
return (bool, date, datetime, dict, float, int, list, str, none_type,) # noqa: E501
return (
bool,
date,
datetime,
dict,
float,
int,
list,
str,
none_type,
) # noqa: E501

_nullable = False

Expand All @@ -104,28 +113,46 @@ def openapi_types():
"""
lazy_import()
return {
'name': (str,), # noqa: E501
'confidence_threshold': (float,), # noqa: E501
'patience_time': (float,), # noqa: E501
'status': (bool, date, datetime, dict, float, int, list, str, none_type,), # noqa: E501
'escalation_type': (bool, date, datetime, dict, float, int, list, str, none_type,), # noqa: E501
"name": (str,), # noqa: E501
"confidence_threshold": (float,), # noqa: E501
"patience_time": (float,), # noqa: E501
"status": (
bool,
date,
datetime,
dict,
float,
int,
list,
str,
none_type,
), # noqa: E501
"escalation_type": (
bool,
date,
datetime,
dict,
float,
int,
list,
str,
none_type,
), # noqa: E501
}

@cached_property
def discriminator():
return None


attribute_map = {
'name': 'name', # noqa: E501
'confidence_threshold': 'confidence_threshold', # noqa: E501
'patience_time': 'patience_time', # noqa: E501
'status': 'status', # noqa: E501
'escalation_type': 'escalation_type', # noqa: E501
"name": "name", # noqa: E501
"confidence_threshold": "confidence_threshold", # noqa: E501
"patience_time": "patience_time", # noqa: E501
"status": "status", # noqa: E501
"escalation_type": "escalation_type", # noqa: E501
}

read_only_vars = {
}
read_only_vars = {}

_composed_schemas = {}

Expand Down Expand Up @@ -172,17 +199,18 @@ def _from_openapi_data(cls, *args, **kwargs): # noqa: E501
escalation_type (bool, date, datetime, dict, float, int, list, str, none_type): Category that define internal proccess for labeling image queries * `STANDARD` - STANDARD * `NO_HUMAN_LABELING` - NO_HUMAN_LABELING. [optional] # noqa: E501
"""

_check_type = kwargs.pop('_check_type', True)
_spec_property_naming = kwargs.pop('_spec_property_naming', False)
_path_to_item = kwargs.pop('_path_to_item', ())
_configuration = kwargs.pop('_configuration', None)
_visited_composed_classes = kwargs.pop('_visited_composed_classes', ())
_check_type = kwargs.pop("_check_type", True)
_spec_property_naming = kwargs.pop("_spec_property_naming", False)
_path_to_item = kwargs.pop("_path_to_item", ())
_configuration = kwargs.pop("_configuration", None)
_visited_composed_classes = kwargs.pop("_visited_composed_classes", ())

self = super(OpenApiModel, cls).__new__(cls)

if args:
raise ApiTypeError(
"Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
"Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments."
% (
args,
self.__class__.__name__,
),
Expand All @@ -198,22 +226,24 @@ def _from_openapi_data(cls, *args, **kwargs): # noqa: E501
self._visited_composed_classes = _visited_composed_classes + (self.__class__,)

for var_name, var_value in kwargs.items():
if var_name not in self.attribute_map and \
self._configuration is not None and \
self._configuration.discard_unknown_keys and \
self.additional_properties_type is None:
if (
var_name not in self.attribute_map
and self._configuration is not None
and self._configuration.discard_unknown_keys
and self.additional_properties_type is None
):
# discard variable.
continue
setattr(self, var_name, var_value)
return self

required_properties = set([
'_data_store',
'_check_type',
'_spec_property_naming',
'_path_to_item',
'_configuration',
'_visited_composed_classes',
"_data_store",
"_check_type",
"_spec_property_naming",
"_path_to_item",
"_configuration",
"_visited_composed_classes",
])

@convert_js_args_to_python_args
Expand Down Expand Up @@ -258,15 +288,16 @@ def __init__(self, *args, **kwargs): # noqa: E501
escalation_type (bool, date, datetime, dict, float, int, list, str, none_type): Category that define internal proccess for labeling image queries * `STANDARD` - STANDARD * `NO_HUMAN_LABELING` - NO_HUMAN_LABELING. [optional] # noqa: E501
"""

_check_type = kwargs.pop('_check_type', True)
_spec_property_naming = kwargs.pop('_spec_property_naming', False)
_path_to_item = kwargs.pop('_path_to_item', ())
_configuration = kwargs.pop('_configuration', None)
_visited_composed_classes = kwargs.pop('_visited_composed_classes', ())
_check_type = kwargs.pop("_check_type", True)
_spec_property_naming = kwargs.pop("_spec_property_naming", False)
_path_to_item = kwargs.pop("_path_to_item", ())
_configuration = kwargs.pop("_configuration", None)
_visited_composed_classes = kwargs.pop("_visited_composed_classes", ())

if args:
raise ApiTypeError(
"Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
"Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments."
% (
args,
self.__class__.__name__,
),
Expand All @@ -282,13 +313,17 @@ def __init__(self, *args, **kwargs): # noqa: E501
self._visited_composed_classes = _visited_composed_classes + (self.__class__,)

for var_name, var_value in kwargs.items():
if var_name not in self.attribute_map and \
self._configuration is not None and \
self._configuration.discard_unknown_keys and \
self.additional_properties_type is None:
if (
var_name not in self.attribute_map
and self._configuration is not None
and self._configuration.discard_unknown_keys
and self.additional_properties_type is None
):
# discard variable.
continue
setattr(self, var_name, var_value)
if var_name in self.read_only_vars:
raise ApiAttributeError(f"`{var_name}` is a read-only attribute. Use `from_openapi_data` to instantiate "
f"class with read only attributes.")
raise ApiAttributeError(
f"`{var_name}` is a read-only attribute. Use `from_openapi_data` to instantiate "
"class with read only attributes."
)
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: 2024-12-09T18:29:17+00:00
# timestamp: 2024-12-10T01:13:13+00:00

from __future__ import annotations

Expand Down
7 changes: 6 additions & 1 deletion spec/public-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,11 @@ paths:
schema:
type: integer
description: Number of items to return per page.
- in: query
name: predictor_id
schema:
type: string
description: Optionally filter image queries by detector ID.
tags:
- image-queries
security:
Expand Down Expand Up @@ -1457,4 +1462,4 @@ servers:
- url: https://device.positronix.ai/device-api
description: Device Prod
- url: https://device.integ.positronix.ai/device-api
description: Device Integ
description: Device Integ
13 changes: 8 additions & 5 deletions src/groundlight/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import warnings
from functools import partial
from io import BufferedReader, BytesIO
from typing import Callable, List, Optional, Union
from typing import Any, Callable, List, Optional, Union

from groundlight_openapi_client import Configuration
from groundlight_openapi_client.api.detectors_api import DetectorsApi
Expand Down Expand Up @@ -528,7 +528,9 @@ def get_image_query(self, id: str) -> ImageQuery: # pylint: disable=redefined-b
iq = ImageQuery.parse_obj(obj.to_dict())
return self._fixup_image_query(iq)

def list_image_queries(self, page: int = 1, page_size: int = 10) -> PaginatedImageQueryList:
def list_image_queries(
self, page: int = 1, page_size: int = 10, detector_id: Union[str, None] = None
) -> PaginatedImageQueryList:
"""
List all image queries associated with your account, with pagination support.

Expand All @@ -550,9 +552,10 @@ def list_image_queries(self, page: int = 1, page_size: int = 10) -> PaginatedIma
:return: PaginatedImageQueryList containing the requested page of image queries and pagination metadata
like total count and links to next/previous pages.
"""
obj = self.image_queries_api.list_image_queries(
page=page, page_size=page_size, _request_timeout=DEFAULT_REQUEST_TIMEOUT
)
params: dict[str, Any] = {"page": page, "page_size": page_size, "_request_timeout": DEFAULT_REQUEST_TIMEOUT}
if detector_id:
params["detector_id"] = detector_id
obj = self.image_queries_api.list_image_queries(**params)
image_queries = PaginatedImageQueryList.parse_obj(obj.to_dict())
if image_queries.results is not None:
image_queries.results = [self._fixup_image_query(iq) for iq in image_queries.results]
Expand Down
14 changes: 14 additions & 0 deletions test/integration/test_groundlight.py
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,20 @@ def test_list_image_queries(gl: Groundlight):
assert is_valid_display_result(image_query.result)


def test_list_image_queries_with_filter(gl: Groundlight):
# We want a fresh detector so we know exactly what image queries are associated with it
detector = gl.create_detector(name=f"Test {datetime.utcnow()}", query="Is there a dog?")
image_query_yes = gl.ask_async(detector=detector.id, image="test/assets/dog.jpeg", human_review="NEVER")
image_query_no = gl.ask_async(detector=detector.id, image="test/assets/cat.jpeg", human_review="NEVER")
iq_ids = [image_query_yes.id, image_query_no.id]

image_queries = gl.list_image_queries(detector_id=detector.id)
num_image_queries = 2
assert len(image_queries.results) == num_image_queries
for image_query in image_queries.results:
assert image_query.id in iq_ids


def test_get_image_query(gl: Groundlight, image_query_yes: ImageQuery):
_image_query = gl.get_image_query(id=image_query_yes.id)
assert str(_image_query)
Expand Down
Loading