Skip to content

Commit 6bc27d7

Browse files
authored
Merge pull request #209 from superannotateai/attach-text
Attach text
2 parents 5d5184d + ce6dd3a commit 6bc27d7

File tree

17 files changed

+320
-126
lines changed

17 files changed

+320
-126
lines changed

docs/source/superannotate.sdk.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ ________
4747
.. autofunction:: superannotate.upload_video_to_project
4848
.. autofunction:: superannotate.upload_videos_from_folder_to_project
4949
.. autofunction:: superannotate.attach_video_urls_to_project
50+
.. autofunction:: superannotate.attach_document_urls_to_project
5051
.. _ref_upload_annotations_from_folder_to_project:
5152
.. autofunction:: superannotate.upload_annotations_from_folder_to_project
5253
.. autofunction:: superannotate.upload_preannotations_from_folder_to_project

superannotate/.DS_Store

6 KB
Binary file not shown.

superannotate/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def consensus(*args, **kwargs):
7676
upload_images_from_s3_bucket_to_project, upload_images_to_project,
7777
attach_image_urls_to_project, upload_preannotations_from_folder_to_project,
7878
upload_video_to_project, upload_videos_from_folder_to_project,
79-
attach_video_urls_to_project
79+
attach_video_urls_to_project,attach_document_urls_to_project
8080
)
8181
from .db.search_projects import search_projects
8282
from .db.teams import (

superannotate/__main__.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def main():
5959
"init": lambda *args, **kwargs: ask_token(),
6060
"export-project": export_project,
6161
"attach-video-urls": attach_video_urls,
62+
"attach-document-urls": attach_document_urls_to_project,
6263
"version": lambda *args, **kwargs: print(f"SuperAnnotate Python SDK version {sa.__version__}")
6364
}
6465
if len(sys.argv) == 1:
@@ -387,5 +388,29 @@ def attach_video_urls(command_name, args):
387388
)
388389

389390

391+
def attach_document_urls_to_project(command_name, args):
392+
parser = argparse.ArgumentParser(prog=_CLI_COMMAND + " " + command_name)
393+
parser.add_argument(
394+
'--project', required=True, help='Project name to upload'
395+
)
396+
parser.add_argument(
397+
'--attachments',
398+
required=True,
399+
help='path to csv file on attachments metadata'
400+
)
401+
parser.add_argument(
402+
'--annotation_status',
403+
required=False,
404+
default="NotStarted",
405+
help=
406+
'Set images\' annotation statuses after upload. Default is NotStarted'
407+
)
408+
args = parser.parse_args(args)
409+
sa.attach_document_urls_to_project(
410+
project=args.project,
411+
attachments=args.attachments,
412+
annotation_status=args.annotation_status
413+
)
414+
390415
if __name__ == "__main__":
391416
main()

