Skip to content

Commit 8bd6193

Browse files
Vaghinak BasentsyanVaghinak Basentsyan
authored andcommitted
Merge branch 'friday' into df_aggregation
# Conflicts: # src/superannotate/lib/app/mixp/utils/parsers.py # src/superannotate/lib/core/entities/utils.py
2 parents cb39e52 + 67209df commit 8bd6193

File tree

13 files changed

+376
-86
lines changed

13 files changed

+376
-86
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3636,6 +3636,7 @@ def attach_document_urls_to_project(
36363636
raise AppException(use_case.response.errors)
36373637

36383638

3639+
@Trackable
36393640
@validate_arguments
36403641
def validate_annotations(
36413642
project_type: ProjectTypes, annotations_json: Union[NotEmptyStr, Path]
@@ -3652,7 +3653,9 @@ def validate_annotations(
36523653
"""
36533654
with open(annotations_json) as file:
36543655
annotation_data = json.loads(file.read())
3655-
response = controller.validate_annotations(project_type, annotation_data, allow_extra=False)
3656+
response = controller.validate_annotations(
3657+
project_type, annotation_data, allow_extra=False
3658+
)
36563659
if response.errors:
36573660
raise AppException(response.errors)
36583661
is_valid, _ = response.data

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,3 +1481,13 @@ def attach_document_urls_to_project(*args, **kwargs):
14811481

14821482
def delete_annotations(*args, **kwargs):
14831483
return {"event_name": "delete_annotations", "properties": {}}
1484+
1485+
1486+
def validate_annotations(*args, **kwargs):
1487+
project_type = kwargs.get("project_type", None)
1488+
if not project_type:
1489+
project_type = args[0]
1490+
return {
1491+
"event_name": "validate_annotations",
1492+
"properties": {"Project Type": project_type},
1493+
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from lib.core.entities.utils import BaseImageInstance
55
from lib.core.entities.utils import BaseModel
6+
from lib.core.entities.utils import Comment
67
from lib.core.entities.utils import Metadata
78
from lib.core.entities.utils import Tag
89
from pydantic import Field
@@ -32,3 +33,4 @@ class PixelAnnotation(BaseModel):
3233
metadata: PixelMetaData
3334
instances: List[PixelAnnotationInstance]
3435
tags: Optional[List[Tag]] = Field(list())
36+
comments: Optional[List[Comment]] = Field(list())

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

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from pydantic import EmailStr
1010
from pydantic import Extra
1111
from pydantic import Field
12+
from pydantic import StrRegexError
1213
from pydantic import validator
1314
from pydantic.errors import EnumMemberError
1415

@@ -26,9 +27,12 @@ def enum_error_handling(self) -> str:
2627

2728
DATE_REGEX = r"\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(?:\.\d{3})Z"
2829

30+
DATE_TIME_FORMAT_ERROR_MESSAGE = (
31+
"does not match expected format YYYY-MM-DDTHH:MM:SS.fffZ"
32+
)
2933

30-
class BaseModel(PyDanticBaseModel):
3134

35+
class BaseModel(PyDanticBaseModel):
3236
class Config:
3337
extra = Extra.allow
3438
use_enum_values = True
@@ -86,7 +90,7 @@ class Attribute(BaseModel):
8690

8791

8892
class Tag(BaseModel):
89-
__root__: str
93+
__root__: NotEmptyStr
9094

9195

9296
class AttributeGroup(BaseModel):
@@ -106,6 +110,15 @@ class TimedBaseModel(BaseModel):
106110
created_at: constr(regex=DATE_REGEX) = Field(None, alias="createdAt")
107111
updated_at: constr(regex=DATE_REGEX) = Field(None, alias="updatedAt")
108112

113+
@validator("created_at", "updated_at" , pre=True)
114+
def validate_created_at(cls, value):
115+
try:
116+
if value is not None:
117+
constr(regex=DATE_REGEX).validate(value)
118+
except (TypeError, StrRegexError):
119+
raise TypeError(DATE_TIME_FORMAT_ERROR_MESSAGE)
120+
return value
121+
109122

110123
class UserAction(BaseModel):
111124
email: EmailStr
@@ -126,15 +139,16 @@ def clean_creation_type(cls, _):
126139

127140
class LastUserAction(BaseModel):
128141
email: EmailStr
129-
timestamp: float
142+
timestamp: int
130143

131144

132145
class BaseInstance(TrackableModel, TimedBaseModel):
133-
class_id: Optional[str] = Field(None, alias="classId")
134-
class_name: Optional[str] = Field(None, alias="className")
146+
class_id: Optional[int] = Field(None, alias="classId")
147+
class_name: Optional[NotEmptyStr] = Field(None, alias="className")
135148

136149

137150
class MetadataBase(BaseModel):
151+
url: Optional[str]
138152
name: NotEmptyStr
139153
last_action: Optional[LastUserAction] = Field(None, alias="lastAction")
140154
width: Optional[int]
@@ -146,7 +160,7 @@ class MetadataBase(BaseModel):
146160

147161

148162
class PointLabels(BaseModel):
149-
__root__: Dict[constr(regex=r"^[0-9]*$"), str] # noqa: F722 E261
163+
__root__: Dict[constr(regex=r"^[0-9]*$"), NotEmptyStr] # noqa: F722 E261
150164

151165

152166
class Correspondence(BaseModel):
@@ -163,7 +177,7 @@ class Comment(TimedBaseModel, TrackableModel):
163177

164178
class BaseImageInstance(BaseInstance):
165179
class_id: Optional[int] = Field(None, alias="classId")
166-
class_name: str = Field(alias="className")
180+
class_name: NotEmptyStr = Field(alias="className")
167181
visible: Optional[bool]
168182
locked: Optional[bool]
169183
probability: Optional[int] = Field(100)

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from lib.core.entities.utils import BboxPoints
88
from lib.core.entities.utils import Comment
99
from lib.core.entities.utils import Metadata
10+
from lib.core.entities.utils import NotEmptyStr
1011
from lib.core.entities.utils import Tag
1112
from lib.core.entities.utils import VectorAnnotationTypeEnum
1213
from pydantic import conlist
@@ -73,7 +74,7 @@ class Template(BaseVectorInstance):
7374
points: conlist(TemplatePoint, min_items=1)
7475
connections: List[TemplateConnection]
7576
template_id: Optional[int] = Field(None, alias="templateId")
76-
template_name: str = Field(alias="templateName")
77+
template_name: NotEmptyStr = Field(alias="templateName")
7778

7879

7980
class CuboidPoint(BaseModel):
@@ -113,7 +114,7 @@ def return_action(cls, values):
113114
try:
114115
instance_type = values["type"]
115116
except KeyError:
116-
raise ValueError("meta.type required")
117+
raise ValueError("metadata.type required")
117118
try:
118119
return ANNOTATION_TYPES[instance_type](**values)
119120
except KeyError:

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

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from enum import Enum
2-
from typing import Dict
32
from typing import List
43
from typing import Optional
54
from typing import Union
@@ -9,6 +8,7 @@
98
from lib.core.entities.utils import BaseModel
109
from lib.core.entities.utils import BboxPoints
1110
from lib.core.entities.utils import MetadataBase
11+
from lib.core.entities.utils import NotEmptyStr
1212
from lib.core.entities.utils import PointLabels
1313
from lib.core.entities.utils import Tag
1414
from pydantic import conlist
@@ -21,7 +21,6 @@ class VideoType(str, Enum):
2121

2222

2323
class MetaData(MetadataBase):
24-
url: Optional[str]
2524
duration: Optional[int]
2625
error: Optional[bool]
2726

@@ -41,7 +40,7 @@ class EventTimeStamp(BaseTimeStamp):
4140

4241
class InstanceMetadata(BaseInstance):
4342
type: VideoType
44-
class_name: Optional[str] = Field(alias="className")
43+
class_name: Optional[NotEmptyStr] = Field(alias="className")
4544
point_labels: Optional[PointLabels] = Field(None, alias="pointLabels")
4645
start: int
4746
end: int
@@ -58,14 +57,6 @@ class EventInstanceMetadata(InstanceMetadata):
5857
type: VideoType = Field(VideoType.EVENT.value, const=True)
5958

6059

61-
class BaseVideoInstance(BaseModel):
62-
metadata: InstanceMetadata
63-
id: Optional[str]
64-
type: VideoType
65-
locked: Optional[bool]
66-
timeline: Dict[float, BaseTimeStamp]
67-
68-
6960
class BaseParameter(BaseModel):
7061
start: int
7162
end: int

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3154,11 +3154,11 @@ def execute(self):
31543154

31553155
class ValidateAnnotationUseCase(BaseUseCase):
31563156
def __init__(
3157-
self,
3158-
project_type: str,
3159-
annotation: dict,
3160-
validators: BaseAnnotationValidator,
3161-
allow_extra: bool = True
3157+
self,
3158+
project_type: str,
3159+
annotation: dict,
3160+
validators: BaseAnnotationValidator,
3161+
allow_extra: bool = True,
31623162
):
31633163
super().__init__()
31643164
self._project_type = project_type

src/superannotate/lib/infrastructure/controller.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,10 +1642,13 @@ def delete_annotations(
16421642
)
16431643
return use_case.execute()
16441644

1645-
def validate_annotations(self, project_type: str, annotation: dict, allow_extra: bool = False):
1645+
def validate_annotations(
1646+
self, project_type: str, annotation: dict, allow_extra: bool = False
1647+
):
16461648
use_case = usecases.ValidateAnnotationUseCase(
1647-
project_type, annotation,
1649+
project_type,
1650+
annotation,
16481651
validators=self.annotation_validators,
1649-
allow_extra=allow_extra
1652+
allow_extra=allow_extra,
16501653
)
16511654
return use_case.execute()

src/superannotate/lib/infrastructure/validators.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ def wrap_error(e: ValidationError) -> str:
2222
error_messages = defaultdict(list)
2323
for error in e.errors():
2424
errors_list = list(error["loc"])
25-
errors_list[1::2] = [f"[{i}]" for i in errors_list[1::2]]
26-
errors_list[2::2] = [f".{i}" for i in errors_list[2::2]]
25+
errors_list[1::] = [
26+
f"[{i}]" if isinstance(i, int) else f".{i}" for i in errors_list[1::]
27+
]
2728
error_messages["".join(errors_list)].append(error["msg"])
2829
texts = ["\n"]
2930
for field, text in error_messages.items():
Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,38 @@
1-
{"metadata":{"name":"text_file_example_1","status":"Completed","url":"https://sa-public-files.s3.us-west-2.amazonaws.com/Text+project/text_file_example_1.txt","projectId":160158,"annotatorEmail":null,"qaEmail":null,"lastAction":{"email":"shab.prog@gmail.com","timestamp":1634899229953}},"instances":[{"start":253,"end":593,"classId":873208,"createdAt":"2021-10-22T10:40:26.151Z","createdBy":{"email":"shab.prog@gmail.com","role":"Admin"},"updatedAt":"2021-10-22T10:40:29.953Z","updatedBy":{"email":"shab.prog@gmail.com","role":"Admin"},"attributes":[],"creationType":"Manual","className":"vid"}],"tags":["vid"],"freeText":""}
1+
{
2+
"metadata": {
3+
"name": "text_file_example_1",
4+
"status": "Completed",
5+
"url": "https://sa-public-files.s3.us-west-2.amazonaws.com/Text+project/text_file_example_1.txt",
6+
"projectId": 160158,
7+
"annotatorEmail": null,
8+
"qaEmail": null,
9+
"lastAction": {
10+
"email": "shab.prog@gmail.com",
11+
"timestamp": 1634899229953
12+
}
13+
},
14+
"instances": [
15+
{
16+
"start": 253,
17+
"end": 593,
18+
"classId": 873208,
19+
"createdAt": "2021-10-22T10:40:26.151Z",
20+
"createdBy": {
21+
"email": "shab.prog@gmail.com",
22+
"role": "Admin"
23+
},
24+
"updatedAt": "2021-10-22T10:40:29.953Z",
25+
"updatedBy": {
26+
"email": "shab.prog@gmail.com",
27+
"role": "Admin"
28+
},
29+
"attributes": [],
30+
"creationType": "Manual",
31+
"className": "vid"
32+
}
33+
],
34+
"tags": [
35+
"vid"
36+
],
37+
"freeText": ""
38+
}

0 commit comments

Comments
 (0)