Skip to content
Merged
15 changes: 15 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ History

All release highlights of this project will be documented in this file.

4.4.34 - April 11, 2025
______________________

**Added**

- ``SAClient.get_integrations`` Added id, createdAt, updatedAt, and creator_id in integration metadata.
- ``SAClient.list_workflows`` Retrieves all workflows for your team along with their metadata.

**Updated**
- ``SAClient.get_project_metadata``

**Removed**
- ``SAClient.get_project_workflow``
- ``SAClient.set_project_workflow``

4.4.33 - April 1, 2025
______________________

Expand Down
2 changes: 0 additions & 2 deletions docs/source/api_reference/api_project.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,4 @@ Projects
.. automethod:: superannotate.SAClient.set_project_default_image_quality_in_editor
.. automethod:: superannotate.SAClient.set_project_steps
.. automethod:: superannotate.SAClient.get_project_steps
.. automethod:: superannotate.SAClient.set_project_workflow
.. automethod:: superannotate.SAClient.get_project_workflow
.. automethod:: superannotate.SAClient.get_component_config
1 change: 1 addition & 0 deletions docs/source/api_reference/api_team.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Team


.. automethod:: superannotate.SAClient.get_team_metadata
.. automethod:: superannotate.SAClient.list_workflows
.. automethod:: superannotate.SAClient.get_integrations
.. automethod:: superannotate.SAClient.invite_contributors_to_team
.. automethod:: superannotate.SAClient.search_team_contributors
Expand Down
2 changes: 1 addition & 1 deletion pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ minversion = 3.7
log_cli=true
python_files = test_*.py
;pytest_plugins = ['pytest_profiling']
addopts = -n 6 --dist loadscope
;addopts = -n 6 --dist loadscope
2 changes: 1 addition & 1 deletion src/superannotate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import sys


__version__ = "4.4.33"
__version__ = "4.4.34"


os.environ.update({"sa_version": __version__})
Expand Down
169 changes: 106 additions & 63 deletions src/superannotate/lib/app/interface/sdk_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@
from lib.infrastructure.validators import wrap_error
from lib.app.serializers import WMProjectSerializer
from lib.core.entities.work_managament import WMUserTypeEnum
from lib.core.jsx_conditions import EmptyQuery


logger = logging.getLogger("sa")

Expand Down Expand Up @@ -211,7 +213,7 @@ def __exit__(self, exc_type, exc_val, exc_tb):
return True

