88from typing import Tuple
99
1010import boto3
11+ from superannotate_schemas .validators import AnnotationValidators
12+
1113import lib .core as constances
12- from lib .core .conditions import Condition
1314from lib .core .conditions import CONDITION_EQ as EQ
15+ from lib .core .conditions import Condition
1416from lib .core .data_handlers import ChainedAnnotationHandlers
1517from lib .core .data_handlers import DocumentTagHandler
1618from lib .core .data_handlers import LastActionHandler
3234from lib .core .usecases .images import ValidateAnnotationUseCase
3335from lib .core .video_convertor import VideoFrameGenerator
3436from superannotate .logger import get_default_logger
35- from superannotate_schemas .validators import AnnotationValidators
36-
3737
3838logger = get_default_logger ()
3939
@@ -45,20 +45,20 @@ class UploadAnnotationsUseCase(BaseReportableUseCae):
4545 ImageInfo = namedtuple ("ImageInfo" , ["path" , "name" , "id" ])
4646
4747 def __init__ (
48- self ,
49- reporter : Reporter ,
50- project : ProjectEntity ,
51- folder : FolderEntity ,
52- team : TeamEntity ,
53- images : BaseManageableRepository ,
54- annotation_classes : List [AnnotationClassEntity ],
55- annotation_paths : List [str ],
56- backend_service_provider : SuerannotateServiceProvider ,
57- templates : List [dict ],
58- validators : AnnotationValidators ,
59- pre_annotation : bool = False ,
60- client_s3_bucket = None ,
61- folder_path : str = None ,
48+ self ,
49+ reporter : Reporter ,
50+ project : ProjectEntity ,
51+ folder : FolderEntity ,
52+ team : TeamEntity ,
53+ images : BaseManageableRepository ,
54+ annotation_classes : List [AnnotationClassEntity ],
55+ annotation_paths : List [str ],
56+ backend_service_provider : SuerannotateServiceProvider ,
57+ templates : List [dict ],
58+ validators : AnnotationValidators ,
59+ pre_annotation : bool = False ,
60+ client_s3_bucket = None ,
61+ folder_path : str = None ,
6262 ):
6363 super ().__init__ (reporter )
6464 self ._project = project
@@ -82,8 +82,8 @@ def __init__(
8282 @property
8383 def annotation_postfix (self ):
8484 if self ._project .project_type in (
85- constances .ProjectType .VIDEO .value ,
86- constances .ProjectType .DOCUMENT .value ,
85+ constances .ProjectType .VIDEO .value ,
86+ constances .ProjectType .DOCUMENT .value ,
8787 ):
8888 return constances .ATTACHED_VIDEO_ANNOTATION_POSTFIX
8989 elif self ._project .project_type == constances .ProjectType .VECTOR .value :
@@ -95,8 +95,8 @@ def annotation_postfix(self):
9595 def extract_name (value : str ):
9696 return os .path .basename (
9797 value .replace (constances .PIXEL_ANNOTATION_POSTFIX , "" )
98- .replace (constances .VECTOR_ANNOTATION_POSTFIX , "" )
99- .replace (constances .ATTACHED_VIDEO_ANNOTATION_POSTFIX , "" ),
98+ .replace (constances .VECTOR_ANNOTATION_POSTFIX , "" )
99+ .replace (constances .ATTACHED_VIDEO_ANNOTATION_POSTFIX , "" ),
100100 )
101101
102102 @property
@@ -120,8 +120,8 @@ def annotations_to_upload(self):
120120 folder_id = self ._folder .uuid ,
121121 images = [image .name for image in images_detail ],
122122 )
123- .execute ()
124- .data
123+ .execute ()
124+ .data
125125 )
126126 for image_data in images_data :
127127 for idx , detail in enumerate (images_detail ):
@@ -151,7 +151,7 @@ def missing_annotations(self):
151151 return self ._missing_annotations
152152
153153 def get_annotation_upload_data (
154- self , image_ids : List [int ]
154+ self , image_ids : List [int ]
155155 ) -> UploadAnnotationAuthData :
156156 if self ._pre_annotation :
157157 function = self ._backend_service .get_pre_annotation_upload_data
@@ -167,12 +167,12 @@ def get_annotation_upload_data(
167167 return response .data
168168
169169 def _upload_annotation (
170- self ,
171- image_id : int ,
172- image_name : str ,
173- upload_data : UploadAnnotationAuthData ,
174- path : str ,
175- bucket ,
170+ self ,
171+ image_id : int ,
172+ image_name : str ,
173+ upload_data : UploadAnnotationAuthData ,
174+ path : str ,
175+ bucket ,
176176 ):
177177 try :
178178 self .reporter .disable_warnings ()
@@ -256,8 +256,8 @@ def execute(self):
256256 )
257257 for step in iterations_range :
258258 annotations_to_upload = self .annotations_to_upload [
259- step : step + self .AUTH_DATA_CHUNK_SIZE # noqa: E203
260- ]
259+ step : step + self .AUTH_DATA_CHUNK_SIZE # noqa: E203
260+ ]
261261 upload_data = self .get_annotation_upload_data (
262262 [int (image .id ) for image in annotations_to_upload ]
263263 )
@@ -270,11 +270,11 @@ def execute(self):
270270 }
271271 # dummy progress
272272 for _ in range (
273- len (annotations_to_upload ) - len (upload_data .images )
273+ len (annotations_to_upload ) - len (upload_data .images )
274274 ):
275275 self .reporter .update_progress ()
276276 with concurrent .futures .ThreadPoolExecutor (
277- max_workers = self .MAX_WORKERS
277+ max_workers = self .MAX_WORKERS
278278 ) as executor :
279279 results = [
280280 executor .submit (
@@ -306,25 +306,25 @@ def execute(self):
306306
307307class UploadAnnotationUseCase (BaseReportableUseCae ):
308308 def __init__ (
309- self ,
310- project : ProjectEntity ,
311- folder : FolderEntity ,
312- image : ImageEntity ,
313- images : BaseManageableRepository ,
314- team : TeamEntity ,
315- annotation_classes : List [AnnotationClassEntity ],
316- backend_service_provider : SuerannotateServiceProvider ,
317- reporter : Reporter ,
318- templates : List [dict ],
319- validators : AnnotationValidators ,
320- annotation_upload_data : UploadAnnotationAuthData = None ,
321- annotations : dict = None ,
322- s3_bucket = None ,
323- client_s3_bucket = None ,
324- mask = None ,
325- verbose : bool = True ,
326- annotation_path : str = None ,
327- pass_validation : bool = False ,
309+ self ,
310+ project : ProjectEntity ,
311+ folder : FolderEntity ,
312+ image : ImageEntity ,
313+ images : BaseManageableRepository ,
314+ team : TeamEntity ,
315+ annotation_classes : List [AnnotationClassEntity ],
316+ backend_service_provider : SuerannotateServiceProvider ,
317+ reporter : Reporter ,
318+ templates : List [dict ],
319+ validators : AnnotationValidators ,
320+ annotation_upload_data : UploadAnnotationAuthData = None ,
321+ annotations : dict = None ,
322+ s3_bucket = None ,
323+ client_s3_bucket = None ,
324+ mask = None ,
325+ verbose : bool = True ,
326+ annotation_path : str = None ,
327+ pass_validation : bool = False ,
328328 ):
329329 super ().__init__ (reporter )
330330 self ._project = project
@@ -413,18 +413,18 @@ def set_annotation_json(self):
413413
414414 @staticmethod
415415 def prepare_annotations (
416- project_type : int ,
417- annotations : dict ,
418- annotation_classes : List [AnnotationClassEntity ],
419- templates : List [dict ],
420- reporter : Reporter ,
421- team : TeamEntity ,
416+ project_type : int ,
417+ annotations : dict ,
418+ annotation_classes : List [AnnotationClassEntity ],
419+ templates : List [dict ],
420+ reporter : Reporter ,
421+ team : TeamEntity ,
422422 ) -> dict :
423423 handlers_chain = ChainedAnnotationHandlers ()
424424 if project_type in (
425- constances .ProjectType .VECTOR .value ,
426- constances .ProjectType .PIXEL .value ,
427- constances .ProjectType .DOCUMENT .value ,
425+ constances .ProjectType .VECTOR .value ,
426+ constances .ProjectType .PIXEL .value ,
427+ constances .ProjectType .DOCUMENT .value ,
428428 ):
429429 handlers_chain .attach (
430430 MissingIDsHandler (annotation_classes , templates , reporter )
@@ -436,7 +436,7 @@ def prepare_annotations(
436436 handlers_chain .attach (LastActionHandler (team .creator_id ))
437437 return handlers_chain .handle (annotations )
438438
439- def clean_json (self , json_data : dict ,) -> Tuple [bool , dict ]:
439+ def clean_json (self , json_data : dict , ) -> Tuple [bool , dict ]:
440440 use_case = ValidateAnnotationUseCase (
441441 constances .ProjectType .get_name (self ._project .project_type ),
442442 annotation = json_data ,
@@ -466,8 +466,8 @@ def execute(self):
466466 Body = json .dumps (annotation_json ),
467467 )
468468 if (
469- self ._project .project_type == constances .ProjectType .PIXEL .value
470- and self ._mask
469+ self ._project .project_type == constances .ProjectType .PIXEL .value
470+ and self ._mask
471471 ):
472472 bucket .put_object (
473473 Key = self .annotation_upload_data .images [self ._image .uuid ][
@@ -540,7 +540,7 @@ def _prettify_annotations(self, annotations: List[dict]):
540540 try :
541541 data = []
542542 for annotation in annotations :
543- data .append ((self ._item_names .index (annotation ["metadata" ]["name" ]), annotation ))
543+ data .append ((self ._item_names .index (annotation ["metadata" ]["name" ]), annotation ))
544544 return [i [1 ] for i in sorted (data , key = lambda x : x [0 ])]
545545 except KeyError :
546546 raise AppException ("Broken data." )
@@ -598,48 +598,48 @@ def validate_project_type(self):
598598 )
599599
600600 def execute (self ):
601- self .reporter .disable_info ()
602- response = GetAnnotations (
603- reporter = self .reporter ,
604- project = self ._project ,
605- folder = self ._folder ,
606- images = self ._images ,
607- item_names = [self ._video_name ],
608- backend_service_provider = self ._client ,
609- show_process = False
610- ).execute ()
611- self .reporter .enable_info ()
612- if response .data :
613- generator = VideoFrameGenerator (response .data [0 ], fps = self ._fps )
614-
615- self .reporter .log_info (f"Getting annotations for { generator .frames_count } frames from { self ._video_name } ." )
616- if response .errors :
617- self ._response .errors = response .errors
618- return self ._response
619- if not response .data :
620- self ._response .errors = AppException (f"Video { self ._video_name } not found." )
621- annotations = response .data
622- if annotations :
623- self ._response .data = list (generator )
601+ if self .is_valid ():
602+ self .reporter .disable_info ()
603+ response = GetAnnotations (
604+ reporter = self .reporter ,
605+ project = self ._project ,
606+ folder = self ._folder ,
607+ images = self ._images ,
608+ item_names = [self ._video_name ],
609+ backend_service_provider = self ._client ,
610+ show_process = False
611+ ).execute ()
612+ self .reporter .enable_info ()
613+ if response .data :
614+ generator = VideoFrameGenerator (response .data [0 ], fps = self ._fps )
615+
616+ self .reporter .log_info (f"Getting annotations for { generator .frames_count } frames from { self ._video_name } ." )
617+ if response .errors :
618+ self ._response .errors = response .errors
619+ return self ._response
620+ if not response .data :
621+ self ._response .errors = AppException (f"Video { self ._video_name } not found." )
622+ annotations = response .data
623+ if annotations :
624+ self ._response .data = list (generator )
625+ else :
626+ self ._response .data = []
624627 else :
625- self ._response .data = []
626- else :
627- self ._response .errors = "Couldn't get annotations."
628+ self ._response .errors = "Couldn't get annotations."
628629 return self ._response
629630
630631
631632class UploadPriorityScoresUseCase (BaseReportableUseCae ):
632-
633633 CHUNK_SIZE = 100
634634
635635 def __init__ (
636- self ,
637- reporter ,
638- project : ProjectEntity ,
639- folder : FolderEntity ,
640- scores : List [PriorityScore ],
641- project_folder_name : str ,
642- backend_service_provider : SuerannotateServiceProvider
636+ self ,
637+ reporter ,
638+ project : ProjectEntity ,
639+ folder : FolderEntity ,
640+ scores : List [PriorityScore ],
641+ project_folder_name : str ,
642+ backend_service_provider : SuerannotateServiceProvider
643643 ):
644644 super ().__init__ (reporter )
645645 self ._project = project
@@ -663,7 +663,12 @@ def get_clean_priority(priority):
663663
664664 @property
665665 def folder_path (self ):
666- return f"{ self ._project .name } { f'/{ self ._folder .name } ' if self ._folder .name != 'root' else '' } "
666+ return f"{ self ._project .name } { f'/{ self ._folder .name } ' if self ._folder .name != 'root' else '' } "
667+
668+ @property
669+ def uploading_info (self ):
670+ data_len : int = len (self ._scores )
671+ return f"Uploading priority scores for { data_len } item{ '(s)' if data_len < 1 else '' } to { self .folder_path } ."
667672
668673 def execute (self ):
669674 if self .is_valid ():
@@ -676,12 +681,12 @@ def execute(self):
676681 })
677682 initial_scores .append (i .name )
678683 uploaded_score_names = []
679- self .reporter .log_info (f"Uploading priority scores for { len ( priorities ) } item(s) from { self .folder_path } ." )
684+ self .reporter .log_info (self .uploading_info )
680685 iterations = range (0 , len (priorities ), self .CHUNK_SIZE )
681686 self .reporter .start_progress (iterations , "Uploading priority scores" )
682687 if iterations :
683688 for i in iterations :
684- priorities_to_upload = priorities [i : i + self .CHUNK_SIZE ] # noqa: E203
689+ priorities_to_upload = priorities [i : i + self .CHUNK_SIZE ] # noqa: E203
685690 res = self ._client .upload_priority_scores (
686691 team_id = self ._project .team_id ,
687692 project_id = self ._project .uuid ,
@@ -690,6 +695,7 @@ def execute(self):
690695 )
691696 self .reporter .update_progress (len (priorities_to_upload ))
692697 uploaded_score_names .extend (list (map (lambda x : x ["name" ], res .get ("data" , []))))
698+ self .reporter .finish_progress ()
693699 skipped_score_names = list (set (initial_scores ) - set (uploaded_score_names ))
694700 self ._response .data = (uploaded_score_names , skipped_score_names )
695701 else :
0 commit comments