|
11 | 11 | from typing import Union |
12 | 12 |
|
13 | 13 | import boto3 |
| 14 | +from pydantic import StrictBool |
| 15 | +from pydantic import conlist |
| 16 | +from pydantic import parse_obj_as |
| 17 | +from pydantic.error_wrappers import ValidationError |
| 18 | +from tqdm import tqdm |
| 19 | + |
14 | 20 | import lib.core as constances |
15 | 21 | from lib.app.annotation_helpers import add_annotation_bbox_to_json |
16 | 22 | from lib.app.annotation_helpers import add_annotation_comment_to_json |
|
45 | 51 | from lib.core.types import PriorityScore |
46 | 52 | from lib.core.types import Project |
47 | 53 | from lib.infrastructure.controller import Controller |
48 | | -from pydantic import conlist |
49 | | -from pydantic import parse_obj_as |
50 | | -from pydantic import StrictBool |
51 | | -from pydantic.error_wrappers import ValidationError |
52 | 54 | from superannotate.logger import get_default_logger |
53 | | -from tqdm import tqdm |
54 | 55 |
|
55 | 56 | logger = get_default_logger() |
56 | 57 |
|
@@ -297,6 +298,7 @@ def search_images( |
297 | 298 | "We're deprecating the search_images function. Please use search_items instead. Learn more." |
298 | 299 | "https://superannotate.readthedocs.io/en/stable/superannotate.sdk.html#superannotate.search_items" |
299 | 300 | ) |
| 301 | + logger.warning(warning_msg) |
300 | 302 | warnings.warn(warning_msg, DeprecationWarning) |
301 | 303 | project_name, folder_name = extract_project_folder(project) |
302 | 304 | project = Controller.get_default()._get_project(project_name) |
@@ -2479,8 +2481,10 @@ def search_images_all_folders( |
2479 | 2481 |
|
2480 | 2482 | :param project: project name |
2481 | 2483 | :type project: str |
| 2484 | +
|
2482 | 2485 | :param image_name_prefix: image name prefix for search |
2483 | 2486 | :type image_name_prefix: str |
| 2487 | +
|
2484 | 2488 | :param annotation_status: if not None, annotation statuses of images to filter, |
2485 | 2489 | should be one of NotStarted InProgress QualityCheck Returned Completed Skipped |
2486 | 2490 | :type annotation_status: str |
@@ -3087,3 +3091,72 @@ def search_items( |
3087 | 3091 | if response.errors: |
3088 | 3092 | raise AppException(response.errors) |
3089 | 3093 | return BaseSerializer.serialize_iterable(response.data) |
| 3094 | + |
| 3095 | + |
| 3096 | +@Trackable |
| 3097 | +@validate_arguments |
| 3098 | +def attach_items( |
| 3099 | + project: Union[NotEmptyStr, dict], |
| 3100 | + attachments, |
| 3101 | + annotation_status="NotStarted" |
| 3102 | +): |
| 3103 | + """Link items from external storage to SuperAnnotate using URLs. |
| 3104 | +
|
| 3105 | + :param project: project name or folder path (e.g., “project1/folder1”) |
| 3106 | + :type project: str |
| 3107 | +
|
| 3108 | + :param attachments: path to CSV file or list of dicts containing attachments URLs. |
| 3109 | + :type attachments: path-like (str or Path) or list of dicts |
| 3110 | +
|
| 3111 | + :param annotation_status: value to set the annotation statuses of the |
| 3112 | + linked items: |
| 3113 | + “NotStarted” |
| 3114 | + “InProgress” |
| 3115 | + “QualityCheck” |
| 3116 | + “Returned” |
| 3117 | + “Completed” |
| 3118 | + “Skipped” |
| 3119 | + :type annotation_status: str |
| 3120 | +
|
| 3121 | + :return: list of attached item names, list of not attached item names, list of duplicate item names |
| 3122 | + that are already in SuperAnnotate. |
| 3123 | + :rtype: tuple |
| 3124 | + """ |
| 3125 | + project_name, folder_name = extract_project_folder(project) |
| 3126 | + |
| 3127 | + images_to_upload, duplicate_images = get_paths_and_duplicated_from_csv(attachments) |
| 3128 | + |
| 3129 | + attachments_data |
| 3130 | + |
| 3131 | + use_case = Controller.get_default().attach_items( |
| 3132 | + project_name=project_name, |
| 3133 | + folder_name=folder_name, |
| 3134 | + files=ImageSerializer.deserialize(images_to_upload), # noqa: E203 |
| 3135 | + annotation_status=annotation_status, |
| 3136 | + ) |
| 3137 | + if len(duplicate_images): |
| 3138 | + logger.warning( |
| 3139 | + constances.ALREADY_EXISTING_FILES_WARNING.format(len(duplicate_images)) |
| 3140 | + ) |
| 3141 | + |
| 3142 | + if use_case.is_valid(): |
| 3143 | + logger.info( |
| 3144 | + constances.ATTACHING_FILES_MESSAGE.format( |
| 3145 | + len(images_to_upload), project |
| 3146 | + ) |
| 3147 | + ) |
| 3148 | + with tqdm( |
| 3149 | + total=use_case.attachments_count, desc="Attaching urls" |
| 3150 | + ) as progress_bar: |
| 3151 | + for attached in use_case.execute(): |
| 3152 | + progress_bar.update(attached) |
| 3153 | + uploaded, duplications = use_case.data |
| 3154 | + uploaded = [i["name"] for i in uploaded] |
| 3155 | + duplications.extend(duplicate_images) |
| 3156 | + failed_images = [ |
| 3157 | + image["name"] |
| 3158 | + for image in images_to_upload |
| 3159 | + if image["name"] not in uploaded + duplications |
| 3160 | + ] |
| 3161 | + return uploaded, failed_images, duplications |
| 3162 | + raise AppException(use_case.response.errors) |
0 commit comments