def save(self):
if len(json.dumps(self.annotation).encode("utf-8")) > 16 * 1024 * 1024:
if len(json.dumps(self.annotation).encode("utf-8")) > 15 * 1024 * 1024:
self._set_large_annotation_adapter(self.annotation)
else:
self._set_small_annotation_adapter(self.annotation)
Expand Down Expand Up @@ -1354,7 +1356,7 @@ def get_project_metadata(
the key "settings"
:type include_settings: bool

:param include_workflow: Deprecated
:param include_workflow: Returns workflow metadata
:type include_workflow: bool

:param include_contributors: enables project contributors output under
Expand All @@ -1377,6 +1379,7 @@ def get_project_metadata(

client.get_project_metadata(
project="Medical Annotations",
include_workflow=True,
include_custom_fields=True
)

Expand All @@ -1385,50 +1388,53 @@ def get_project_metadata(
::

{
"classes": [],
"completed_items_count": None,
"contributors": [],
"createdAt": "2025-02-04T12:04:01+00:00",
"updatedAt": "2024-02-04T12:04:01+00:00",
"id": 902174,
"team_id": 233435,
"name": "Medical Annotations",
"type": "Vector",
"description": "DESCRIPTION",
"instructions_link": None,
"creator_id": "ecample@email.com",
"entropy_status": 1,
"sharing_status": None,
"status": "NotStarted",
"folder_id": 1191383,
"workflow_id": 1,
"workflow": {
"createdAt": "2024-09-03T12:48:09+00:00",
"updatedAt": "2024-09-03T12:48:09+00:00",
"id": 1,
"name": "System workflow",
"type": "system",
"description": "This workflow is generated by the system, and prevents annotators from completing items.",
"raw_config": {"roles": ["Annotator", "QA"], ...}
},
"upload_state": "INITIAL",
"users": [],
"contributors": [],
"settings": [],
"classes": [],
"item_count": None,
"completed_items_count": None,
"root_folder_completed_items_count": None,
"custom_fields": {
"Notes": "Something",
"Ann Quality threshold": 80,
"Tag": ["Tag1", "Tag2", "Tag3"],
"Due date": 1738281600.0,
"Other_Custom_Field": None,
},
"description": "DESCRIPTION",
"entropy_status": 1,
"folder_id": 1191383,
"id": 902174,
"instructions_link": None,
"item_count": None,
"name": "Medical Annotations",
"root_folder_completed_items_count": None,
"settings": [],
"sharing_status": None,
"status": "NotStarted",
"team_id": 233435,
"type": "Vector",
"updatedAt": "2024-02-04T12:04:01+00:00",
"upload_state": "INITIAL",
"users": [],
"workflow_id": 1,
}
}
"""
project_name, _ = extract_project_folder(project)
project = self.controller.get_project(project_name)
if include_workflow:
warnings.warn(
DeprecationWarning(
"The “include_workflow” parameter is deprecated."
" Please use the “get_project_steps” function instead."
)
)
response = self.controller.projects.get_metadata(
project,
include_annotation_classes,
include_settings,
include_workflow,
include_contributors,
include_complete_item_count,
include_custom_fields,
Expand Down Expand Up @@ -1464,18 +1470,6 @@ def get_project_settings(self, project: Union[NotEmptyStr, dict]):
]
return settings

def get_project_workflow(self, project: Union[str, dict]):
"""
Deprecated
"""
warnings.warn(
DeprecationWarning(
"The “get_project_workflow” function is deprecated."
" Please use the “get_project_steps” function instead."
)
)
return self.get_project_steps(project)

def get_project_steps(self, project: Union[str, dict]):
"""Gets project's steps.

Expand Down Expand Up @@ -1509,10 +1503,10 @@ def get_project_steps(self, project: Union[str, dict]):
"""
project_name, _ = extract_project_folder(project)
project = self.controller.get_project(project_name)
workflow = self.controller.projects.list_workflow(project)
if workflow.errors:
raise AppException(workflow.errors)
return workflow.data
steps = self.controller.projects.list_steps(project)
if steps.errors:
raise AppException(steps.errors)
return steps.data

def search_annotation_classes(
self, project: Union[NotEmptyStr, dict], name_contains: Optional[str] = None
Expand Down Expand Up @@ -2502,19 +2496,6 @@ def download_export(
if response.errors:
raise AppException(response.errors)

def set_project_workflow(
self, project: Union[NotEmptyStr, dict], new_workflow: List[dict]
):
"""
Deprecated
"""
warnings.warn(
DeprecationWarning(
"The “set_project_workflow” function is deprecated. Please use the “set_project_steps” function instead."
)
)
return self.set_project_steps(project, new_workflow)

def set_project_steps(self, project: Union[NotEmptyStr, dict], steps: List[dict]):
"""Sets project's steps.

Expand Down Expand Up @@ -2548,7 +2529,7 @@ def set_project_steps(self, project: Union[NotEmptyStr, dict], steps: List[dict]
"""
project_name, _ = extract_project_folder(project)
project = self.controller.get_project(project_name)
response = self.controller.projects.set_workflows(project, steps=steps)
response = self.controller.projects.set_steps(project, steps=steps)
if response.errors:
raise AppException(response.errors)

Expand Down Expand Up @@ -3273,14 +3254,33 @@ def get_integrations(self):

:return: metadata objects of all integrations of the team.
:rtype: list of dicts

Request Example:
::

client.get_integrations()


Response Example:
::

[
{
"createdAt": "2023-11-27T11:16:02.000Z",
"id": 5072,
"name": "My S3 Bucket",
"root": "test-openseadragon-1212",
"type": "aws",
"updatedAt": "2023-12-27T11:16:02.000Z",
"creator_id": "example@superannotate.com"
}
]
"""
response = self.controller.integrations.list()
if response.errors:
raise AppException(response.errors)
integrations = response.data
return BaseSerializer.serialize_iterable(
integrations, ("name", "type", "root") # noqa
)
return BaseSerializer.serialize_iterable(integrations)

def attach_items_from_integrated_storage(
self,
Expand Down Expand Up @@ -4783,3 +4783,46 @@ def item_context(
item=_item,
overwrite=overwrite,
)

def list_workflows(self):
"""
Lists team’s all workflows and their metadata

:return: metadata of workflows
:rtype: list of dicts


Request Example:
::

client.list_workflows()


Response Example:
::

[
{
"createdAt": "2024-09-03T12:48:09+00:00",
"updatedAt": "2024-09-04T12:48:09+00:00",
"id": 1,
"name": "System workflow",
"type": "system",
"description": "This workflow is generated by the system, and prevents annotators from completing items.",
"raw_config": {"roles": ["Annotator", "QA"], ...}
},
{
"createdAt": "2025-01-03T12:48:09+00:00",
"updatedAt": "2025-01-05T12:48:09+00:00",
"id": 58758,
"name": "Custom workflow",
"type": "user",
"description": "This workflow custom build.",
"raw_config": {"roles": ["Custom Annotator", "Custom QA"], ...}
}
]
"""
workflows = self.controller.service_provider.work_management.list_workflows(
EmptyQuery()
)
return BaseSerializer.serialize_iterable(workflows.data)
2 changes: 1 addition & 1 deletion src/superannotate/lib/core/entities/integrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

class IntegrationEntity(TimedBaseModel):
id: int = None
user_id: str = None
creator_id: str = None
name: str
type: IntegrationTypeEnum = Field(None, alias="source")
root: str = Field(None, alias="bucket_name")
Expand Down
27 changes: 15 additions & 12 deletions src/superannotate/lib/core/entities/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,20 @@ class Config:
extra = Extra.ignore


class WorkflowEntity(TimedBaseModel):
id: Optional[int]
name: Optional[str]
type: Optional[str]
description: Optional[str]
raw_config: Optional[dict]

def is_system(self):
return self.type == "system"

class Config:
extra = Extra.ignore


class ProjectEntity(TimedBaseModel):
id: Optional[int]
team_id: Optional[int]
Expand All @@ -101,6 +115,7 @@ class ProjectEntity(TimedBaseModel):
status: Optional[ProjectStatus]
folder_id: Optional[int]
workflow_id: Optional[int]
workflow: Optional[WorkflowEntity]
sync_status: Optional[int]
upload_state: Optional[int]
users: Optional[List[ContributorEntity]] = []
Expand Down Expand Up @@ -175,15 +190,3 @@ class CustomFieldEntity(BaseModel):

class Config:
extra = Extra.allow


class WorkflowEntity(BaseModel):
id: Optional[int]
name: Optional[str]
type: Optional[str]

def is_system(self):
return self.type == "system"

class Config:
extra = Extra.ignore
10 changes: 4 additions & 6 deletions src/superannotate/lib/core/serviceproviders.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,17 +261,15 @@ def set_settings(
raise NotImplementedError

@abstractmethod
def list_workflows(self, project: entities.ProjectEntity):
def list_steps(self, project: entities.ProjectEntity):
raise NotImplementedError

@abstractmethod
def set_workflow(
self, project: entities.ProjectEntity, workflow: entities.WorkflowEntity
):
def set_step(self, project: entities.ProjectEntity, step: entities.StepEntity):
raise NotImplementedError

@abstractmethod
def set_workflows(self, project: entities.ProjectEntity, steps: list):
def set_steps(self, project: entities.ProjectEntity, steps: list):
raise NotImplementedError

@abstractmethod
Expand All @@ -283,7 +281,7 @@ def un_share(self, project: entities.ProjectEntity, user_id) -> ServiceResponse:
raise NotImplementedError

@abstractmethod
def set_project_workflow_attributes(
def set_project_step_attributes(
self, project: entities.ProjectEntity, attributes: list
):
raise NotImplementedError
Expand Down
Loading
Loading