Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/source/api_reference/api_project.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ Projects
.. automethod:: superannotate.SAClient.add_contributors_to_project
.. automethod:: superannotate.SAClient.get_project_settings
.. 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_steps
.. automethod:: superannotate.SAClient.get_component_config
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.35"
__version__ = "4.4.36dev1"


os.environ.update({"sa_version": __version__})
Expand Down
81 changes: 74 additions & 7 deletions src/superannotate/lib/app/interface/sdk_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@
from lib.core.entities.work_managament import WMUserTypeEnum
from lib.core.jsx_conditions import EmptyQuery


logger = logging.getLogger("sa")

NotEmptyStr = constr(strict=True, min_length=1)
Expand Down Expand Up @@ -1493,10 +1492,11 @@ def get_project_steps(self, project: Union[str, dict]):
:param project: project name or metadata
:type project: str or dict

:return: project steps
:rtype: list of dicts
:return: A list of step dictionaries,
or a dictionary containing both steps and their connections (for Keypoint workflows).
:rtype: list of dicts or dict

Response Example:
Response Example for General Annotation Project:
::

[
Expand All @@ -1515,6 +1515,34 @@ def get_project_steps(self, project: Union[str, dict]):
}
]

Response Example for Keypoint Annotation Project:
::

{
"steps": [
{
"step": 1,
"className": "Left Shoulder",
"class_id": "1",
"attribute": [
{
"attribute": {
"id": 123,
"group_id": 12
}
}
]
},
{
"step": 2,
"class_id": "2",
"className": "Right Shoulder",
}
],
"connections": [
[1, 2]
]
}
"""
project_name, _ = extract_project_folder(project)
project = self.controller.get_project(project_name)
Expand Down Expand Up @@ -2511,7 +2539,12 @@ def download_export(
if response.errors:
raise AppException(response.errors)

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

:param project: project name or metadata
Expand All @@ -2520,7 +2553,11 @@ def set_project_steps(self, project: Union[NotEmptyStr, dict], steps: List[dict]
:param steps: new workflow list of dicts
:type steps: list of dicts

Request Example:
:param connections: Defines connections between keypoint annotation steps.
Each inner list specifies a pair of step IDs indicating a connection.
:type connections: list of dicts

Request Example for General Annotation Project:
::

sa.set_project_steps(
Expand All @@ -2541,10 +2578,40 @@ def set_project_steps(self, project: Union[NotEmptyStr, dict], steps: List[dict]
}
]
)

Request Example for Keypoint Annotation Project:
::

sa.set_project_steps(
project="Pose Estimation Project",
steps=[
{
"step": 1,
"class_id": 12,
"attribute": [
{
"attribute": {
"id": 123,
"group_id": 12
}
}
]
},
{
"step": 2,
"class_id": 13
}
],
connections=[
[1, 2]
]
)
"""
project_name, _ = extract_project_folder(project)
project = self.controller.get_project(project_name)
response = self.controller.projects.set_steps(project, steps=steps)
response = self.controller.projects.set_steps(
project, steps=steps, connections=connections
)
if response.errors:
raise AppException(response.errors)

Expand Down
2 changes: 2 additions & 0 deletions src/superannotate/lib/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from lib.core.enums import ImageQuality
from lib.core.enums import ProjectStatus
from lib.core.enums import ProjectType
from lib.core.enums import StepsType
from lib.core.enums import TrainingStatus
from lib.core.enums import UploadState
from lib.core.enums import UserRole
Expand Down Expand Up @@ -186,6 +187,7 @@ def setup_logging(level=DEFAULT_LOGGING_LEVEL, file_path=LOG_FILE_LOCATION):
FolderStatus,
ProjectStatus,
ProjectType,
StepsType,
UserRole,
UploadState,
TrainingStatus,
Expand Down
6 changes: 6 additions & 0 deletions src/superannotate/lib/core/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ def images(self):
return self.VECTOR.value, self.PIXEL.value, self.TILED.value


class StepsType(Enum):
INITIAL = 1
BASIC = 2
KEYPOINT = 3


class UserRole(BaseTitledEnum):
CONTRIBUTOR = "Contributor", 4
ADMIN = "Admin", 7
Expand Down
8 changes: 8 additions & 0 deletions src/superannotate/lib/core/serviceproviders.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,10 +264,18 @@ def set_settings(
def list_steps(self, project: entities.ProjectEntity):
raise NotImplementedError

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

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

@abstractmethod
def set_keypoint_steps(self, project: entities.ProjectEntity, steps, connections):
raise NotImplementedError

@abstractmethod
def set_steps(self, project: entities.ProjectEntity, steps: list):
raise NotImplementedError
Expand Down
15 changes: 7 additions & 8 deletions src/superannotate/lib/core/usecases/annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,10 @@ def log_report(

class ItemToUpload(BaseModel):
item: BaseItemEntity
annotation_json: Optional[dict]
path: Optional[str]
file_size: Optional[int]
mask: Optional[io.BytesIO]
annotation_json: Optional[dict] = None
path: Optional[str] = None
file_size: Optional[int] = None
mask: Optional[io.BytesIO] = None

class Config:
arbitrary_types_allowed = True
Expand Down Expand Up @@ -282,12 +282,12 @@ def validate_project_type(self):
raise AppException("Unsupported project type.")

def _validate_json(self, json_data: dict) -> list:
if self._project.type >= constants.ProjectType.PIXEL.value:
if self._project.type >= int(constants.ProjectType.PIXEL):
return []
use_case = ValidateAnnotationUseCase(
reporter=self.reporter,
team_id=self._project.team_id,
project_type=self._project.type.value,
project_type=self._project.type,
annotation=json_data,
service_provider=self._service_provider,
)
Expand Down Expand Up @@ -2103,8 +2103,7 @@ def execute(self):
for item_name in uploaded_annotations:
category = (
name_annotation_map[item_name]["metadata"]
.get("item_category", {})
.get("value")
.get("item_category", None)
)
if category:
item_id_category_map[name_item_map[item_name].id] = category
Expand Down
Loading