1818from cvat_sdk .api_client .api_client import Endpoint
1919from cvat_sdk .core .helpers import get_paginated_collection
2020from cvat_sdk .core .uploading import AnnotationUploader
21+ from httpx import URL
2122
2223from src .core .config import Config
2324from src .utils .enums import BetterEnumMeta
@@ -30,48 +31,46 @@ class CVATException(Exception):
3031 """Indicates that CVAT API returned unexpected response"""
3132
3233
33- def _request_annotations (endpoint : Endpoint , cvat_id : int , format_name : str ) -> bool :
34+ class RequestStatus (str , Enum , metaclass = BetterEnumMeta ):
35+ QUEUED = "Queued"
36+ STARTED = "Started"
37+ FINISHED = "Finished"
38+ FAILED = "Failed"
39+
40+
41+ def _request_annotations (endpoint : Endpoint , cvat_id : int , format_name : str ) -> str :
3442 """
3543 Requests annotations export.
3644 The dataset preparation can take some time (e.g. 10 min), so it must be used like this:
3745
38- while not _request_annotations(...):
39- # some waiting like
40- sleep(1)
41-
42- _get_annotations(...)
46+ request_id = _request_annotations(...)
47+ _get_annotations(request_id, ...)
4348 """
4449
4550 (_ , response ) = endpoint .call_with_http_info (
4651 id = cvat_id ,
4752 format = format_name ,
53+ save_images = False ,
4854 _parse_response = False ,
4955 )
5056
5157 assert response .status in [HTTPStatus .ACCEPTED , HTTPStatus .CREATED ]
52- return response .status == HTTPStatus . CREATED
58+ return response .json ()[ "rq_id" ]
5359
5460
5561def _get_annotations (
56- endpoint : Endpoint ,
62+ api_client : ApiClient ,
63+ request_id : str ,
5764 * ,
58- cvat_id : int ,
59- format_name : str ,
6065 attempt_interval : int = 5 ,
6166 timeout : int | None = _NOTSET ,
6267) -> io .RawIOBase :
6368 """
6469 Downloads annotations.
6570 The dataset preparation can take some time (e.g. 10 min), so it should be used like this:
6671
67- while not _request_annotations(...):
68- # some waiting like
69- sleep(1)
70-
71- _get_annotations(...)
72-
73-
74- It still can be used as 1 call, but the result can be unreliable.
72+ request_id = _request_annotations(...)
73+ _get_annotations(request_id, ...)
7574 """
7675
7776 time_begin = utcnow ()
@@ -80,20 +79,33 @@ def _get_annotations(
8079 timeout = Config .cvat_config .export_timeout
8180
8281 while True :
83- ( _ , response ) = endpoint . call_with_http_info (
84- id = cvat_id ,
85- action = "download" ,
86- format = format_name ,
87- _parse_response = False ,
88- )
89- if response .status == HTTPStatus . OK :
82+ request_info = api_client . requests_api . retrieve ( request_id )[ 0 ]
83+ if request_info . status . value == models . RequestStatus . allowed_values [( "value" ,)][ "FAILED" ]:
84+ raise Exception (
85+ f"Failed to export annotations for { request_id = } : { request_info . message } "
86+ )
87+
88+ if request_info .status . value == models . RequestStatus . allowed_values [( "value" ,)][ "FINISHED" ] :
9089 break
9190
9291 if timeout is not None and timedelta (seconds = timeout ) < (utcnow () - time_begin ):
9392 raise Exception ("Failed to retrieve the dataset from CVAT within the timeout interval" )
9493
9594 sleep (attempt_interval )
9695
96+ result_url = URL (request_info .result_url )
97+ query_params = result_url .params
98+ headers = api_client .get_common_headers ()
99+ api_client .update_params_for_auth (
100+ headers = headers ,
101+ queries = query_params ,
102+ auth_settings = ["" ],
103+ resource_path = "" ,
104+ method = "GET" ,
105+ request_auths = list (api_client .configuration .auth_settings ().values ()),
106+ body = "" ,
107+ )
108+ response = api_client .rest_client .GET (request_info .result_url , headers = headers )
97109 file_buffer = io .BytesIO (response .data )
98110 assert zipfile .is_zipfile (file_buffer )
99111 file_buffer .seek (0 )
@@ -231,23 +243,20 @@ def create_project(
231243 raise
232244
233245
234- def request_project_annotations (cvat_id : int , format_name : str ) -> bool :
246+ def request_project_annotations (cvat_id : int , format_name : str ) -> str :
235247 """
236248 Requests annotations export.
237249 The dataset preparation can take some time (e.g. 10 min), so it must be used like this:
238250
239- while not request_project_annotations(...):
240- # some waiting like
241- sleep(1)
242-
243- get_project_annotations(...)
251+ request_id = request_project_annotations(...):
252+ get_project_annotations(request_id, ...)
244253 """
245254
246255 logger = logging .getLogger ("app" )
247256 with get_api_client () as api_client :
248257 try :
249258 return _request_annotations (
250- api_client .projects_api .retrieve_annotations_endpoint ,
259+ api_client .projects_api .create_dataset_export_endpoint ,
251260 cvat_id = cvat_id ,
252261 format_name = format_name ,
253262 )
@@ -256,32 +265,19 @@ def request_project_annotations(cvat_id: int, format_name: str) -> bool:
256265 raise
257266
258267
259- def get_project_annotations (
260- cvat_id : int , format_name : str , * , timeout : int | None = _NOTSET
261- ) -> io .RawIOBase :
268+ def get_project_annotations (request_id : str , * , timeout : int | None = _NOTSET ) -> io .RawIOBase :
262269 """
263270 Downloads annotations.
264271 The dataset preparation can take some time (e.g. 10 min), so it should be used like this:
265272
266- while not request_project_annotations(...):
267- # some waiting like
268- sleep(1)
269-
270- get_project_annotations(...)
271-
272-
273- It still can be used as 1 call, but the result can be unreliable.
273+ request_id = request_project_annotations(...):
274+ get_project_annotations(request_id, ...)
274275 """
275276
276277 logger = logging .getLogger ("app" )
277278 with get_api_client () as api_client :
278279 try :
279- return _get_annotations (
280- api_client .projects_api .retrieve_annotations_endpoint ,
281- cvat_id = cvat_id ,
282- format_name = format_name ,
283- timeout = timeout ,
284- )
280+ return _get_annotations (api_client , request_id = request_id , timeout = timeout )
285281 except exceptions .ApiException as e :
286282 logger .exception (f"Exception when calling ProjectApi.retrieve_annotations: { e } \n " )
287283 raise
@@ -418,23 +414,20 @@ def put_task_data(
418414 raise
419415
420416
421- def request_task_annotations (cvat_id : int , format_name : str ) -> bool :
417+ def request_task_annotations (cvat_id : int , format_name : str ) -> str :
422418 """
423419 Requests annotations export.
424420 The dataset preparation can take some time (e.g. 10 min), so it must be used like this:
425421
426- while not request_task_annotations(...):
427- # some waiting like
428- sleep(1)
429-
430- get_task_annotations(...)
422+ request_id = request_task_annotations(...):
423+ get_task_annotations(request_id, ...)
431424 """
432425
433426 logger = logging .getLogger ("app" )
434427 with get_api_client () as api_client :
435428 try :
436429 return _request_annotations (
437- api_client .tasks_api .retrieve_annotations_endpoint ,
430+ api_client .tasks_api .create_dataset_export_endpoint ,
438431 cvat_id = cvat_id ,
439432 format_name = format_name ,
440433 )
@@ -443,32 +436,19 @@ def request_task_annotations(cvat_id: int, format_name: str) -> bool:
443436 raise
444437
445438
446- def get_task_annotations (
447- cvat_id : int , format_name : str , * , timeout : int | None = _NOTSET
448- ) -> io .RawIOBase :
439+ def get_task_annotations (request_id : str , * , timeout : int | None = _NOTSET ) -> io .RawIOBase :
449440 """
450441 Downloads annotations.
451442 The dataset preparation can take some time (e.g. 10 min), so it must be used like this:
452443
453- while not request_task_annotations(...):
454- # some waiting like
455- sleep(1)
456-
457- get_task_annotations(...)
458-
459-
460- It still can be used as 1 call, but the result can be unreliable.
444+ request_id = request_task_annotations(...):
445+ get_task_annotations(request_id, ...)
461446 """
462447
463448 logger = logging .getLogger ("app" )
464449 with get_api_client () as api_client :
465450 try :
466- return _get_annotations (
467- api_client .tasks_api .retrieve_annotations_endpoint ,
468- cvat_id = cvat_id ,
469- format_name = format_name ,
470- timeout = timeout ,
471- )
451+ return _get_annotations (api_client , request_id = request_id , timeout = timeout )
472452 except exceptions .ApiException as e :
473453 logger .exception (f"Exception when calling TasksApi.retrieve_annotations: { e } \n " )
474454 raise
@@ -488,23 +468,20 @@ def fetch_task_jobs(task_id: int) -> list[models.JobRead]:
488468 raise
489469
490470
491- def request_job_annotations (cvat_id : int , format_name : str ) -> bool :
471+ def request_job_annotations (cvat_id : int , format_name : str ) -> str :
492472 """
493473 Requests annotations export.
494474 The dataset preparation can take some time (e.g. 10 min), so it must be used like this:
495475
496- while not request_job_annotations(...):
497- # some waiting like
498- sleep(1)
499-
500- get_job_annotations(...)
476+ request_id = request_job_annotations(...):
477+ get_job_annotations(request_id, ...)
501478 """
502479
503480 logger = logging .getLogger ("app" )
504481 with get_api_client () as api_client :
505482 try :
506483 return _request_annotations (
507- api_client .jobs_api .retrieve_annotations_endpoint ,
484+ api_client .jobs_api .create_dataset_export_endpoint ,
508485 cvat_id = cvat_id ,
509486 format_name = format_name ,
510487 )
@@ -513,32 +490,19 @@ def request_job_annotations(cvat_id: int, format_name: str) -> bool:
513490 raise
514491
515492
516- def get_job_annotations (
517- cvat_id : int , format_name : str , * , timeout : int | None = _NOTSET
518- ) -> io .RawIOBase :
493+ def get_job_annotations (request_id : str , * , timeout : int | None = _NOTSET ) -> io .RawIOBase :
519494 """
520495 Downloads annotations.
521496 The dataset preparation can take some time (e.g. 10 min), so it must be used like this:
522497
523- while not request_job_annotations(...):
524- # some waiting like
525- sleep(1)
526-
527- get_job_annotations(...)
528-
529-
530- It still can be used as 1 call, but the result can be unreliable.
498+ request_id = request_job_annotations(...):
499+ get_job_annotations(request_id, ...)
531500 """
532501
533502 logger = logging .getLogger ("app" )
534503 with get_api_client () as api_client :
535504 try :
536- return _get_annotations (
537- api_client .jobs_api .retrieve_annotations_endpoint ,
538- cvat_id = cvat_id ,
539- format_name = format_name ,
540- timeout = timeout ,
541- )
505+ return _get_annotations (api_client , request_id = request_id , timeout = timeout )
542506 except exceptions .ApiException as e :
543507 logger .exception (f"Exception when calling JobsApi.retrieve_annotations: { e } \n " )
544508 raise
@@ -577,14 +541,7 @@ def fetch_projects(assignee: str = "") -> list[models.ProjectRead]:
577541 raise
578542
579543
580- class UploadStatus (str , Enum , metaclass = BetterEnumMeta ):
581- QUEUED = "Queued"
582- STARTED = "Started"
583- FINISHED = "Finished"
584- FAILED = "Failed"
585-
586-
587- def get_task_upload_status (cvat_id : int ) -> tuple [UploadStatus | None , str ]:
544+ def get_task_upload_status (cvat_id : int ) -> tuple [RequestStatus | None , str ]:
588545 logger = logging .getLogger ("app" )
589546
590547 with get_api_client () as api_client :
@@ -596,7 +553,7 @@ def get_task_upload_status(cvat_id: int) -> tuple[UploadStatus | None, str]:
596553 status = None
597554 reason = f"Task #{ cvat_id } creation request not found"
598555 else :
599- status = UploadStatus (results [0 ].status .value .capitalize ())
556+ status = RequestStatus (results [0 ].status .value .capitalize ())
600557 reason = results [0 ].message
601558
602559 return status , reason
0 commit comments