Skip to content

Commit 0e7687f

Browse files
committed
Pydantic changes
1 parent 69c52fd commit 0e7687f

File tree

6 files changed

+215
-102
lines changed

6 files changed

+215
-102
lines changed

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

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -517,17 +517,20 @@ def get_project_metadata(
517517
include_workflow,
518518
include_contributors,
519519
include_complete_image_count,
520-
).data
521-
522-
metadata = ProjectSerializer(response["project"]).serialize()
520+
)
521+
if response.errors:
522+
raise AppException(response.errors)
523523

524-
for elem in "classes", "workflows", "contributors":
525-
if response.get(elem):
526-
metadata[elem] = [
527-
BaseSerializer(attribute).serialize()
528-
for attribute in response[elem]
529-
]
530-
return metadata
524+
return response.data.dict()
525+
# metadata = ProjectSerializer(response["project"]).serialize()
526+
#
527+
# for elem in "classes", "workflows", "contributors":
528+
# if response.get(elem):
529+
# metadata[elem] = [
530+
# BaseSerializer(attribute).serialize()
531+
# for attribute in response[elem]
532+
# ]
533+
# return metadata
531534

532535
def get_project_settings(self, project: Union[NotEmptyStr, dict]):
533536
"""Gets project's settings.

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

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
from lib.core.entities.base import AttachmentEntity
21
from lib.core.entities.base import BaseItemEntity
3-
from lib.core.entities.base import ProjectEntity
4-
from lib.core.entities.base import SettingEntity
52
from lib.core.entities.base import SubSetEntity
3+
from lib.core.entities.project import AttachmentEntity
4+
from lib.core.entities.project import ProjectEntity
5+
from lib.core.entities.project import SettingEntity
66
from lib.core.entities.classes import AnnotationClassEntity
77
from lib.core.entities.integrations import IntegrationEntity
88
from lib.core.entities.items import DocumentEntity
@@ -20,8 +20,6 @@
2020
from lib.core.entities.project_entities import WorkflowEntity
2121

2222

23-
# from lib.core.entities.project_entities import ProjectEntity
24-
2523
__all__ = [
2624
# base
2725
"SettingEntity",
@@ -46,11 +44,5 @@
4644
"UserEntity",
4745
"TeamEntity",
4846
"MLModelEntity",
49-
"IntegrationEntity",
50-
# annotations
51-
"DocumentAnnotation",
52-
"VideoAnnotation",
53-
"VectorAnnotation",
54-
"PixelAnnotation",
55-
"VideoExportAnnotation",
47+
"IntegrationEntity"
5648
]

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

Lines changed: 96 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,109 @@
11
import uuid
22
from datetime import datetime
3+
from enum import Enum
34
from typing import Any
45
from typing import List
56
from typing import Optional
67
from typing import Union
8+
from typing import no_type_check
79

8-
from lib.core.enums import AnnotationStatus
9-
from pydantic import BaseModel
10+
from pydantic import BaseModel as PydanticBaseModel
1011
from pydantic import Extra
1112
from pydantic import Field
12-
from pydantic import StrictBool
13-
from pydantic import StrictFloat
14-
from pydantic import StrictInt
15-
from pydantic import StrictStr
1613
from pydantic.datetime_parse import parse_datetime
14+
from pydantic.typing import is_namedtuple
15+
from pydantic.utils import ROOT_KEY
16+
from pydantic.utils import ValueItems
17+
from pydantic.utils import sequence_like
18+
19+
from lib.core.enums import AnnotationStatus
20+
from lib.core.enums import BaseTitledEnum
21+
22+
try:
23+
from pydantic import AbstractSetIntStr # noqa
24+
from pydantic import MappingIntStrAny # noqa
25+
except ImportError:
26+
pass
27+
28+
29+
class BaseModel(PydanticBaseModel):
30+
"""
31+
32+
"""
33+
@classmethod
34+
@no_type_check
35+
def _get_value(
36+
cls,
37+
v: Any,
38+
to_dict: bool,
39+
by_alias: bool,
40+
include: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']],
41+
exclude: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']],
42+
exclude_unset: bool,
43+
exclude_defaults: bool,
44+
exclude_none: bool,
45+
) -> Any:
46+
47+
if isinstance(v, BaseModel):
48+
if to_dict:
49+
v_dict = v.dict(
50+
by_alias=by_alias,
51+
exclude_unset=exclude_unset,
52+
exclude_defaults=exclude_defaults,
53+
include=include,
54+
exclude=exclude,
55+
exclude_none=exclude_none,
56+
)
57+
if ROOT_KEY in v_dict:
58+
return v_dict[ROOT_KEY]
59+
return v_dict
60+
else:
61+
return v.copy(include=include, exclude=exclude)
62+
63+
value_exclude = ValueItems(v, exclude) if exclude else None
64+
value_include = ValueItems(v, include) if include else None
65+
66+
if isinstance(v, dict):
67+
return {
68+
k_: cls._get_value(
69+
v_,
70+
to_dict=to_dict,
71+
by_alias=by_alias,
72+
exclude_unset=exclude_unset,
73+
exclude_defaults=exclude_defaults,
74+
include=value_include and value_include.for_element(k_),
75+
exclude=value_exclude and value_exclude.for_element(k_),
76+
exclude_none=exclude_none,
77+
)
78+
for k_, v_ in v.items()
79+
if (not value_exclude or not value_exclude.is_excluded(k_))
80+
and (not value_include or value_include.is_included(k_))
81+
}
82+
83+
elif sequence_like(v):
84+
seq_args = (
85+
cls._get_value(
86+
v_,
87+
to_dict=to_dict,
88+
by_alias=by_alias,
89+
exclude_unset=exclude_unset,
90+
exclude_defaults=exclude_defaults,
91+
include=value_include and value_include.for_element(i),
92+
exclude=value_exclude and value_exclude.for_element(i),
93+
exclude_none=exclude_none,
94+
)
95+
for i, v_ in enumerate(v)
96+
if (not value_exclude or not value_exclude.is_excluded(i))
97+
and (not value_include or value_include.is_included(i))
98+
)
99+
100+
return v.__class__(*seq_args) if is_namedtuple(v.__class__) else v.__class__(seq_args)
101+
elif isinstance(v, BaseTitledEnum) and getattr(cls.Config, 'use_enum_names', False):
102+
return v.name
103+
elif isinstance(v, Enum) and getattr(cls.Config, 'use_enum_values', False):
104+
return v.name
105+
else:
106+
return v
17107

18108

19109
class StringDate(datetime):
@@ -70,68 +160,3 @@ def map_fields(entity: dict) -> dict:
70160
entity["annotator_email"] = entity.get("annotator_id")
71161
entity["qa_email"] = entity.get("qa_id")
72162
return entity
73-
74-
75-
class AttachmentEntity(BaseModel):
76-
name: Optional[str] = Field(default_factory=lambda: str(uuid.uuid4()))
77-
url: str
78-
79-
class Config:
80-
extra = Extra.ignore
81-
82-
83-
class SettingEntity(BaseModel):
84-
id: Optional[int]
85-
project_id: Optional[int]
86-
attribute: str
87-
value: Union[StrictStr, StrictInt, StrictFloat, StrictBool]
88-
89-
class Config:
90-
extra = Extra.ignore
91-
92-
def __copy__(self):
93-
return SettingEntity(attribute=self.attribute, value=self.value)
94-
95-
96-
class ProjectEntity(TimedBaseModel):
97-
id: Optional[int]
98-
team_id: Optional[int]
99-
name: Optional[str]
100-
type: Optional[int]
101-
description: Optional[str]
102-
instructions_link: Optional[str]
103-
creator_id: Optional[str]
104-
entropy_status: Optional[int]
105-
sharing_status: Optional[int]
106-
status: Optional[int]
107-
folder_id: Optional[int]
108-
sync_status: Optional[int]
109-
upload_state: Optional[int]
110-
users: Optional[List[Any]] = []
111-
unverified_users: Optional[List[Any]] = []
112-
contributors: Optional[List[Any]] = []
113-
settings: Optional[List[SettingEntity]] = []
114-
classes: Optional[List[Any]] = []
115-
workflows: Optional[List[Any]] = []
116-
completed_images_count: Optional[int] = Field(None, alias="completedImagesCount")
117-
root_folder_completed_images_count: Optional[int] = Field(
118-
None, alias="rootFolderCompletedImagesCount"
119-
)
120-
121-
class Config:
122-
extra = Extra.ignore
123-
124-
def __copy__(self):
125-
return ProjectEntity(
126-
team_id=self.team_id,
127-
name=self.name,
128-
type=self.type,
129-
description=self.description,
130-
instructions_link=self.instructions_link
131-
if self.description
132-
else f"Copy of {self.name}.",
133-
status=self.status,
134-
folder_id=self.folder_id,
135-
users=self.users,
136-
upload_state=self.upload_state,
137-
)
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import uuid
2+
from typing import Any
3+
from typing import Iterable
4+
from typing import List
5+
from typing import Optional
6+
from typing import Union
7+
8+
from pydantic import Extra
9+
from pydantic import Field
10+
from pydantic import StrictBool
11+
from pydantic import StrictFloat
12+
from pydantic import StrictInt
13+
from pydantic import StrictStr
14+
15+
from lib.core.enums import ProjectType
16+
from lib.core.enums import ProjectStatus
17+
from lib.core.entities.base import BaseModel
18+
from lib.core.entities.base import TimedBaseModel
19+
from lib.core.entities.classes import AnnotationClassEntity
20+
21+
22+
class AttachmentEntity(BaseModel):
23+
name: Optional[str] = Field(default_factory=lambda: str(uuid.uuid4()))
24+
url: str
25+
26+
class Config:
27+
extra = Extra.ignore
28+
29+
30+
class WorkflowEntity(BaseModel):
31+
uuid: Optional[int]
32+
project_id: Optional[int]
33+
class_id: Optional[int]
34+
step: Optional[int]
35+
tool: Optional[int]
36+
attribute: Iterable = tuple(),
37+
38+
def __copy__(self):
39+
return WorkflowEntity(step=self.step, tool=self.tool, attribute=self.attribute)
40+
41+
42+
class SettingEntity(BaseModel):
43+
id: Optional[int]
44+
project_id: Optional[int]
45+
attribute: str
46+
value: Union[StrictStr, StrictInt, StrictFloat, StrictBool]
47+
48+
class Config:
49+
extra = Extra.ignore
50+
51+
def __copy__(self):
52+
return SettingEntity(attribute=self.attribute, value=self.value)
53+
54+
55+
class ProjectEntity(TimedBaseModel):
56+
id: Optional[int]
57+
team_id: Optional[int]
58+
name: Optional[str]
59+
type: Optional[ProjectType]
60+
description: Optional[str]
61+
instructions_link: Optional[str]
62+
creator_id: Optional[str]
63+
entropy_status: Optional[int]
64+
sharing_status: Optional[int]
65+
status: Optional[ProjectStatus]
66+
folder_id: Optional[int]
67+
sync_status: Optional[int]
68+
upload_state: Optional[int]
69+
users: Optional[List[Any]] = []
70+
unverified_users: Optional[List[Any]] = []
71+
contributors: Optional[List[Any]] = []
72+
settings: Optional[List[SettingEntity]] = []
73+
classes: Optional[List[AnnotationClassEntity]] = []
74+
workflows: Optional[List[WorkflowEntity]] = []
75+
completedImagesCount: Optional[int]
76+
rootFolderCompletedImagesCount: Optional[int]
77+
78+
class Config:
79+
extra = Extra.ignore
80+
use_enum_names = True
81+
82+
def __copy__(self):
83+
return ProjectEntity(
84+
team_id=self.team_id,
85+
name=self.name,
86+
type=self.type,
87+
description=self.description,
88+
instructions_link=self.instructions_link
89+
if self.description
90+
else f"Copy of {self.name}.",
91+
status=self.status,
92+
folder_id=self.folder_id,
93+
users=self.users,
94+
upload_state=self.upload_state,
95+
)

src/superannotate/lib/core/repositories.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ class BaseManageableRepository(BaseReadOnlyRepository):
3333
def insert(self, entity: BaseEntity) -> BaseEntity:
3434
raise NotImplementedError
3535

36-
@abstractmethod
3736
def update(self, entity: BaseEntity) -> BaseEntity:
3837
raise NotImplementedError
3938

src/superannotate/lib/core/usecases/projects.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,6 @@ def execute(self):
135135
project = self._projects.get_one(
136136
uuid=self._project.id, team_id=self._project.team_id
137137
)
138-
data["project"] = project
139138
if self._include_complete_image_count:
140139
completed_images_data = self._service.bulk_get_folders(
141140
self._project.team_id, [project.id]
@@ -147,24 +146,24 @@ def execute(self):
147146
if i["is_root"]:
148147
root_completed_count = i["completedCount"]
149148

150-
project.root_folder_completed_images_count = root_completed_count
151-
project.completed_images_count = total_completed_count
149+
project.rootFolderCompletedImagesCount = root_completed_count
150+
project.completedImagesCount = total_completed_count
152151

153152
if self._include_annotation_classes:
154-
data["classes"] = self.annotation_classes_use_case.execute().data
153+
project.classes = self.annotation_classes_use_case.execute().data
155154

156155
if self._include_settings:
157-
data["project"].settings = self.settings_use_case.execute().data
156+
project.settings = self.settings_use_case.execute().data
158157

159158
if self._include_workflow:
160-
data["workflows"] = self.work_flow_use_case.execute().data
159+
project.workflows = self.work_flow_use_case.execute().data
161160

162161
if self._include_contributors:
163-
data["contributors"] = project.users
162+
project.contributors = project.users
164163
else:
165164
project.users = []
166165

167-
self._response.data = data
166+
self._response.data = project
168167
return self._response
169168

170169

0 commit comments

Comments
 (0)