13
13
14
14
from roboflow .config import API_URL , DEFAULT_BATCH_NAME , DEMO_KEYS
15
15
from roboflow .core .version import Version
16
+ from roboflow .util .general import retry
16
17
17
18
ACCEPTED_IMAGE_FORMATS = ["PNG" , "JPEG" ]
18
19
@@ -25,6 +26,10 @@ def custom_formatwarning(msg, *args, **kwargs):
25
26
warnings .formatwarning = custom_formatwarning
26
27
27
28
29
+ class UploadError (Exception ):
30
+ pass
31
+
32
+
28
33
class Project :
29
34
def __init__ (self , api_key , a_project , model_format = None ):
30
35
if api_key in DEMO_KEYS :
@@ -342,9 +347,30 @@ def __image_upload(
342
347
)
343
348
# Get response
344
349
response = requests .post (upload_url )
345
- # Return response
346
-
347
- return response
350
+ responsejson = None
351
+ try :
352
+ responsejson = response .json ()
353
+ except :
354
+ pass
355
+ if response .status_code == 200 :
356
+ if responsejson :
357
+ if "duplicate" in responsejson .keys ():
358
+ print (f"Duplicate image not uploaded: { image_path } " )
359
+ elif not responsejson .get ("success" ):
360
+ raise UploadError (f"Server rejected image: { responsejson } " )
361
+ return responsejson .get ("id" )
362
+ else :
363
+ warnings .warn (
364
+ f"upload image { image_path } 200 OK, weird response: { response } "
365
+ )
366
+ return None
367
+ else :
368
+ if responsejson :
369
+ raise UploadError (
370
+ f"Bad response: { response .status_code } - { responsejson } "
371
+ )
372
+ else :
373
+ raise UploadError (f"Bad response: { response } " )
348
374
349
375
def __annotation_upload (
350
376
self , annotation_path : str , image_id : str , is_prediction : bool = False
@@ -378,10 +404,6 @@ def __annotation_upload(
378
404
"result" : "File not found or uploading to non-classification type project with invalid string"
379
405
}
380
406
381
- # Set annotation upload url
382
-
383
- project_name = self .id .rsplit ("/" )[1 ]
384
-
385
407
self .annotation_upload_url = "" .join (
386
408
[
387
409
API_URL + "/dataset/" ,
@@ -395,15 +417,48 @@ def __annotation_upload(
395
417
]
396
418
)
397
419
398
- # Get annotation response
399
- annotation_response = requests .post (
420
+ response = requests .post (
400
421
self .annotation_upload_url ,
401
422
data = annotation_string ,
402
423
headers = {"Content-Type" : "text/plain" },
403
424
)
404
-
405
- # Return annotation response
406
- return annotation_response
425
+ responsejson = None
426
+ try :
427
+ responsejson = response .json ()
428
+ except :
429
+ pass
430
+ if response .status_code == 200 :
431
+ if responsejson :
432
+ if responsejson .get ("error" ):
433
+ raise UploadError (
434
+ f"Failed to save annotation for { image_id } : { responsejson ['error' ]} "
435
+ )
436
+ elif not responsejson .get ("success" ):
437
+ raise UploadError (
438
+ f"Failed to save annotation for { image_id } : { responsejson } "
439
+ )
440
+ else :
441
+ warnings .warn (
442
+ f"save annotation { annotation_path } 200 OK, weird response: { response } "
443
+ )
444
+ elif response .status_code == 409 and "already annotated" in (
445
+ responsejson or {}
446
+ ).get ("error" , {}).get ("message" ):
447
+ print (f"image already annotated: { annotation_path } " )
448
+ else :
449
+ if responsejson :
450
+ if responsejson .get ("error" ):
451
+ raise UploadError (
452
+ f"save annotation for { image_id } / bad response: { response .status_code } - { responsejson ['error' ]} "
453
+ )
454
+ else :
455
+ raise UploadError (
456
+ f"save annotation for { image_id } / bad response: { response .status_code } - { responsejson } "
457
+ )
458
+ else :
459
+ raise UploadError (
460
+ f"save annotation for { image_id } bad response: { response } "
461
+ )
407
462
408
463
def check_valid_image (self , image_path ):
409
464
try :
@@ -420,7 +475,7 @@ def upload(
420
475
image_path : str = None ,
421
476
annotation_path : str = None ,
422
477
hosted_image : bool = False ,
423
- image_id : int = None ,
478
+ image_id : str = None ,
424
479
split : str = "train" ,
425
480
num_retry_uploads : int = 0 ,
426
481
batch_name : str = DEFAULT_BATCH_NAME ,
@@ -434,7 +489,7 @@ def upload(
434
489
image_path (str) - path to image you'd like to upload
435
490
annotation_path (str) - if you're upload annotation, path to it
436
491
hosted_image (bool) - whether the image is hosted
437
- image_id (int ) - id of the image
492
+ image_id (str ) - id of the image
438
493
split (str) - to upload the image to
439
494
num_retry_uploads (int) - how many times to retry upload on failure
440
495
batch_name (str) - name of batch to upload to within project
@@ -519,90 +574,40 @@ def single_upload(
519
574
):
520
575
success = False
521
576
annotation_success = False
522
- # User gives image path
523
577
if image_path is not None :
524
- # Upload Image Response
525
- response = self .__image_upload (
526
- image_path ,
527
- hosted_image = hosted_image ,
528
- split = split ,
529
- batch_name = batch_name ,
530
- tag_names = tag_names ,
531
- ** kwargs ,
532
- )
533
- # Get JSON response values
534
578
try :
535
- if "duplicate" in response .json ().keys ():
536
- if response .json ()["duplicate" ]:
537
- success = True
538
- warnings .warn ("Duplicate image not uploaded: " + image_path )
539
- else :
540
- success , image_id = (
541
- response .json ()["success" ],
542
- response .json ()["id" ],
543
- )
544
-
545
- if not success :
546
- warnings .warn (f"Server rejected image: { response .json ()} " )
547
-
548
- except Exception :
549
- # Image fails to upload
550
- warnings .warn (f"Bad response: { response } " )
551
- success = False
552
- # Give user warning that image failed to upload
553
- if not success :
554
- warnings .warn (
555
- "Upload api failed with response: " + str (response .json ())
579
+ image_id = retry (
580
+ num_retry_uploads ,
581
+ Exception ,
582
+ self .__image_upload ,
583
+ image_path ,
584
+ hosted_image = hosted_image ,
585
+ split = split ,
586
+ batch_name = batch_name ,
587
+ tag_names = tag_names ,
588
+ ** kwargs ,
556
589
)
557
- if num_retry_uploads > 0 :
558
- warnings .warn (
559
- "Image, "
560
- + image_path
561
- + ", failed to upload! Retrying for this many times: "
562
- + str (num_retry_uploads )
563
- )
564
- self .single_upload (
565
- image_path = image_path ,
566
- annotation_path = annotation_path ,
567
- hosted_image = hosted_image ,
568
- image_id = image_id ,
569
- split = split ,
570
- num_retry_uploads = num_retry_uploads - 1 ,
571
- ** kwargs ,
572
- )
573
- return
574
- else :
575
- warnings .warn (
576
- "Image, "
577
- + image_path
578
- + ", failed to upload! You can specify num_retry_uploads to retry a number of times."
579
- )
590
+ success = True
591
+ except BaseException as e :
592
+ print (
593
+ f"{ image_path } ERROR uploading image after { num_retry_uploads } retries: { e } " ,
594
+ file = sys .stderr ,
595
+ )
596
+ return
580
597
581
598
# Upload only annotations to image based on image Id (no image)
582
599
if annotation_path is not None and image_id is not None and success :
583
600
# Get annotation upload response
584
- annotation_response = self .__annotation_upload (
585
- annotation_path , image_id , is_prediction = is_prediction
586
- )
587
- # Check if upload was a success
588
601
try :
589
- response_data = annotation_response .json ()
590
- if "success" in response_data .keys ():
591
- annotation_success = True
592
- elif "error" in response_data .keys ():
593
- warnings .warn (
594
- f"Uploading annotation data for image failed: { str (response_data ['error' ])} "
595
- )
596
- annotation_success = False
597
- else :
598
- warnings .warn (
599
- f"Uploading annotation data for image failed: { str (response_data )} "
600
- )
601
- annotation_success = False
602
- except :
603
- warnings .warn (f"Bad response: { response .status_code } " )
604
- annotation_success = False
605
-
602
+ self .__annotation_upload (
603
+ annotation_path , image_id , is_prediction = is_prediction
604
+ )
605
+ annotation_success = True
606
+ except BaseException as e :
607
+ print (
608
+ f"{ annotation_path } ERROR saving annotation: { e } " , file = sys .stderr
609
+ )
610
+ return False
606
611
# Give user warning that annotation failed to upload
607
612
if not annotation_success :
608
613
warnings .warn (
0 commit comments