superannotate/analytics/common.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,15 @@ def aggregate_annotations_as_df(
183183
:rtype: pandas DataFrame
184184
"""
185185

186+
json_paths = list(Path(str(project_root)).glob("*.json"))
187+
if (
188+
json_paths
189+
and "___pixel.json" not in json_paths[0].name
190+
and "___objects.json" not in json_paths[0].name
191+
):
192+
raise SABaseException(0, "The function does not support projects containing videos / documents attached with URLs")
193+
194+
186195
if verbose:
187196
logger.info(
188197
"Aggregating annotations from %s as pandas DataFrame", project_root

superannotate/common.py

Lines changed: 92 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
SPECIAL_CHARACTERS_IN_PROJECT_FOLDER_NAMES = set('/\\:*?"<>|')
2121

22-
_PROJECT_TYPES = {"Vector": 1, "Pixel": 2, "Video": 3}
22+
_PROJECT_TYPES = {"Vector": 1, "Pixel": 2, "Video": 3, "Document": 4}
2323

2424
_ANNOTATION_STATUSES = {
2525
"NotStarted": 1,
@@ -59,45 +59,96 @@
5959
"Semantic Segmentation for Pixel Projects": "semantic_segmentation_pixel"
6060
}
6161

62-
VIDEO_DEPRICATED_FUNCTIONS = [
63-
"upload_images_from_folder_to_project",
64-
"get_image_metadata",
65-
"search_images",
66-
"upload_images_to_project",
67-
"upload_annotations_from_folder_to_project",
68-
"upload_image_annotations",
69-
"download_image",
70-
"download_image_annotations",
71-
"get_image_annotations",
72-
"set_image_annotation_status",
73-
"aggregate_annotations_as_df",
74-
"attach_image_urls_to_project",
75-
"clone_project",
76-
"copy_image",
77-
"export_annotation",
78-
"upload_image_to_project",
79-
"upload_video_to_project",
80-
"add_annotation_bbox_to_image",
81-
"assign_images",
82-
"delete_images",
83-
"get_project_image_count",
84-
"set_project_workflow",
85-
"upload_preannotations_from_folder_to_project",
86-
"upload_videos_from_folder_to_project",
87-
"add_annotation_comment_to_image",
88-
"add_annotation_point_to_image",
89-
"benchmark",
90-
"class_distribution",
91-
"consensus",
92-
"convert_project_type",
93-
"copy_images",
94-
"get_project_workflow",
95-
"move_image",
96-
"move_images",
97-
"set_images_annotation_statuses",
98-
"set_project_default_image_quality_in_editor",
99-
"upload_images_from_google_cloud_to_project",
100-
]
62+
DEPRICATED_FUNCTIONS_PER_PROJECT_TYPE = {
63+
"Vector": [],
64+
"Pixel": [],
65+
"Video": [
66+
"attach_document_urls_to_project",
67+
"upload_images_from_folder_to_project",
68+
"get_image_metadata",
69+
"search_images",
70+
"upload_images_to_project",
71+
"upload_annotations_from_folder_to_project",
72+
"upload_image_annotations",
73+
"download_image",
74+
"download_image_annotations",
75+
"get_image_annotations",
76+
"set_image_annotation_status",
77+
"aggregate_annotations_as_df",
78+
"attach_image_urls_to_project",
79+
"clone_project",
80+
"copy_image",
81+
"export_annotation",
82+
"upload_image_to_project",
83+
"upload_video_to_project",
84+
"add_annotation_bbox_to_image",
85+
"assign_images",
86+
"delete_images",
87+
"get_project_image_count",
88+
"set_project_workflow",
89+
"upload_preannotations_from_folder_to_project",
90+
"upload_videos_from_folder_to_project",
91+
"add_annotation_comment_to_image",
92+
"add_annotation_point_to_image",
93+
"benchmark",
94+
"class_distribution",
95+
"consensus",
96+
"convert_project_type",
97+
"copy_images",
98+
"get_project_workflow",
99+
"move_image",
100+
"move_images",
101+
"set_images_annotation_statuses",
102+
"set_project_default_image_quality_in_editor",
103+
"upload_images_from_google_cloud_to_project",
104+
"get_image_bytes",
105+
"upload_images_from_azure_blob_to_project",
106+
"upload_images_from_public_urls_to_project"
107+
],
108+
"Document": [
109+
"attach_video_urls_to_project",
110+
"upload_images_from_folder_to_project",
111+
"get_image_metadata",
112+
"search_images",
113+
"upload_images_to_project",
114+
"upload_annotations_from_folder_to_project",
115+
"upload_image_annotations",
116+
"download_image",
117+
"download_image_annotations",
118+
"get_image_annotations",
119+
"set_image_annotation_status",
120+
"aggregate_annotations_as_df",
121+
"attach_image_urls_to_project",
122+
"clone_project",
123+
"copy_image",
124+
"export_annotation",
125+
"upload_image_to_project",
126+
"upload_video_to_project",
127+
"add_annotation_bbox_to_image",
128+
"assign_images",
129+
"delete_images",
130+
"get_project_image_count",
131+
"set_project_workflow",
132+
"upload_preannotations_from_folder_to_project",
133+
"upload_videos_from_folder_to_project",
134+
"add_annotation_comment_to_image",
135+
"add_annotation_point_to_image",
136+
"benchmark",
137+
"class_distribution",
138+
"consensus",
139+
"convert_project_type",
140+
"copy_images",
141+
"get_project_workflow",
142+
"move_image",
143+
"move_images",
144+
"set_images_annotation_statuses",
145+
"set_project_default_image_quality_in_editor",
146+
"upload_images_from_google_cloud_to_project",
147+
"get_image_bytes",
148+
"upload_images_from_azure_blob_to_project",
149+
"upload_images_from_public_urls_to_project"
150+
],
151+
}
101152

102153

103154
def prediction_segmentation_status_from_str_to_int(status):
@@ -364,7 +415,7 @@ def write_to_json(output_path, json_data):
364415

365416

366417
def tqdm_converter(
367-
total_num, images_converted, images_not_converted, finish_event
418+
total_num, images_converted, images_not_converted, finish_event
368419
):
369420
with tqdm(total=total_num) as pbar:
370421
while True:

superannotate/db/exports.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,10 @@ def prepare_export(
135135
"Include fuse functionality is not supported for projects containing items attached with URLs"
136136
)
137137
include_fuse = False
138-
if project["type"] == "Video":
138+
if project["type"] in ["Video","Document"]:
139139
if only_pinned:
140140
logger.warning(
141-
"Pin functionality is not supported for projects containing videos attached with URLs"
141+
f"Pin functionality is not supported for projects containing {project['type']} attached with URLs"
142142
)
143143
only_pinned, include_fuse = False, False
144144

superannotate/db/images.py

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -659,12 +659,6 @@ def download_image(
659659
)
660660

661661
project, project_folder = get_project_and_folder_metadata(project)
662-
upload_state = common.upload_state_int_to_str(project.get("upload_state"))
663-
if upload_state == "External":
664-
raise SABaseException(
665-
0,
666-
"The function does not support projects containing images attached with URLs"
667-
)
668662
img = get_image_bytes(
669663
(project, project_folder), image_name, variant=variant
670664
)
@@ -735,12 +729,7 @@ def get_image_bytes(project, image_name, variant='original'):
735729
:rtype: io.BytesIO()
736730
"""
737731
project, project_folder = get_project_and_folder_metadata(project)
738-
upload_state = common.upload_state_int_to_str(project.get("upload_state"))
739-
if upload_state == "External":
740-
raise SABaseException(
741-
0,
742-
"The function does not support projects containing images attached with URLs"
743-
)
732+
744733
if variant not in ["original", "lores"]:
745734
raise SABaseException(
746735
0, "Image download variant should be either original or lores"
@@ -987,6 +976,7 @@ def upload_image_annotations(
987976
:param mask: BytesIO object or filepath to mask annotation for pixel projects in SuperAnnotate format
988977
:type mask: BytesIO or Pathlike (str or Path)
989978
"""
979+
project, project_folder = get_project_and_folder_metadata(project)
990980

991981
if isinstance(annotation_json, list):
992982
raise SABaseException(
@@ -997,7 +987,6 @@ def upload_image_annotations(
997987
if verbose:
998988
logger.info("Uploading annotations from %s.", annotation_json)
999989
annotation_json = json.load(open(annotation_json))
1000-
project, project_folder = get_project_and_folder_metadata(project)
1001990
image = get_image_metadata((project, project_folder), image_name)
1002991
team_id, project_id, image_id, folder_id, image_name = image[
1003992
"team_id"], image["project_id"], image["id"], image['folder_id'], image[

superannotate/db/project_api.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,19 @@ def get_project_metadata_bare(project_name, include_complete_image_count=False):
4242
res = results[0]
4343
res["type"] = common.project_type_int_to_str(res["type"])
4444
res["user_role"] = common.user_role_int_to_str(res["user_role"])
45+
project_type = res["type"]
4546
current_frame = inspect.currentframe()
4647
outer_function = inspect.getframeinfo(current_frame.f_back).function
4748
outer_outer_function = inspect.getframeinfo(
4849
current_frame.f_back.f_back
4950
).function
50-
if res.get("type") and res["type"] == "Video" and (
51-
outer_function in common.VIDEO_DEPRICATED_FUNCTIONS or
52-
outer_outer_function in common.VIDEO_DEPRICATED_FUNCTIONS
51+
if res.get("type") and res["type"] in ["Video","Document"] and (
52+
outer_function in common.DEPRICATED_FUNCTIONS_PER_PROJECT_TYPE[res["type"]] or
53+
outer_outer_function in common.DEPRICATED_FUNCTIONS_PER_PROJECT_TYPE[res["type"]]
5354
):
5455
raise SABaseException(
5556
0,
56-
"The function does not support projects containing videos attached with URLs"
57+
f"The function does not support projects containing {project_type} attached with URLs"
5758
)
5859
return res
5960
else:
@@ -150,12 +151,13 @@ def get_project_and_folder_metadata(project):
150151
outer_outer_function = inspect.getframeinfo(
151152
current_frame.f_back.f_back
152153
).function
153-
if project.get("type") and project["type"] == "Video" \
154-
and (outer_function in common.VIDEO_DEPRICATED_FUNCTIONS
155-
or outer_outer_function in common.VIDEO_DEPRICATED_FUNCTIONS):
154+
if project.get("type") and project["type"] in ["Video","Document"] \
155+
and (outer_function in common.DEPRICATED_FUNCTIONS_PER_PROJECT_TYPE[project["type"]]
156+
or outer_outer_function in common.DEPRICATED_FUNCTIONS_PER_PROJECT_TYPE[project["type"]]):
157+
project_type = project['type']
156158
raise SABaseException(
157159
0,
158-
"The function does not support projects containing videos attached with URLs"
160+
f"The function does not support projects containing {project_type} attached with URLs"
159161
)
160162
return project, folder
161163

superannotate/db/project_images.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,6 @@ def upload_image_to_project(
5757
"""
5858
initial_project_inp = project
5959
project, folder = get_project_and_folder_metadata(project)
60-
upload_state = common.upload_state_int_to_str(project.get("upload_state"))
61-
if upload_state == "External":
62-
raise SABaseException(
63-
0,
64-
"The function does not support projects containing images attached with URLs"
65-
)
6660
annotation_status = common.annotation_status_str_to_int(annotation_status)
6761
if image_quality_in_editor is None:
6862
image_quality_in_editor = get_project_default_image_quality_in_editor(

0 commit comments

Comments
 (0)