Skip to content

Commit 3f4368b

Browse files
committed
Added integrations
1 parent 2750f6d commit 3f4368b

File tree

16 files changed

+662
-324
lines changed

16 files changed

+662
-324
lines changed

src/superannotate/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
from superannotate.lib.app.interface.sdk_interface import aggregate_annotations_as_df
2222
from superannotate.lib.app.interface.sdk_interface import assign_folder
2323
from superannotate.lib.app.interface.sdk_interface import assign_images
24+
from superannotate.lib.app.interface.sdk_interface import get_integrations
25+
from superannotate.lib.app.interface.sdk_interface import attach_items_from_integrated_storage
2426
from superannotate.lib.app.interface.sdk_interface import (
2527
attach_document_urls_to_project,
2628
)
@@ -135,6 +137,9 @@
135137
# annotations
136138
"get_annotations",
137139
"get_annotations_per_frame",
140+
# integrations
141+
"get_integrations",
142+
"attach_items_from_integrated_storage",
138143
# converters
139144
"convert_json_version",
140145
"import_annotation",

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from lib.app.serializers import SettingsSerializer
3535
from lib.app.serializers import TeamSerializer
3636
from lib.core import LIMITED_FUNCTIONS
37+
from lib.core.entities.integrations import IntegrationEntity
3738
from lib.core.entities.project_entities import AnnotationClassEntity
3839
from lib.core.enums import ImageQuality
3940
from lib.core.exceptions import AppException
@@ -2923,3 +2924,49 @@ def upload_priority_scores(project: NotEmptyStr, scores: List[PriorityScore]):
29232924
if response.errors:
29242925
raise AppException(response.errors)
29252926
return response.data
2927+
2928+
2929+
@Trackable
2930+
@validate_arguments
2931+
def get_integrations():
2932+
"""Get all integrations per team
2933+
2934+
:return: metadata objects of all integrations of the team.
2935+
:rtype: list of dicts
2936+
"""
2937+
response = Controller.get_default().get_integrations()
2938+
if response.errors:
2939+
raise AppException(response.errors)
2940+
integrations = response.data
2941+
return BaseSerializers.serialize_iterable(integrations, ("name", "type", "root"))
2942+
2943+
2944+
@Trackable
2945+
@validate_arguments
2946+
def attach_items_from_integrated_storage(
2947+
project: NotEmptyStr,
2948+
integration: Union[NotEmptyStr, IntegrationEntity],
2949+
folder_path: Optional[NotEmptyStr] = None
2950+
):
2951+
"""Link images from integrated external storage to SuperAnnotate.
2952+
2953+
:param project: project name or folder path where items should be attached (e.g., “project1/folder1”).
2954+
:type project: str
2955+
2956+
:param project: project name or folder path where items should be attached (e.g., “project1/folder1”).
2957+
:type project: str
2958+
2959+
:param integration: existing integration name or metadata dict to pull items from.
2960+
Mandatory keys in integration metadata’s dict is “name”.
2961+
:type integration: str
2962+
2963+
:param folder_path: Points to an exact folder/directory within given storage.
2964+
If None, items are fetched from the root directory.
2965+
:type folder_path: str
2966+
"""
2967+
project_name, folder_name = extract_project_folder(project)
2968+
if isinstance(integration, str):
2969+
integration = IntegrationEntity(name=integration)
2970+
response = Controller.get_default().attach_integrations(project_name, folder_name, integration, folder_path)
2971+
if response.errors:
2972+
raise AppException(response.errors)

src/superannotate/lib/app/mixp/utils/parsers.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import lib.core as constances
22
from lib.app.helpers import extract_project_folder
33
from lib.core.enums import ProjectType
4+
from lib.core.entities import IntegrationEntity
45
from lib.infrastructure.controller import Controller
56

67

