Skip to content

Commit 2c6d371

Browse files
authored
Add bounding boxes label enum (#390)
This PR adds a new bounding boxes label enum to the SDK. It will be used to correctly construct responses on the edge, like `Label` is used for binary mode. I also bumped the version number to do a new release with this enum. Due to compatibility issues between `datamodel-code-generator` and the version of pydantic in use, I also update `datamodel-code-generator`.
1 parent 55ece55 commit 2c6d371

File tree

10 files changed

+362
-13
lines changed

10 files changed

+362
-13
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ generate: install-generator ## Generate the SDK from our public openapi spec
2828
-o ./generated \
2929
--additional-properties=packageName=groundlight_openapi_client
3030
# strict-nullable makes nullable fields Optional in the generated Pydantic classes: https://github.com/koxudaxi/datamodel-code-generator/issues/327
31-
poetry run datamodel-codegen --input spec/public-api.yaml --output generated/model.py --strict-nullable --use-schema-description --output-model-type pydantic_v2.BaseModel --use-subclass-enum
31+
poetry run datamodel-codegen --input spec/public-api.yaml --output generated/model.py --strict-nullable --use-schema-description --output-model-type pydantic_v2.BaseModel --use-subclass-enum --output-datetime-class datetime
3232
poetry run black .
3333

3434
PYTEST=poetry run pytest -v

generated/.openapi-generator/FILES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ docs/BBoxGeometry.md
1010
docs/BBoxGeometryRequest.md
1111
docs/BinaryClassificationResult.md
1212
docs/BlankEnum.md
13+
docs/BoundingBoxLabelEnum.md
1314
docs/BoundingBoxModeConfiguration.md
1415
docs/BoundingBoxResult.md
1516
docs/ChannelEnum.md
@@ -96,6 +97,7 @@ groundlight_openapi_client/model/b_box_geometry.py
9697
groundlight_openapi_client/model/b_box_geometry_request.py
9798
groundlight_openapi_client/model/binary_classification_result.py
9899
groundlight_openapi_client/model/blank_enum.py
100+
groundlight_openapi_client/model/bounding_box_label_enum.py
99101
groundlight_openapi_client/model/bounding_box_mode_configuration.py
100102
groundlight_openapi_client/model/bounding_box_result.py
101103
groundlight_openapi_client/model/channel_enum.py

generated/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ Class | Method | HTTP request | Description
154154
- [BBoxGeometryRequest](docs/BBoxGeometryRequest.md)
155155
- [BinaryClassificationResult](docs/BinaryClassificationResult.md)
156156
- [BlankEnum](docs/BlankEnum.md)
157+
- [BoundingBoxLabelEnum](docs/BoundingBoxLabelEnum.md)
157158
- [BoundingBoxModeConfiguration](docs/BoundingBoxModeConfiguration.md)
158159
- [BoundingBoxResult](docs/BoundingBoxResult.md)
159160
- [ChannelEnum](docs/ChannelEnum.md)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# BoundingBoxLabelEnum
2+
3+
4+
## Properties
5+
Name | Type | Description | Notes
6+
------------ | ------------- | ------------- | -------------
7+
**value** | **str** | | must be one of ["NO_OBJECTS", "BOUNDING_BOX", "GREATER_THAN_MAX", "UNCLEAR", ]
8+
9+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
10+
11+
Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
"""
2+
Groundlight API
3+
4+
Groundlight makes it simple to understand images. You can easily create computer vision detectors just by describing what you want to know using natural language. # noqa: E501
5+
6+
The version of the OpenAPI document: 0.18.2
7+
8+
Generated by: https://openapi-generator.tech
9+
"""
10+
11+
import re # noqa: F401
12+
import sys # noqa: F401
13+
14+
from groundlight_openapi_client.model_utils import ( # noqa: F401
15+
ApiTypeError,
16+
ModelComposed,
17+
ModelNormal,
18+
ModelSimple,
19+
cached_property,
20+
change_keys_js_to_python,
21+
convert_js_args_to_python_args,
22+
date,
23+
datetime,
24+
file_type,
25+
none_type,
26+
validate_get_composed_info,
27+
OpenApiModel,
28+
)
29+
from groundlight_openapi_client.exceptions import ApiAttributeError
30+
31+
32+
class BoundingBoxLabelEnum(ModelSimple):
33+
"""NOTE: This class is auto generated by OpenAPI Generator.
34+
Ref: https://openapi-generator.tech
35+
36+
Do not edit the class manually.
37+
38+
Attributes:
39+
allowed_values (dict): The key is the tuple path to the attribute
40+
and the for var_name this is (var_name,). The value is a dict
41+
with a capitalized key describing the allowed value and an allowed
42+
value. These dicts store the allowed enum values.
43+
validations (dict): The key is the tuple path to the attribute
44+
and the for var_name this is (var_name,). The value is a dict
45+
that stores validations for max_length, min_length, max_items,
46+
min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum,
47+
inclusive_minimum, and regex.
48+
additional_properties_type (tuple): A tuple of classes accepted
49+
as additional properties values.
50+
"""
51+
52+
allowed_values = {
53+
("value",): {
54+
"NO_OBJECTS": "NO_OBJECTS",
55+
"BOUNDING_BOX": "BOUNDING_BOX",
56+
"GREATER_THAN_MAX": "GREATER_THAN_MAX",
57+
"UNCLEAR": "UNCLEAR",
58+
},
59+
}
60+
61+
validations = {}
62+
63+
additional_properties_type = None
64+
65+
_nullable = False
66+
67+
@cached_property
68+
def openapi_types():
69+
"""
70+
This must be a method because a model may have properties that are
71+
of type self, this must run after the class is loaded
72+
73+
Returns
74+
openapi_types (dict): The key is attribute name
75+
and the value is attribute type.
76+
"""
77+
return {
78+
"value": (str,),
79+
}
80+
81+
@cached_property
82+
def discriminator():
83+
return None
84+
85+
attribute_map = {}
86+
87+
read_only_vars = set()
88+
89+
_composed_schemas = None
90+
91+
required_properties = set([
92+
"_data_store",
93+
"_check_type",
94+
"_spec_property_naming",
95+
"_path_to_item",
96+
"_configuration",
97+
"_visited_composed_classes",
98+
])
99+
100+
@convert_js_args_to_python_args
101+
def __init__(self, *args, **kwargs):
102+
"""BoundingBoxLabelEnum - a model defined in OpenAPI
103+
104+
Note that value can be passed either in args or in kwargs, but not in both.
105+
106+
Args:
107+
args[0] (str):, must be one of ["NO_OBJECTS", "BOUNDING_BOX", "GREATER_THAN_MAX", "UNCLEAR", ] # noqa: E501
108+
109+
Keyword Args:
110+
value (str):, must be one of ["NO_OBJECTS", "BOUNDING_BOX", "GREATER_THAN_MAX", "UNCLEAR", ] # noqa: E501
111+
_check_type (bool): if True, values for parameters in openapi_types
112+
will be type checked and a TypeError will be
113+
raised if the wrong type is input.
114+
Defaults to True
115+
_path_to_item (tuple/list): This is a list of keys or values to
116+
drill down to the model in received_data
117+
when deserializing a response
118+
_spec_property_naming (bool): True if the variable names in the input data
119+
are serialized names, as specified in the OpenAPI document.
120+
False if the variable names in the input data
121+
are pythonic names, e.g. snake case (default)
122+
_configuration (Configuration): the instance to use when
123+
deserializing a file_type parameter.
124+
If passed, type conversion is attempted
125+
If omitted no type conversion is done.
126+
_visited_composed_classes (tuple): This stores a tuple of
127+
classes that we have traveled through so that
128+
if we see that class again we will not use its
129+
discriminator again.
130+
When traveling through a discriminator, the
131+
composed schema that is
132+
is traveled through is added to this set.
133+
For example if Animal has a discriminator
134+
petType and we pass in "Dog", and the class Dog
135+
allOf includes Animal, we move through Animal
136+
once using the discriminator, and pick Dog.
137+
Then in Dog, we will make an instance of the
138+
Animal class but this time we won't travel
139+
through its discriminator because we passed in
140+
_visited_composed_classes = (Animal,)
141+
"""
142+
# required up here when default value is not given
143+
_path_to_item = kwargs.pop("_path_to_item", ())
144+
145+
if "value" in kwargs:
146+
value = kwargs.pop("value")
147+
elif args:
148+
args = list(args)
149+
value = args.pop(0)
150+
else:
151+
raise ApiTypeError(
152+
"value is required, but not passed in args or kwargs and doesn't have default",
153+
path_to_item=_path_to_item,
154+
valid_classes=(self.__class__,),
155+
)
156+
157+
_check_type = kwargs.pop("_check_type", True)
158+
_spec_property_naming = kwargs.pop("_spec_property_naming", False)
159+
_configuration = kwargs.pop("_configuration", None)
160+
_visited_composed_classes = kwargs.pop("_visited_composed_classes", ())
161+
162+
if args:
163+
raise ApiTypeError(
164+
"Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments."
165+
% (
166+
args,
167+
self.__class__.__name__,
168+
),
169+
path_to_item=_path_to_item,
170+
valid_classes=(self.__class__,),
171+
)
172+
173+
self._data_store = {}
174+
self._check_type = _check_type
175+
self._spec_property_naming = _spec_property_naming
176+
self._path_to_item = _path_to_item
177+
self._configuration = _configuration
178+
self._visited_composed_classes = _visited_composed_classes + (self.__class__,)
179+
self.value = value
180+
if kwargs:
181+
raise ApiTypeError(
182+
"Invalid named arguments=%s passed to %s. Remove those invalid named arguments."
183+
% (
184+
kwargs,
185+
self.__class__.__name__,
186+
),
187+
path_to_item=_path_to_item,
188+
valid_classes=(self.__class__,),
189+
)
190+
191+
@classmethod
192+
@convert_js_args_to_python_args
193+
def _from_openapi_data(cls, *args, **kwargs):
194+
"""BoundingBoxLabelEnum - a model defined in OpenAPI
195+
196+
Note that value can be passed either in args or in kwargs, but not in both.
197+
198+
Args:
199+
args[0] (str):, must be one of ["NO_OBJECTS", "BOUNDING_BOX", "GREATER_THAN_MAX", "UNCLEAR", ] # noqa: E501
200+
201+
Keyword Args:
202+
value (str):, must be one of ["NO_OBJECTS", "BOUNDING_BOX", "GREATER_THAN_MAX", "UNCLEAR", ] # noqa: E501
203+
_check_type (bool): if True, values for parameters in openapi_types
204+
will be type checked and a TypeError will be
205+
raised if the wrong type is input.
206+
Defaults to True
207+
_path_to_item (tuple/list): This is a list of keys or values to
208+
drill down to the model in received_data
209+
when deserializing a response
210+
_spec_property_naming (bool): True if the variable names in the input data
211+
are serialized names, as specified in the OpenAPI document.
212+
False if the variable names in the input data
213+
are pythonic names, e.g. snake case (default)
214+
_configuration (Configuration): the instance to use when
215+
deserializing a file_type parameter.
216+
If passed, type conversion is attempted
217+
If omitted no type conversion is done.
218+
_visited_composed_classes (tuple): This stores a tuple of
219+
classes that we have traveled through so that
220+
if we see that class again we will not use its
221+
discriminator again.
222+
When traveling through a discriminator, the
223+
composed schema that is
224+
is traveled through is added to this set.
225+
For example if Animal has a discriminator
226+
petType and we pass in "Dog", and the class Dog
227+
allOf includes Animal, we move through Animal
228+
once using the discriminator, and pick Dog.
229+
Then in Dog, we will make an instance of the
230+
Animal class but this time we won't travel
231+
through its discriminator because we passed in
232+
_visited_composed_classes = (Animal,)
233+
"""
234+
# required up here when default value is not given
235+
_path_to_item = kwargs.pop("_path_to_item", ())
236+
237+
self = super(OpenApiModel, cls).__new__(cls)
238+
239+
if "value" in kwargs:
240+
value = kwargs.pop("value")
241+
elif args:
242+
args = list(args)
243+
value = args.pop(0)
244+
else:
245+
raise ApiTypeError(
246+
"value is required, but not passed in args or kwargs and doesn't have default",
247+
path_to_item=_path_to_item,
248+
valid_classes=(self.__class__,),
249+
)
250+
251+
_check_type = kwargs.pop("_check_type", True)
252+
_spec_property_naming = kwargs.pop("_spec_property_naming", False)
253+
_configuration = kwargs.pop("_configuration", None)
254+
_visited_composed_classes = kwargs.pop("_visited_composed_classes", ())
255+
256+
if args:
257+
raise ApiTypeError(
258+
"Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments."
259+
% (
260+
args,
261+
self.__class__.__name__,
262+
),
263+
path_to_item=_path_to_item,
264+
valid_classes=(self.__class__,),
265+
)
266+
267+
self._data_store = {}
268+
self._check_type = _check_type
269+
self._spec_property_naming = _spec_property_naming
270+
self._path_to_item = _path_to_item
271+
self._configuration = _configuration
272+
self._visited_composed_classes = _visited_composed_classes + (self.__class__,)
273+
self.value = value
274+
if kwargs:
275+
raise ApiTypeError(
276+
"Invalid named arguments=%s passed to %s. Remove those invalid named arguments."
277+
% (
278+
kwargs,
279+
self.__class__.__name__,
280+
),
281+
path_to_item=_path_to_item,
282+
valid_classes=(self.__class__,),
283+
)
284+
285+
return self

generated/groundlight_openapi_client/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from groundlight_openapi_client.model.b_box_geometry_request import BBoxGeometryRequest
1919
from groundlight_openapi_client.model.binary_classification_result import BinaryClassificationResult
2020
from groundlight_openapi_client.model.blank_enum import BlankEnum
21+
from groundlight_openapi_client.model.bounding_box_label_enum import BoundingBoxLabelEnum
2122
from groundlight_openapi_client.model.bounding_box_mode_configuration import BoundingBoxModeConfiguration
2223
from groundlight_openapi_client.model.bounding_box_result import BoundingBoxResult
2324
from groundlight_openapi_client.model.channel_enum import ChannelEnum

generated/model.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# generated by datamodel-codegen:
22
# filename: public-api.yaml
3-
# timestamp: 2025-08-28T18:43:04+00:00
3+
# timestamp: 2025-10-20T17:36:39+00:00
44

55
from __future__ import annotations
66

@@ -324,6 +324,13 @@ class VerbEnum(str, Enum):
324324
NO_QUERIES = "NO_QUERIES"
325325

326326

327+
class BoundingBoxLabelEnum(str, Enum):
328+
NO_OBJECTS = "NO_OBJECTS"
329+
BOUNDING_BOX = "BOUNDING_BOX"
330+
GREATER_THAN_MAX = "GREATER_THAN_MAX"
331+
UNCLEAR = "UNCLEAR"
332+
333+
327334
class Source(str, Enum):
328335
STILL_PROCESSING = "STILL_PROCESSING"
329336
CLOUD = "CLOUD"
@@ -479,16 +486,16 @@ class LabelValueRequest(BaseModel):
479486

480487

481488
class PaginatedDetectorList(BaseModel):
482-
count: int = Field(..., example=123)
483-
next: Optional[AnyUrl] = Field(None, example="http://api.example.org/accounts/?page=4")
484-
previous: Optional[AnyUrl] = Field(None, example="http://api.example.org/accounts/?page=2")
489+
count: int = Field(..., examples=[123])
490+
next: Optional[AnyUrl] = Field(None, examples=["http://api.example.org/accounts/?page=4"])
491+
previous: Optional[AnyUrl] = Field(None, examples=["http://api.example.org/accounts/?page=2"])
485492
results: List[Detector]
486493

487494

488495
class PaginatedImageQueryList(BaseModel):
489-
count: int = Field(..., example=123)
490-
next: Optional[AnyUrl] = Field(None, example="http://api.example.org/accounts/?page=4")
491-
previous: Optional[AnyUrl] = Field(None, example="http://api.example.org/accounts/?page=2")
496+
count: int = Field(..., examples=[123])
497+
next: Optional[AnyUrl] = Field(None, examples=["http://api.example.org/accounts/?page=4"])
498+
previous: Optional[AnyUrl] = Field(None, examples=["http://api.example.org/accounts/?page=2"])
492499
results: List[ImageQuery]
493500

494501

@@ -545,7 +552,7 @@ class RuleRequest(BaseModel):
545552

546553

547554
class PaginatedRuleList(BaseModel):
548-
count: int = Field(..., example=123)
549-
next: Optional[AnyUrl] = Field(None, example="http://api.example.org/accounts/?page=4")
550-
previous: Optional[AnyUrl] = Field(None, example="http://api.example.org/accounts/?page=2")
555+
count: int = Field(..., examples=[123])
556+
next: Optional[AnyUrl] = Field(None, examples=["http://api.example.org/accounts/?page=4"])
557+
previous: Optional[AnyUrl] = Field(None, examples=["http://api.example.org/accounts/?page=2"])
551558
results: List[Rule]

0 commit comments

Comments
 (0)