Skip to content

Commit 454af54

Browse files
authored
Merge pull request #433 from superannotateai/friday
Friday
2 parents 3b09c7d + b205a64 commit 454af54

File tree

88 files changed

+2652
-3371
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+2652
-3371
lines changed

.github/workflows/pre_release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
- name: Install dependencies
1717
run: |
1818
python -m pip install --upgrade pip
19-
pip install setuptools wheel twine
19+
pip install setuptools wheel twine packaging
2020
- name: Create distribution files
2121
run: python setup.py sdist
2222
- name: Publish distribution to PyPI

docs/source/superannotate.sdk.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ ________
2929
.. _ref_get_project_metadata:
3030
.. autofunction:: superannotate.get_project_metadata
3131
.. autofunction:: superannotate.get_project_image_count
32-
.. autofunction:: superannotate.get_project_and_folder_metadata
3332
.. autofunction:: superannotate.search_folders
3433
.. autofunction:: superannotate.get_folder_metadata
3534
.. autofunction:: superannotate.create_folder
@@ -74,7 +73,11 @@ ______
7473

7574
.. autofunction:: superannotate.query
7675
.. autofunction:: superannotate.search_items
76+
.. autofunction:: superannotate.attach_items
77+
.. autofunction:: superannotate.copy_items
78+
.. autofunction:: superannotate.move_items
7779
.. autofunction:: superannotate.get_item_metadata
80+
.. autofunction:: superannotate.set_annotation_statuses
7881

7982
----------
8083

@@ -83,9 +86,6 @@ ______
8386

8487

8588
.. _ref_search_images:
86-
.. autofunction:: superannotate.search_images
87-
.. autofunction:: superannotate.search_images_all_folders
88-
.. autofunction:: superannotate.get_image_metadata
8989
.. autofunction:: superannotate.download_image
9090
.. autofunction:: superannotate.set_image_annotation_status
9191
.. autofunction:: superannotate.set_images_annotation_statuses

pytest.ini

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[pytest]
2-
minversion = 3.0
2+
minversion = 3.7
33
log_cli=true
44
python_files = test_*.py
5-
;addopts = -n auto --dist=loadscope
5+
addopts = -n auto --dist=loadscope

requirements_dev.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
superannotate_schemas>=1.0.41b1
1+
superannotate_schemas>=v1.0.42dev2
22

