@@ -992,6 +992,8 @@ def __init__(
992992 self ._classes = classes
993993 self ._callback = callback
994994 self ._images = images
995+ self ._big_file_queues = []
996+ self ._small_file_queues = []
995997
996998 def validate_item_names (self ):
997999 if self ._item_names :
@@ -1052,7 +1054,105 @@ def coroutine_wrapper(coroutine):
10521054 loop .close ()
10531055 return count
10541056
1057+ async def _download_big_annotation (self , item , export_path , folder_id ):
1058+ postfix = self .get_postfix ()
1059+ await self ._backend_client .download_big_annotation (
1060+ item = item ,
1061+ team_id = self ._project .team_id ,
1062+ project_id = self ._project .id ,
1063+ folder_id = folder_id ,
1064+ reporter = self .reporter ,
1065+ download_path = f"{ export_path } { '/' + self ._folder .name if not self ._folder .is_root else '' } " ,
1066+ postfix = postfix ,
1067+ callback = self ._callback ,
1068+ )
1069+
1070+ async def download_big_annotations (self , queue_idx , export_path , folder_id ):
1071+ while True :
1072+ cur_queue = self ._big_file_queues [queue_idx ]
1073+ item = await cur_queue .get ()
1074+ cur_queue .task_done ()
1075+ if item :
1076+ await self ._download_big_annotation (item , export_path , folder_id )
1077+ else :
1078+ cur_queue .put_nowait (None )
1079+ break
1080+
1081+ async def download_small_annotations (self , queue_idx , export_path , folder_id ):
1082+ cur_queue = self ._small_file_queues [queue_idx ]
1083+
1084+ items = []
1085+ item = ""
1086+ postfix = self .get_postfix ()
1087+ while item is not None :
1088+ item = await cur_queue .get ()
1089+ if item :
1090+ items .append (item )
1091+ await self ._backend_client .download_small_annotations (
1092+ team_id = self ._project .team_id ,
1093+ project_id = self ._project .id ,
1094+ folder_id = folder_id ,
1095+ items = items ,
1096+ reporter = self .reporter ,
1097+ download_path = f"{ export_path } { '/' + self ._folder .name if not self ._folder .is_root else '' } " ,
1098+ postfix = postfix ,
1099+ callback = self ._callback ,
1100+ )
1101+
1102+ async def distribute_to_queues (
1103+ self , item_names , sm_queue_id , l_queue_id , folder_id
1104+ ):
1105+ try :
1106+ team_id = self ._project .team_id
1107+ project_id = self ._project .id
1108+
1109+ resp = self ._backend_client .sort_items_by_size (
1110+ item_names , team_id , project_id , folder_id
1111+ )
1112+
1113+ for item in resp ["large" ]:
1114+ await self ._big_file_queues [l_queue_id ].put (item )
1115+
1116+ for item in resp ["small" ]:
1117+ await self ._small_file_queues [sm_queue_id ].put (item ["name" ])
1118+ finally :
1119+ await self ._big_file_queues [l_queue_id ].put (None )
1120+ await self ._small_file_queues [sm_queue_id ].put (None )
1121+
1122+ async def run_workers (self , item_names , folder_id , export_path ):
1123+ try :
1124+ self ._big_file_queues .append (asyncio .Queue ())
1125+ self ._small_file_queues .append (asyncio .Queue ())
1126+ small_file_queue_idx = len (self ._small_file_queues ) - 1
1127+ big_file_queue_idx = len (self ._big_file_queues ) - 1
1128+ res = await asyncio .gather (
1129+ self .distribute_to_queues (
1130+ item_names , small_file_queue_idx , big_file_queue_idx , folder_id
1131+ ),
1132+ self .download_big_annotations (
1133+ big_file_queue_idx , export_path , folder_id
1134+ ),
1135+ self .download_big_annotations (
1136+ big_file_queue_idx , export_path , folder_id
1137+ ),
1138+ self .download_big_annotations (
1139+ big_file_queue_idx , export_path , folder_id
1140+ ),
1141+ self .download_small_annotations (
1142+ small_file_queue_idx , export_path , folder_id
1143+ ),
1144+ return_exceptions = True ,
1145+ )
1146+ if any (res ):
1147+ self .reporter .log_error (f"Error { str ([i for i in res if i ])} " )
1148+ except Exception as e :
1149+ self .reporter .log_error (f"Error { str (e )} " )
1150+
1151+ def per_folder_execute (self , item_names , folder_id , export_path ):
1152+ asyncio .run (self .run_workers (item_names , folder_id , export_path ))
1153+
10551154 def execute (self ):
1155+
10561156 if self .is_valid ():
10571157 export_path = str (
10581158 self .destination
@@ -1064,77 +1164,52 @@ def execute(self):
10641164 f"Downloading the annotations of the requested items to { export_path } \n This might take a while…"
10651165 )
10661166 self .reporter .start_spinner ()
1167+
10671168 folders = []
10681169 if self ._folder .is_root and self ._recursive :
10691170 folders = self ._folders .get_all (
10701171 Condition ("team_id" , self ._project .team_id , EQ )
10711172 & Condition ("project_id" , self ._project .id , EQ ),
10721173 )
10731174 folders .append (self ._folder )
1074- postfix = self .get_postfix ()
1075- import nest_asyncio
1076- import platform
1077-
1078- if platform .system ().lower () == "windows" :
1079- asyncio .set_event_loop_policy (asyncio .WindowsSelectorEventLoopPolicy ())
1080-
1081- nest_asyncio .apply ()
10821175
10831176 if not folders :
1084- loop = asyncio .new_event_loop ()
1085- if not self ._item_names :
1086- condition = (
1087- Condition ("team_id" , self ._project .team_id , EQ )
1088- & Condition ("project_id" , self ._project .id , EQ )
1089- & Condition ("folder_id" , self ._folder .uuid , EQ )
1090- )
1091- item_names = [item .name for item in self ._images .get_all (condition )]
1092- else :
1093- item_names = self ._item_names
1094- count = loop .run_until_complete (
1095- self ._backend_client .download_annotations (
1096- team_id = self ._project .team_id ,
1097- project_id = self ._project .id ,
1098- folder_id = self ._folder .uuid ,
1099- items = item_names ,
1100- reporter = self .reporter ,
1101- download_path = f"{ export_path } { '/' + self ._folder .name if not self ._folder .is_root else '' } " ,
1102- postfix = postfix ,
1103- callback = self ._callback ,
1104- )
1105- )
1106- else :
1107- with concurrent .futures .ThreadPoolExecutor (max_workers = 5 ) as executor :
1108- coroutines = []
1109- for folder in folders :
1110- if not self ._item_names :
1111- condition = (
1112- Condition ("team_id" , self ._project .team_id , EQ )
1113- & Condition ("project_id" , self ._project .id , EQ )
1114- & Condition ("folder_id" , folder .uuid , EQ )
1115- )
1116- item_names = [
1117- item .name for item in self ._images .get_all (condition )
1118- ]
1119- else :
1120- item_names = self ._item_names
1121- coroutines .append (
1122- self ._backend_client .download_annotations (
1123- team_id = self ._project .team_id ,
1124- project_id = self ._project .id ,
1125- folder_id = folder .uuid ,
1126- items = item_names ,
1127- reporter = self .reporter ,
1128- download_path = f"{ export_path } { '/' + folder .name if not folder .is_root else '' } " , # noqa
1129- postfix = postfix ,
1130- callback = self ._callback ,
1131- )
1177+ folders .append (self ._folder )
1178+ with concurrent .futures .ThreadPoolExecutor (max_workers = 5 ) as executor :
1179+ futures = []
1180+ for folder in folders :
1181+ if not self ._item_names :
1182+ condition = (
1183+ Condition ("team_id" , self ._project .team_id , EQ )
1184+ & Condition ("project_id" , self ._project .id , EQ )
1185+ & Condition ("folder_id" , folder .uuid , EQ )
11321186 )
1133- count = sum (
1134- [i for i in executor .map (self .coroutine_wrapper , coroutines )]
1187+ item_names = [
1188+ item .name for item in self ._images .get_all (condition )
1189+ ]
1190+ else :
1191+ item_names = self ._item_names
1192+
1193+ new_export_path = export_path
1194+ if folder .name != "root" :
1195+ new_export_path += f"/{ folder .name } "
1196+
1197+ # TODO check
1198+ if not item_names :
1199+ continue
1200+ future = executor .submit (
1201+ self .per_folder_execute ,
1202+ item_names ,
1203+ folder .uuid ,
1204+ new_export_path ,
11351205 )
1206+ futures .append (future )
1207+
1208+ for future in concurrent .futures .as_completed (futures ):
1209+ print (future .result ())
11361210
11371211 self .reporter .stop_spinner ()
1212+ count = self .get_items_count (export_path )
11381213 self .reporter .log_info (f"Downloaded annotations for { count } items." )
11391214 self .download_annotation_classes (export_path )
11401215 self ._response .data = os .path .abspath (export_path )
0 commit comments