Skip to content

Commit 96a5961

Browse files
committed
Added retries on form data fail and GenAI
1 parent 974b11b commit 96a5961

File tree

7 files changed

+51
-19
lines changed

7 files changed

+51
-19
lines changed

pytest.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ minversion = 3.7
33
log_cli=true
44
python_files = test_*.py
55
;pytest_plugins = ['pytest_profiling']
6-
addopts = -n auto --dist=loadscope
6+
;addopts = -n auto --dist=loadscope
77

src/superannotate/lib/app/interface/sdk_interface.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
"Tiled",
8080
"Other",
8181
"PointCloud",
82-
"CustomEditor",
82+
"GenAI",
8383
]
8484

8585
ANNOTATION_STATUS = Literal[

src/superannotate/lib/core/entities/classes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class AttributeGroup(TimedBaseModel):
7373
group_type: Optional[GroupTypeEnum]
7474
class_id: Optional[StrictInt]
7575
name: Optional[StrictStr]
76+
required: bool = Field(default=False)
7677
attributes: Optional[List[Attribute]]
7778
default_value: Any
7879

src/superannotate/lib/core/enums.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class ProjectType(BaseTitledEnum):
9393
TILED = "Tiled", 5
9494
OTHER = "Other", 6
9595
POINT_CLOUD = "PointCloud", 7
96-
CUSTOM_EDITOR = "CustomEditor", 8
96+
GEN_AI = "GenAI", 8
9797
UNSUPPORTED_TYPE_1 = "UnsupportedType", 9
9898
UNSUPPORTED_TYPE_2 = "UnsupportedType", 10
9999

src/superannotate/lib/infrastructure/services/http_client.py

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
import io
23
import json
34
import logging
45
import platform
@@ -13,7 +14,6 @@
1314

1415
import aiohttp
1516
import requests
16-
from aiohttp.client_exceptions import ClientError
1717
from lib.core.exceptions import AppException
1818
from lib.core.service_types import ServiceResponse
1919
from lib.core.serviceproviders import BaseClient
@@ -229,19 +229,39 @@ class AIOHttpSession(aiohttp.ClientSession):
229229
RETRY_LIMIT = 3
230230
BACKOFF_FACTOR = 0.3
231231

232-
async def request(self, *args, **kwargs) -> aiohttp.ClientResponse:
233-
attempts = self.RETRY_LIMIT
234-
delay = 0
235-
for _ in range(attempts):
236-
delay += self.BACKOFF_FACTOR
237-
attempts -= 1
238-
try:
239-
response = await super()._request(*args, **kwargs)
240-
except ClientError:
241-
if not attempts:
242-
raise
232+
class AIOHttpSession(aiohttp.ClientSession):
233+
RETRY_STATUS_CODES = [401, 403, 502, 503, 504]
234+
RETRY_LIMIT = 3
235+
BACKOFF_FACTOR = 0.3
236+
237+
@staticmethod
238+
def _copy_form_data(data: aiohttp.FormData) -> aiohttp.FormData:
239+
form_data = aiohttp.FormData(quote_fields=False)
240+
for field in data._fields: # noqa
241+
if isinstance(field[2], io.IOBase):
242+
field[2].seek(0)
243+
form_data.add_field(
244+
value=field[2],
245+
content_type=field[1].get("Content-Type", ""),
246+
**field[0],
247+
)
248+
return form_data
249+
250+
async def request(self, *args, **kwargs) -> aiohttp.ClientResponse:
251+
attempts = self.RETRY_LIMIT
252+
delay = 0
253+
for _ in range(attempts):
254+
delay += self.BACKOFF_FACTOR
255+
try:
256+
response = await super()._request(*args, **kwargs)
257+
if attempts <= 1 or response.status not in self.RETRY_STATUS_CODES:
258+
return response
259+
except (aiohttp.ClientError, RuntimeError) as e:
260+
if attempts <= 1:
261+
raise
262+
if isinstance(e, RuntimeError):
263+
data = kwargs["data"]
264+
if isinstance(data, aiohttp.FormData):
265+
kwargs["data"] = self._copy_form_data(data)
266+
attempts -= 1
243267
await asyncio.sleep(delay)
244-
continue
245-
if response.status not in self.RETRY_STATUS_CODES or not attempts:
246-
return response
247-
await asyncio.sleep(delay)

tests/integration/classes/test_create_annotation_class.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def test_create_annotation_class_with_attr_and_default_value(self):
4444
attribute_groups=[
4545
{
4646
"name": "test",
47+
"required": False,
4748
"attributes": [{"name": "Car"}, {"name": "Track"}, {"name": "Bus"}],
4849
"default_value": "Bus",
4950
}

tests/integration/projects/test_basic_project.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@
1111
sa = SAClient()
1212

1313

14+
class TestGenAIProjectBasic(BaseTestCase):
15+
PROJECT_NAME = "TestGenAICreate"
16+
PROJECT_TYPE = "GenAI"
17+
PROJECT_DESCRIPTION = "DESCRIPTION"
18+
19+
def test_search(self):
20+
projects = sa.search_projects(self.PROJECT_NAME, return_metadata=True)
21+
assert projects
22+
23+
1424
class TestProjectBasic(BaseTestCase):
1525
PROJECT_NAME = "TestWorkflowGet"
1626
PROJECT_TYPE = "Vector"

0 commit comments

Comments
 (0)