src/superannotate/__init__.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
attach_document_urls_to_project,
2626
)
2727
from superannotate.lib.app.interface.sdk_interface import attach_image_urls_to_project
28+
from superannotate.lib.app.interface.sdk_interface import attach_items
2829
from superannotate.lib.app.interface.sdk_interface import (
2930
attach_items_from_integrated_storage,
3031
)
@@ -34,6 +35,7 @@
3435
from superannotate.lib.app.interface.sdk_interface import consensus
3536
from superannotate.lib.app.interface.sdk_interface import copy_image
3637
from superannotate.lib.app.interface.sdk_interface import copy_images
38+
from superannotate.lib.app.interface.sdk_interface import copy_items
3739
from superannotate.lib.app.interface.sdk_interface import create_annotation_class
3840
from superannotate.lib.app.interface.sdk_interface import (
3941
create_annotation_classes_from_classes_json,
@@ -57,12 +59,8 @@
5759
from superannotate.lib.app.interface.sdk_interface import get_annotations_per_frame
5860
from superannotate.lib.app.interface.sdk_interface import get_exports
5961
from superannotate.lib.app.interface.sdk_interface import get_folder_metadata
60-
from superannotate.lib.app.interface.sdk_interface import get_image_metadata
6162
from superannotate.lib.app.interface.sdk_interface import get_integrations
6263
from superannotate.lib.app.interface.sdk_interface import get_item_metadata
63-
from superannotate.lib.app.interface.sdk_interface import (
64-
get_project_and_folder_metadata,
65-
)
6664
from superannotate.lib.app.interface.sdk_interface import get_project_image_count
6765
from superannotate.lib.app.interface.sdk_interface import get_project_metadata
6866
from superannotate.lib.app.interface.sdk_interface import get_project_settings
@@ -71,19 +69,19 @@
7169
from superannotate.lib.app.interface.sdk_interface import init
7270
from superannotate.lib.app.interface.sdk_interface import invite_contributors_to_team
7371
from superannotate.lib.app.interface.sdk_interface import move_images
72+
from superannotate.lib.app.interface.sdk_interface import move_items
7473
from superannotate.lib.app.interface.sdk_interface import pin_image
7574
from superannotate.lib.app.interface.sdk_interface import prepare_export
7675
from superannotate.lib.app.interface.sdk_interface import query
7776
from superannotate.lib.app.interface.sdk_interface import rename_project
7877
from superannotate.lib.app.interface.sdk_interface import run_prediction
7978
from superannotate.lib.app.interface.sdk_interface import search_annotation_classes
8079
from superannotate.lib.app.interface.sdk_interface import search_folders
81-
from superannotate.lib.app.interface.sdk_interface import search_images
82-
from superannotate.lib.app.interface.sdk_interface import search_images_all_folders
8380
from superannotate.lib.app.interface.sdk_interface import search_items
8481
from superannotate.lib.app.interface.sdk_interface import search_models
8582
from superannotate.lib.app.interface.sdk_interface import search_projects
8683
from superannotate.lib.app.interface.sdk_interface import search_team_contributors
84+
from superannotate.lib.app.interface.sdk_interface import set_annotation_statuses
8785
from superannotate.lib.app.interface.sdk_interface import set_auth_token
8886
from superannotate.lib.app.interface.sdk_interface import set_image_annotation_status
8987
from superannotate.lib.app.interface.sdk_interface import set_images_annotation_statuses
@@ -161,29 +159,29 @@
161159
"rename_project",
162160
"upload_priority_scores",
163161
# Images Section
164-
"search_images",
165162
"copy_image",
166163
# Folders Section
167164
"create_folder",
168165
"get_folder_metadata",
169166
"delete_folders",
170-
"get_project_and_folder_metadata",
171167
"search_folders",
172168
"assign_folder",
173169
"unassign_folder",
174170
# Items Section
175171
"get_item_metadata",
176172
"search_items",
177173
"query",
174+
"attach_items",
175+
"copy_items",
176+
"move_items",
177+
"set_annotation_statuses",
178178
# Image Section
179179
"copy_images",
180180
"move_images",
181181
"delete_images",
182182
"download_image",
183183
"pin_image",
184-
"get_image_metadata",
185184
"get_project_image_count",
186-
"search_images_all_folders",
187185
"assign_images",
188186
"unassign_images",
189187
"download_image_annotations",

src/superannotate/lib/app/analytics/aggregators.py

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,34 @@ class VideoRawData:
5656
attributeName: str = None
5757

5858

59+
class DocumentRawData:
60+
docName: str = None
61+
folderName: str = None
62+
docStatus: str = None
63+
docUrl: str = None
64+
docAnnotator: str = None
65+
docQA: str = None
66+
# tag
67+
tagId: int = None
68+
tag: str = None
69+
# instance
70+
instanceId: int = None
71+
instanceStart: int = None
72+
instanceEnd: int = None
73+
type: str = None
74+
className: str = None
75+
createdAt: str = None
76+
createdBy: str = None
77+
creatorRole: str = None
78+
updatedAt: str = None
79+
updatedBy: str = None
80+
updatorRole: str = None
81+
# attribute
82+
attributeId: int = None
83+
attributeGroupName: str = None
84+
attributeName: str = None
85+
86+
5987
class DataAggregator:
6088
def __init__(
6189
self,
@@ -124,6 +152,8 @@ def aggregate_annotations_as_df(self):
124152
return self.aggregate_image_annotations_as_df(annotation_paths)
125153
elif self.project_type == constances.ProjectType.VIDEO.name:
126154
return self.aggregate_video_annotations_as_df(annotation_paths)
155+
elif self.project_type == constances.ProjectType.DOCUMENT.name:
156+
return self.aggregate_document_annotations_as_df(annotation_paths)
127157

128158
def aggregate_video_annotations_as_df(self, annotation_paths: List[str]):
129159
raws = []
@@ -205,7 +235,61 @@ def aggregate_video_annotations_as_df(self, annotation_paths: List[str]):
205235
raws.append(instance_raw)
206236
if not instances:
207237
raws.append(raw_data)
208-
return pd.DataFrame([raw.__dict__ for raw in raws], dtype=object)
238+
df = pd.DataFrame([raw.__dict__ for raw in raws], dtype=object)
239+
return df.where(pd.notnull(df), None)
240+
241+
def aggregate_document_annotations_as_df(self, annotation_paths: List[str]):
242+
raws = []
243+
for annotation_path in annotation_paths:
244+
annotation_path = Path(annotation_path)
245+
annotation_data = json.load(open(annotation_path))
246+
raw_data = DocumentRawData()
247+
# metadata
248+
raw_data.docName = annotation_data["metadata"]["name"]
249+
raw_data.folderName = (
250+
annotation_path.parent.name
251+
if annotation_path.parent != self.project_root
252+
else None
253+
)
254+
raw_data.docStatus = annotation_data["metadata"].get("status")
255+
raw_data.docUrl = annotation_data["metadata"].get("url")
256+
raw_data.docAnnotator = annotation_data["metadata"].get("annotatorEmail")
257+
raw_data.docQA = annotation_data["metadata"].get("qaEmail")
258+
# append tags
259+
for idx, tag in enumerate(annotation_data.get("tags", [])):
260+
tag_row = copy.copy(raw_data)
261+
tag_row.tagId = idx
262+
tag_row.tag = tag
263+
raws.append(tag_row)
264+
# append instances
265+
instances = annotation_data.get("instances", [])
266+
for idx, instance in enumerate(instances):
267+
instance_raw = copy.copy(raw_data)
268+
instance_raw.instanceId = int(idx)
269+
instance_raw.instanceStart = instance.get("start")
270+
instance_raw.instanceEnd = instance.get("end")
271+
instance_raw.type = instance.get("type")
272+
instance_raw.className = instance.get("className")
273+
instance_raw.createdAt = instance.get("createdAt")
274+
instance_raw.createdBy = instance.get("createdBy", {}).get("email")
275+
instance_raw.creatorRole = instance.get("createdBy", {}).get("role")
276+
instance_raw.updatedAt = instance.get("updatedAt")
277+
instance_raw.updatedBy = instance.get("updatedBy", {}).get("email")
278+
instance_raw.updatorRole = instance.get("updatedBy", {}).get("role")
279+
attributes = instance.get("attributes", [])
280+
# append attributes
281+
for attribute_id, attribute in enumerate(attributes):
282+
attribute_raw = copy.copy(instance_raw)
283+
attribute_raw.attributeId = attribute_id
284+
attribute_raw.attributeGroupName = attribute.get("groupName")
285+
attribute_raw.attributeName = attribute.get("name")
286+
raws.append(attribute_raw)
287+
if not attributes:
288+
raws.append(instance_raw)
289+
if not instances:
290+
raws.append(raw_data)
291+
df = pd.DataFrame([raw.__dict__ for raw in raws], dtype=object)
292+
return df.where(pd.notnull(df), None)
209293

210294
def aggregate_image_annotations_as_df(self, annotations_paths: List[str]):
211295
annotation_data = {

src/superannotate/lib/app/helpers.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import boto3
1010
import pandas as pd
11+
from superannotate.lib.app.exceptions import AppException
1112
from superannotate.lib.app.exceptions import PathError
1213
from superannotate.lib.core import ATTACHED_VIDEO_ANNOTATION_POSTFIX
1314
from superannotate.lib.core import PIXEL_ANNOTATION_POSTFIX
@@ -168,3 +169,33 @@ def get_paths_and_duplicated_from_csv(csv_path):
168169
else:
169170
duplicate_images.append(temp)
170171
return images_to_upload, duplicate_images
172+
173+
174+
def get_name_url_duplicated_from_csv(csv_path):
175+
image_data = pd.read_csv(csv_path, dtype=str)
176+
if "url" not in image_data.columns:
177+
raise AppException("Column 'url' is required")
178+
image_data = image_data[~image_data["url"].isnull()]
179+
if "name" in image_data.columns:
180+
image_data["name"] = (
181+
image_data["name"]
182+
.fillna("")
183+
.apply(lambda cell: cell if str(cell).strip() else str(uuid.uuid4()))
184+
)
185+
else:
186+
image_data["name"] = [str(uuid.uuid4()) for _ in range(len(image_data.index))]
187+
188+
image_data = pd.DataFrame(image_data, columns=["name", "url"])
189+
img_names_urls = image_data.to_dict(orient="records")
190+
duplicate_images = []
191+
seen = []
192+
images_to_upload = []
193+
for i in img_names_urls:
194+
temp = i["name"]
195+
i["name"] = i["name"].strip()
196+
if i["name"] not in seen:
197+
seen.append(i["name"])
198+
images_to_upload.append(i)
199+
else:
200+
duplicate_images.append(temp)
201+
return images_to_upload, duplicate_images

src/superannotate/lib/app/interface/cli_interface.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ def _upload_annotations(
207207
dataset_format=format,
208208
dataset_name=dataset_name,
209209
project_type=constances.ProjectType.get_name(
210-
project["project"].project_type
210+
project["project"].type
211211
),
212212
task=task,
213213
)

0 commit comments

Comments
 (0)