@@ -1238,3 +1239,36 @@ def upload_priority_scores(*args, **kwargs):
12381239
"event_name": "upload_priority_scores",
12391240
"properties": {"Score Count": len(scores)},
12401241
}
1242+
1243+
1244+
def get_integrations(*args, **kwargs):
1245+
return {
1246+
"event_name": "get_integrations",
1247+
"properties": {},
1248+
}
1249+
1250+
1251+
def attach_items_from_integrated_storage(*args, **kwargs):
1252+
project = kwargs.get("project")
1253+
integration = kwargs.get("integration")
1254+
folder_path = kwargs.get("folder_path")
1255+
if not project:
1256+
project = args[0]
1257+
if not integration:
1258+
integration = args[1]
1259+
if not folder_path:
1260+
folder_path = args[2]
1261+
1262+
project_name, _ = extract_project_folder(project)
1263+
if isinstance(integration, str):
1264+
integration = IntegrationEntity(name=integration)
1265+
project = Controller.get_default().get_project_metadata(project_name)
1266+
return {
1267+
"event_name": "attach_items_from_integrated_storage",
1268+
"properties": {
1269+
"project_type": ProjectType.get_name(project.project_type),
1270+
"integration_name": integration.name,
1271+
"folder_path": bool(folder_path)
1272+
},
1273+
}
1274+

src/superannotate/lib/app/serializers.py

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
from abc import ABC
2+
from typing import List
3+
from typing import Set
4+
from typing import Union
5+
from typing import Any
26

37
import superannotate.lib.core as constance
48
from pydantic import BaseModel
@@ -11,12 +15,37 @@ class BaseSerializers(ABC):
1115
def __init__(self, entity: BaseEntity):
1216
self._entity = entity
1317

14-
def serialize(self):
15-
if isinstance(self._entity, dict):
16-
return self._entity
17-
if isinstance(self._entity, BaseModel):
18-
return self._entity.dict(by_alias=True)
19-
return self._entity.to_dict()
18+
def serialize(self, fields: List[str] = None, by_alias: bool = True, flat: bool = False):
19+
return self._serialize(self._entity, fields, by_alias, flat)
20+
21+
@staticmethod
22+
def _serialize(entity: Any, fields: List[str] = None, by_alias: bool = False, flat: bool = False):
23+
if isinstance(entity, dict):
24+
return entity
25+
if isinstance(entity, BaseModel):
26+
if fields:
27+
fields = set(fields)
28+
if len(fields) == 1:
29+
if flat:
30+
return entity.dict(include=fields, by_alias=by_alias)[next(iter(fields))]
31+
else:
32+
return entity.dict(include=fields, by_alias=by_alias)
33+
return entity.dict(include=fields, by_alias=by_alias)
34+
return entity.dict(by_alias=by_alias)
35+
return entity.to_dict()
36+
37+
@classmethod
38+
def serialize_iterable(
39+
cls,
40+
data: List[Any],
41+
fields: Union[List[str], Set[str]] = None,
42+
by_alias: bool = False,
43+
flat: bool = False
44+
) -> List[Any]:
45+
serialized_data = []
46+
for i in data:
47+
serialized_data.append(cls._serialize(i, fields, by_alias, flat))
48+
return serialized_data
2049

2150

2251
class UserSerializer(BaseSerializers):

src/superannotate/lib/core/entities/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from lib.core.entities.project_entities import TeamEntity
1212
from lib.core.entities.project_entities import UserEntity
1313
from lib.core.entities.project_entities import WorkflowEntity
14+
from lib.core.entities.integrations import IntegrationEntity
1415
from superannotate_schemas.schemas.internal.document import DocumentAnnotation
1516
from superannotate_schemas.schemas.internal.pixel import PixelAnnotation
1617
from superannotate_schemas.schemas.internal.vector import VectorAnnotation
@@ -33,6 +34,7 @@
3334
"UserEntity",
3435
"TeamEntity",
3536
"MLModelEntity",
37+
"IntegrationEntity",
3638
# annotations
3739
"DocumentAnnotation",
3840
"VideoAnnotation",
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from datetime import datetime
2+
3+
from pydantic import BaseModel
4+
from pydantic import Field
5+
6+
7+
class TimedBaseModel(BaseModel):
8+
created_at: datetime = Field(None, alias="createdAt")
9+
updated_at: datetime = Field(None, alias="updatedAt")
10+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from pydantic import Field
2+
from lib.core.entities.base import TimedBaseModel
3+
4+
5+
class IntegrationEntity(TimedBaseModel):
6+
id: int = None
7+
user_id: str = None
8+
name: str
9+
type: str = "aws"
10+
root: str = Field(None, alias="bucket_name")
11+
source: int = None
12+
13+
class Config:
14+
arbitrary_types_allowed = True

0 commit comments

Comments
 (0)