Skip to content

Commit 8c75a04

Browse files
committed
Fixed streamed data chinks handeling
1 parent 714ee85 commit 8c75a04

File tree

10 files changed

+79
-39
lines changed

10 files changed

+79
-39
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2850,7 +2850,7 @@ def invite_contributors_to_team(
28502850

28512851
@Trackable
28522852
@validate_arguments
2853-
def get_annotations(project: NotEmptyStr, items: Optional[List[NotEmptyStr]]):
2853+
def get_annotations(project: NotEmptyStr, items: Optional[List[NotEmptyStr]] = None):
28542854
"""Returns annotations for the given list of items.
28552855
28562856
:param project: project name

src/superannotate/lib/core/reporter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ def log_debug(self, value: str):
4646
self.debug_messages.append(value)
4747

4848
def start_progress(
49-
self, iterations: Union[int, range], description: str = "Processing"
49+
self, iterations: Union[int, range], description: str = "Processing", disable=False
5050
):
51-
self.progress_bar = self.get_progress_bar(iterations, description)
51+
self.progress_bar = self.get_progress_bar(iterations, description, disable)
5252

5353
@staticmethod
5454
def get_progress_bar(

src/superannotate/lib/core/usecases/annotations.py

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
import boto3
1111
import lib.core as constances
12+
from lib.core.conditions import Condition
13+
from lib.core.conditions import CONDITION_EQ as EQ
1214
from lib.core.data_handlers import ChainedAnnotationHandlers
1315
from lib.core.data_handlers import DocumentTagHandler
1416
from lib.core.data_handlers import LastActionHandler
@@ -494,14 +496,18 @@ def __init__(
494496
reporter: Reporter,
495497
project: ProjectEntity,
496498
folder: FolderEntity,
499+
images: BaseManageableRepository,
497500
item_names: Optional[List[str]],
498-
backend_service_provider: SuerannotateServiceProvider
501+
backend_service_provider: SuerannotateServiceProvider,
502+
show_process: bool = True
499503
):
500504
super().__init__(reporter)
501505
self._project = project
502506
self._folder = folder
507+
self._images = images
503508
self._item_names = item_names
504509
self._client = backend_service_provider
510+
self._show_process = show_process
505511

506512
def validate_item_names(self):
507513
if self._item_names:
@@ -512,27 +518,36 @@ def validate_item_names(self):
512518
f"Dropping duplicates. Found {len_unique_items}/{len_items} unique items."
513519
)
514520
self._item_names = item_names
521+
else:
522+
condition = (
523+
Condition("team_id", self._project.team_id, EQ)
524+
& Condition("project_id", self._project.uuid, EQ)
525+
& Condition("folder_id", self._folder.uuid, EQ)
526+
)
527+
528+
self._item_names = [item.name for item in self._images.get_all(condition)]
515529

516530
def execute(self):
517-
items_count = len(self._item_names)
518-
self.reporter.log_info(
519-
f"Getting {items_count} annotations from "
520-
f"{self._project.name}{f'/{self._folder.name}' if self._folder else ''}."
521-
)
522-
self.reporter.start_progress(items_count)
523-
annotations = self._client.get_annotations(
524-
team_id=self._project.team_id,
525-
project_id=self._project.uuid,
526-
folder_id=self._folder.uuid,
527-
items=self._item_names,
528-
reporter=self.reporter
529-
)
530-
received_items_count = len(annotations)
531-
if items_count > received_items_count:
532-
self.reporter.log_warning(
533-
f"Could not find annotations for {items_count - received_items_count}/{items_count} items."
531+
if self.is_valid():
532+
items_count = len(self._item_names)
533+
self.reporter.log_info(
534+
f"Getting {items_count} annotations from "
535+
f"{self._project.name}{f'/{self._folder.name}' if self._folder else ''}."
534536
)
535-
self._response.data = annotations
537+
self.reporter.start_progress(items_count, disable=not self._show_process)
538+
annotations = self._client.get_annotations(
539+
team_id=self._project.team_id,
540+
project_id=self._project.uuid,
541+
folder_id=self._folder.uuid,
542+
items=self._item_names,
543+
reporter=self.reporter
544+
)
545+
received_items_count = len(annotations)
546+
if items_count > received_items_count:
547+
self.reporter.log_warning(
548+
f"Could not find annotations for {items_count - received_items_count}/{items_count} items."
549+
)
550+
self._response.data = annotations
536551
return self._response
537552

538553

@@ -542,13 +557,15 @@ def __init__(
542557
reporter: Reporter,
543558
project: ProjectEntity,
544559
folder: FolderEntity,
560+
images: BaseManageableRepository,
545561
video_name: str,
546562
fps: int,
547563
backend_service_provider: SuerannotateServiceProvider
548564
):
549565
super().__init__(reporter)
550566
self._project = project
551567
self._folder = folder
568+
self._images = images
552569
self._video_name = video_name
553570
self._fps = fps
554571
self._client = backend_service_provider
@@ -558,8 +575,10 @@ def execute(self):
558575
reporter=self.reporter,
559576
project=self._project,
560577
folder=self._folder,
578+
images=self._images,
561579
item_names=[self._video_name],
562-
backend_service_provider=self._client
580+
backend_service_provider=self._client,
581+
show_process=False
563582
).execute()
564583
generator = VideoFrameGenerator(response.data[0], fps=self._fps)
565584
self.reporter.log_info(f"Getting annotations for {generator.frames_count} frames from {self._video_name}.")

src/superannotate/lib/core/usecases/images.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1928,8 +1928,8 @@ def execute(self):
19281928
project=self._project,
19291929
folder=self._folder,
19301930
attachments=self._attachments[
1931-
i : i + self.CHUNK_SIZE
1932-
], # noqa: E203
1931+
i : i + self.CHUNK_SIZE # noqa: E203
1932+
],
19331933
backend_service_provider=self._backend_service,
19341934
annotation_status=self._annotation_status,
19351935
upload_state_code=self._upload_state_code,

src/superannotate/lib/infrastructure/controller.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@ def __init__(self, config_path: str = None, token: str = None):
7474
self.initialize_backend_client()
7575

7676
def retrieve_configs(self, path: Path, raise_exception=True):
77+
7778
token, backend_url, ssl_verify = None, None, None
78-
if not path.is_file() or not os.access(path, os.R_OK):
79+
if not Path(path).is_file() or not os.access(path, os.R_OK):
7980
if raise_exception:
8081
raise AppException(
8182
f"SuperAnnotate config file {str(path)} not found."
@@ -1626,6 +1627,7 @@ def get_annotations(self, project_name: str, folder_name: str, item_names: List[
16261627
reporter=self.default_reporter,
16271628
project=project,
16281629
folder=folder,
1630+
images=self.images,
16291631
item_names=item_names,
16301632
backend_service_provider=self.backend_client
16311633
)
@@ -1639,6 +1641,7 @@ def get_annotations_per_frame(self, project_name: str, folder_name: str, video_n
16391641
reporter=self.default_reporter,
16401642
project=project,
16411643
folder=folder,
1644+
images=self.images,
16421645
video_name=video_name,
16431646
fps=fps,
16441647
backend_service_provider=self.backend_client

src/superannotate/lib/infrastructure/services.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ class SuperannotateBackendService(BaseBackendService):
176176
DEFAULT_CHUNK_SIZE = 1000
177177

178178
URL_USERS = "users"
179+
URL_LIST_ALL_IMAGES = "/images/getImagesWithAnnotationPaths"
179180
URL_LIST_PROJECTS = "projects"
180181
URL_FOLDERS_IMAGES = "images-folders"
181182
URL_CREATE_PROJECT = "project"

src/superannotate/lib/infrastructure/stream_data_handler.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,21 @@ async def fetch(self, method: str, session: aiohttp.ClientSession, url: str, dat
2525
params: dict = None):
2626
response = await session._request(method, url, json=data, params=params)
2727
buffer = b""
28-
async for line in response.content:
28+
async for line in response.content.iter_any():
2929
slices = line.split(self.DELIMITER)
3030
if len(slices) == 1:
3131
buffer += slices[0]
3232
continue
3333
elif slices[0]:
3434
self._annotations.append(json.loads(buffer + slices[0]))
35+
self._reporter.update_progress()
3536
for data in slices[1:-1]:
3637
self._annotations.append(json.loads(data))
38+
self._reporter.update_progress()
3739
buffer = slices[-1]
3840
if buffer:
3941
self._annotations.append(json.loads(buffer))
42+
self._reporter.update_progress()
4043
return self._annotations
4144

4245
async def get_data(
@@ -54,9 +57,8 @@ async def get_data(
5457

5558
if chunk_size:
5659
for i in range(0, len(data), chunk_size):
57-
await self.fetch(method, session, url, map_function(data[i:i + chunk_size]), params=params)
58-
self._reporter.update_progress(chunk_size)
60+
data_to_process = data[i:i + chunk_size]
61+
await self.fetch(method, session, url, map_function(data_to_process), params=params)
5962
else:
6063
await self.fetch(method, session, url, map_function(data), params=params)
61-
self._reporter.update_progress(len(data))
6264
return self._annotations

tests/integration/annotations/test_get_annotations.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
from pathlib import Path
1+
import json
22
import os
3+
from pathlib import Path
34
from typing import List
4-
import json
5-
import pytest
65

7-
import src.superannotate as sa
6+
import pytest
87
from pydantic import parse_obj_as
98
from superannotate_schemas.schemas.internal import VectorAnnotation
9+
10+
import src.superannotate as sa
1011
from tests.integration.base import BaseTestCase
1112

1213

@@ -40,3 +41,18 @@ def test_get_annotations(self):
4041
annotation_data = json.load(annotation_file)
4142
self.assertEqual(len(annotation_data["instances"]), len(annotations[0]["instances"]))
4243
parse_obj_as(List[VectorAnnotation], annotations)
44+
45+
@pytest.mark.flaky(reruns=3)
46+
def test_get_annotations_all(self):
47+
sa.init()
48+
sa.upload_images_from_folder_to_project(
49+
self.PROJECT_NAME, self.folder_path, annotation_status="InProgress"
50+
)
51+
sa.create_annotation_classes_from_classes_json(
52+
self.PROJECT_NAME, f"{self.folder_path}/classes/classes.json"
53+
)
54+
_, _, _ = sa.upload_annotations_from_folder_to_project(
55+
self.PROJECT_NAME, self.folder_path
56+
)
57+
annotations = sa.get_annotations(f"{self.PROJECT_NAME}")
58+
self.assertEqual(len(annotations), 4)

tests/integration/test_df_processing.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def folder_path(self):
1919
)
2020

2121
def test_filter_instances(self):
22-
df = sa.aggregate_annotations_as_df(self.folder_path,self.PROJECT_TYPE)
22+
df = sa.aggregate_annotations_as_df(self.folder_path, self.PROJECT_TYPE)
2323
df = df[~(df.duplicated(["instanceId", "imageName"]))]
2424
df = df[df.duplicated(["trackingId"], False) & df["trackingId"].notnull()]
2525
self.assertEqual(len(df), 2)
@@ -28,6 +28,7 @@ def test_filter_instances(self):
2828
{"example_image_1.jpg", "example_image_2.jpg"},
2929
)
3030

31+
3132
class TestDFWithTagInstace(BaseTestCase):
3233
PROJECT_TYPE = "Vector"
3334
TEST_FOLDER_PATH = "data_set/sample_project_vector_with_tag"
@@ -38,13 +39,11 @@ def folder_path(self):
3839
Path(os.path.join(dirname(dirname(__file__)), self.TEST_FOLDER_PATH))
3940
)
4041

41-
4242
def test_filter_instances(self):
4343
df = sa.aggregate_annotations_as_df(self.folder_path, self.PROJECT_TYPE)
4444
self.assertEqual(df.iloc[0]["type"], "tag")
4545

4646

47-
4847
class TestClassDistibutionWithTagInstance(BaseTestCase):
4948
PROJECT_TYPE = "Vector"
5049
EXPORT_ROOT_PATH = "data_set"
@@ -57,6 +56,6 @@ def root_path(self):
5756
)
5857

5958
def test_filter_instances(self):
60-
df = sa.class_distribution(export_root=self.root_path,project_names=[self.PROJECT_NAME])
59+
df = sa.class_distribution(export_root=self.root_path, project_names=[self.PROJECT_NAME])
6160
self.assertEqual(df.iloc[0]['count'], 1)
62-
self.assertEqual(df.iloc[0]['className'], "Weather")
61+
self.assertEqual(df.iloc[0]['className'], "Weather")

tests/profiling/profiling.py

Whitespace-only changes.

0 commit comments

Comments
 (0)