@@ -523,10 +523,14 @@ def copy_image(
523523 destination_project
524524 )
525525
526- project = controller .get_project_metadata (destination_project ).data
527- if project ["project" ].project_type == constances .ProjectType .VIDEO .value :
526+ project = controller .get_project_metadata (destination_project ).data ["project" ]
527+ if (
528+ project .project_type == constances .ProjectType .VIDEO .value
529+ or project .project_type == constances .ProjectType .DOCUMENT .value
530+ ):
528531 raise AppValidationException (
529- "The function does not support projects containing videos attached with URLs"
532+ "The function does not support projects containing "
533+ f"{ constances .ProjectType .get_name (project .project_type )} attached with URLs"
530534 )
531535
532536 img_bytes = get_image_bytes (project = source_project , image_name = image_name )
@@ -778,10 +782,15 @@ def move_images(
778782 """
779783 project_name , source_folder_name = extract_project_folder (source_project )
780784
781- project = controller .get_project_metadata (project_name ).data
782- if project ["project" ].project_type == constances .ProjectType .VIDEO .value :
785+ project = controller .get_project_metadata (project_name ).data ["project" ]
786+
787+ if (
788+ project .project_type == constances .ProjectType .VIDEO .value
789+ or project .project_type == constances .ProjectType .DOCUMENT .value
790+ ):
783791 raise AppValidationException (
784- "The function does not support projects containing videos attached with URLs"
792+ "The function does not support projects containing "
793+ f"{ constances .ProjectType .get_name (project .project_type )} attached with URLs"
785794 )
786795
787796 _ , destination_folder_name = extract_project_folder (destination_project )
@@ -1132,13 +1141,16 @@ def assign_images(project: Union[str, dict], image_names: List[str], user: str):
11321141 project_name , folder_name = extract_project_folder (project )
11331142 if not folder_name :
11341143 folder_name = "root"
1135- contributors = (
1136- controller .get_project_metadata (
1137- project_name = project_name , include_contributors = True
1144+ project_entity = controller .get_project_metadata (
1145+ project_name = project_name , include_contributors = True
1146+ ).data ["project" ]
1147+
1148+ if project_entity .project_type == constances .ProjectType .DOCUMENT .value :
1149+ raise AppValidationException (
1150+ "The function does not support projects containing document attached with URLs"
11381151 )
1139- .data ["project" ]
1140- .users
1141- )
1152+ contributors = project_entity .users
1153+
11421154 contributor = None
11431155 for c in contributors :
11441156 if c ["user_id" ] == user :
@@ -1312,8 +1324,8 @@ def upload_images_from_google_cloud_to_project(
13121324 failed_images = []
13131325 duplicated_images = []
13141326 project_name , folder_name = extract_project_folder (project )
1315- project = controller .get_project_metadata (project_name ).data
1316- if project [ "project" ] .project_type == constances .ProjectType .VIDEO .value :
1327+ project = controller .get_project_metadata (project_name ).data [ "project" ]
1328+ if project .project_type == constances .ProjectType .VIDEO .value :
13171329 raise AppValidationException (
13181330 "The function does not support projects containing videos attached with URLs"
13191331 )
@@ -1413,8 +1425,8 @@ def upload_images_from_azure_blob_to_project(
14131425 failed_images = []
14141426 duplicated_images = []
14151427 project_name , folder_name = extract_project_folder (project )
1416- project = controller .get_project_metadata (project_name ).data
1417- if project [ "project" ] .project_type == constances .ProjectType .VIDEO .value :
1428+ project = controller .get_project_metadata (project_name ).data [ "project" ]
1429+ if project .project_type == constances .ProjectType .VIDEO .value :
14181430 raise AppValidationException (
14191431 "The function does not support projects containing videos attached with URLs"
14201432 )
@@ -1865,7 +1877,11 @@ def upload_videos_from_folder_to_project(
18651877 """
18661878
18671879 project_name , folder_name = extract_project_folder (project )
1868-
1880+ project = controller .get_project_metadata (project_name ).data ["project" ]
1881+ if project .project_type == constances .ProjectType .DOCUMENT .value :
1882+ raise AppValidationException (
1883+ "The function does not support projects containing document attached with URLs"
1884+ )
18691885 video_paths = []
18701886 for extension in extensions :
18711887 if not recursive_subfolders :
@@ -2158,10 +2174,14 @@ def move_image(
21582174 )
21592175
21602176 source_project_name , source_folder_name = extract_project_folder (source_project )
2161- project = controller .get_project_metadata (source_project_name ).data
2162- if project ["project" ].project_type == constances .ProjectType .VIDEO .value :
2177+ project = controller .get_project_metadata (source_project_name ).data ["project" ]
2178+ if (
2179+ project .project_type == constances .ProjectType .VIDEO .value
2180+ or project .project_type == constances .ProjectType .DOCUMENT .value
2181+ ):
21632182 raise AppValidationException (
2164- "The function does not support projects containing videos attached with URLs"
2183+ "The function does not support projects containing "
2184+ f"{ constances .ProjectType .get_name (project .project_type )} attached with URLs"
21652185 )
21662186
21672187 destination_project , destination_folder = extract_project_folder (
@@ -2240,6 +2260,9 @@ def download_export(
22402260 extract_zip_contents = extract_zip_contents ,
22412261 to_s3_bucket = to_s3_bucket ,
22422262 )
2263+ if response .errors :
2264+ raise AppException (response .errors )
2265+
22432266 downloaded_folder_path = response .data
22442267
22452268 if to_s3_bucket :
@@ -2404,10 +2427,14 @@ def attach_image_urls_to_project(project, attachments, annotation_status="NotSta
24042427 :rtype: tuple
24052428 """
24062429 project_name , folder_name = extract_project_folder (project )
2407- project = controller .get_project_metadata (project_name ).data
2408- if project ["project" ].project_type == constances .ProjectType .VIDEO .value :
2430+ project = controller .get_project_metadata (project_name ).data ["project" ]
2431+ if (
2432+ project .project_type == constances .ProjectType .VIDEO .value
2433+ or project .project_type == constances .ProjectType .DOCUMENT .value
2434+ ):
24092435 raise AppValidationException (
2410- "The function does not support projects containing videos attached with URLs"
2436+ "The function does not support projects containing "
2437+ f"{ constances .ProjectType .get_name (project .project_type )} attached with URLs"
24112438 )
24122439
24132440 image_data = pd .read_csv (attachments , dtype = str )
@@ -2461,8 +2488,8 @@ def attach_video_urls_to_project(project, attachments, annotation_status="NotSta
24612488 :rtype: (list, list, list)
24622489 """
24632490 project_name , folder_name = extract_project_folder (project )
2464- project = controller .get_project_metadata (project_name ).data
2465- if project [ "project" ] .project_type != constances .ProjectType .VIDEO .value :
2491+ project = controller .get_project_metadata (project_name ).data [ "project" ]
2492+ if project .project_type != constances .ProjectType .VIDEO .value :
24662493 raise AppValidationException ("The function does not support" )
24672494
24682495 image_data = pd .read_csv (attachments , dtype = str )
@@ -2533,10 +2560,15 @@ def upload_annotations_from_folder_to_project(
25332560 """
25342561
25352562 project_name , folder_name = extract_project_folder (project )
2536- project = controller .get_project_metadata (project_name ).data
2537- if project ["project" ].project_type == constances .ProjectType .VIDEO .value :
2563+ project = controller .get_project_metadata (project_name ).data ["project" ]
2564+
2565+ if (
2566+ project .project_type == constances .ProjectType .VIDEO .value
2567+ or project .project_type == constances .ProjectType .DOCUMENT .value
2568+ ):
25382569 raise AppValidationException (
2539- "The function does not support projects containing videos attached with URLs"
2570+ "The function does not support projects containing "
2571+ f"{ constances .ProjectType .get_name (project .project_type )} attached with URLs"
25402572 )
25412573
25422574 if recursive_subfolders :
@@ -2610,10 +2642,14 @@ def upload_preannotations_from_folder_to_project(
26102642 :rtype: tuple of list of strs
26112643 """
26122644 project_name , folder_name = extract_project_folder (project )
2613- project = controller .get_project_metadata (project_name ).data
2614- if project ["project" ].project_type == constances .ProjectType .VIDEO .value :
2645+ project = controller .get_project_metadata (project_name ).data ["project" ]
2646+ if (
2647+ project .project_type == constances .ProjectType .VIDEO .value
2648+ or project .project_type == constances .ProjectType .DOCUMENT .value
2649+ ):
26152650 raise AppValidationException (
2616- "The function does not support projects containing videos attached with URLs"
2651+ "The function does not support projects containing "
2652+ f"{ constances .ProjectType .get_name (project .project_type )} attached with URLs"
26172653 )
26182654
26192655 if recursive_subfolders :
@@ -3449,10 +3485,14 @@ def upload_image_to_project(
34493485 """
34503486 project_name , folder_name = extract_project_folder (project )
34513487
3452- project = controller .get_project_metadata (project_name ).data
3453- if project ["project" ].project_type == constances .ProjectType .VIDEO .value :
3488+ project = controller .get_project_metadata (project_name ).data ["project" ]
3489+ if (
3490+ project .project_type == constances .ProjectType .VIDEO .value
3491+ or project .project_type == constances .ProjectType .DOCUMENT .value
3492+ ):
34543493 raise AppValidationException (
3455- "The function does not support projects containing videos attached with URLs"
3494+ "The function does not support projects containing "
3495+ f"{ constances .ProjectType .get_name (project .project_type )} attached with URLs"
34563496 )
34573497
34583498 if not isinstance (img , io .BytesIO ):
@@ -3539,10 +3579,15 @@ def upload_images_to_project(
35393579 uploaded_image_entities = []
35403580 failed_images = []
35413581 project_name , folder_name = extract_project_folder (project )
3542- project = controller .get_project_metadata (project_name ).data
3543- if project ["project" ].project_type == constances .ProjectType .VIDEO .value :
3582+ project = controller .get_project_metadata (project_name ).data ["project" ]
3583+
3584+ if (
3585+ project .project_type == constances .ProjectType .VIDEO .value
3586+ or project .project_type == constances .ProjectType .DOCUMENT .value
3587+ ):
35443588 raise AppValidationException (
3545- "The function does not support projects containing videos attached with URLs"
3589+ "The function does not support projects containing "
3590+ f"{ constances .ProjectType .get_name (project .project_type )} attached with URLs"
35463591 )
35473592
35483593 ProcessedImage = namedtuple ("ProcessedImage" , ["uploaded" , "path" , "entity" ])
@@ -3700,3 +3745,63 @@ def delete_annotations(project: str, image_names: List[str] = None):
37003745 )
37013746 if response .errors :
37023747 raise AppException (response .errors )
3748+
3749+
3750+ @Trackable
3751+ @typechecked
3752+ def attach_document_urls_to_project (
3753+ project : Union [str , dict ],
3754+ attachments : Union [Path , str ],
3755+ annotation_status : Optional [str ] = "NotStarted" ,
3756+ ):
3757+ """Link documents on external storage to SuperAnnotate.
3758+
3759+ :param project: project name or project folder path
3760+ :type project: str or dict
3761+ :param attachments: path to csv file on attachments metadata
3762+ :type attachments: Path-like (str or Path)
3763+ :param annotation_status: value to set the annotation statuses of the linked documents: NotStarted InProgress QualityCheck Returned Completed Skipped
3764+ :type annotation_status: str
3765+
3766+ :return: list of attached documents, list of not attached documents, list of skipped documents
3767+ :rtype: tuple
3768+ """
3769+ project_name , folder_name = extract_project_folder (project )
3770+
3771+ image_data = pd .read_csv (attachments , dtype = str )
3772+ image_data = image_data [~ image_data ["url" ].isnull ()]
3773+ if "name" in image_data .columns :
3774+ image_data ["name" ] = (
3775+ image_data ["name" ]
3776+ .fillna ("" )
3777+ .apply (lambda cell : cell if str (cell ).strip () else str (uuid .uuid4 ()))
3778+ )
3779+ else :
3780+ image_data ["name" ] = [str (uuid .uuid4 ()) for _ in range (len (image_data .index ))]
3781+
3782+ image_data = pd .DataFrame (image_data , columns = ["name" , "url" ])
3783+ img_names_urls = image_data .rename (columns = {"url" : "path" }).to_dict (
3784+ orient = "records"
3785+ )
3786+ list_of_not_uploaded = []
3787+ duplicate_images = []
3788+ for i in range (0 , len (img_names_urls ), 500 ):
3789+ response = controller .attach_urls (
3790+ project_name = project_name ,
3791+ folder_name = folder_name ,
3792+ files = ImageSerializer .deserialize (
3793+ img_names_urls [i : i + 500 ] # noqa: E203
3794+ ),
3795+ annotation_status = annotation_status ,
3796+ )
3797+ if response .errors :
3798+ list_of_not_uploaded .append (response .data [0 ])
3799+ duplicate_images .append (response .data [1 ])
3800+
3801+ list_of_uploaded = [
3802+ image ["name" ]
3803+ for image in img_names_urls
3804+ if image ["name" ] not in list_of_not_uploaded
3805+ ]
3806+
3807+ return list_of_uploaded , list_of_not_uploaded , duplicate_images
0 commit comments