From 1dd61d41c0aae33b341b79be0b0061e94f42da27 Mon Sep 17 00:00:00 2001 From: Vaghinak Basentsyan Date: Mon, 24 Jan 2022 15:13:08 +0400 Subject: [PATCH 1/6] Add InstanceTag model. --- pytest.ini | 2 +- src/superannotate_schemas/schemas/base.py | 20 +++++++------------ src/superannotate_schemas/schemas/enums.py | 6 ++++++ .../schemas/external/vector.py | 4 +++- .../schemas/internal/vector.py | 1 + tests/test_cli.py | 3 ++- 6 files changed, 20 insertions(+), 16 deletions(-) diff --git a/pytest.ini b/pytest.ini index d9ab3b4..de4eaf7 100644 --- a/pytest.ini +++ b/pytest.ini @@ -2,4 +2,4 @@ minversion = 3.0 log_cli=true python_files = test_*.py -;addopts = -n auto --dist=loadscope \ No newline at end of file +addopts = -n auto --dist=loadscope diff --git a/src/superannotate_schemas/schemas/base.py b/src/superannotate_schemas/schemas/base.py index 8794bfe..360911c 100644 --- a/src/superannotate_schemas/schemas/base.py +++ b/src/superannotate_schemas/schemas/base.py @@ -26,6 +26,7 @@ from superannotate_schemas.schemas.enums import BaseImageRoleEnum from superannotate_schemas.schemas.enums import VectorAnnotationTypeEnum from superannotate_schemas.schemas.enums import AnnotationStatusEnum +from superannotate_schemas.schemas.enums import TagTypeEnum from superannotate_schemas.schemas.constances import DATE_REGEX from superannotate_schemas.schemas.constances import DATE_TIME_FORMAT_ERROR_MESSAGE from superannotate_schemas.schemas.constances import POINT_LABEL_VALUE_FORMAT_ERROR_MESSAGE @@ -72,12 +73,6 @@ class Tag(BaseModel): __root__: NotEmptyStr -class AttributeGroup(BaseModel): - name: NotEmptyStr - is_multiselect: Optional[bool] = Field(False) - attributes: List[BaseAttribute] - - class BboxPoints(BaseModel): x1: StrictNumber x2: StrictNumber @@ -126,6 +121,12 @@ class BaseInstance(TrackableModel, TimedBaseModel): class_name: Optional[NotEmptyStr] = Field(None, alias="className") +class InstanceTag(BaseInstance): + type: TagTypeEnum + probability: Optional[StrictInt] = Field(100) + attributes: Optional[List[BaseAttribute]] = Field(list()) + + class BaseMetadata(BaseModel): name: NotEmptyStr url: Optional[StrictStr] @@ -220,13 +221,6 @@ class BaseVectorInstance(BaseImageAnnotationInstance): tracking_id: Optional[str] = Field(alias="trackingId") group_id: Optional[int] = Field(alias="groupId") -# -# class Metadata(BaseMetadata): -# name: NotEmptyStr -# status: Optional[AnnotationStatusEnum] -# pinned: Optional[StrictBool] -# is_predicted: Optional[StrictBool] = Field(None, alias="isPredicted") - class PixelColor(BaseModel): __root__: ColorType diff --git a/src/superannotate_schemas/schemas/enums.py b/src/superannotate_schemas/schemas/enums.py index 0b8557b..e8ccdbb 100644 --- a/src/superannotate_schemas/schemas/enums.py +++ b/src/superannotate_schemas/schemas/enums.py @@ -10,6 +10,7 @@ class VectorAnnotationTypeEnum(str, Enum): POLYGON = "polygon" POINT = "point" RBBOX = "rbbox" + TAG = "tag" class CreationTypeEnum(str, Enum): @@ -38,3 +39,8 @@ class BaseImageRoleEnum(str, Enum): ADMIN = "Admin" ANNOTATOR = "Annotator" QA = "QA" + + +class TagTypeEnum(str, Enum): + TAG = "tag" + OBJECT = "object" diff --git a/src/superannotate_schemas/schemas/external/vector.py b/src/superannotate_schemas/schemas/external/vector.py index 637faca..220b7f3 100644 --- a/src/superannotate_schemas/schemas/external/vector.py +++ b/src/superannotate_schemas/schemas/external/vector.py @@ -21,6 +21,7 @@ from superannotate_schemas.schemas.base import NotEmptyStr from superannotate_schemas.schemas.base import StrictNumber from superannotate_schemas.schemas.base import Tag +from superannotate_schemas.schemas.base import InstanceTag from superannotate_schemas.schemas.enums import VectorAnnotationTypeEnum @@ -115,12 +116,13 @@ class Cuboid(VectorInstance): VectorAnnotationTypeEnum.POLYLINE: PolyLine, VectorAnnotationTypeEnum.ELLIPSE: Ellipse, VectorAnnotationTypeEnum.RBBOX: RotatedBox, + VectorAnnotationTypeEnum.TAG: InstanceTag, } class AnnotationInstance(BaseModel): __root__: Union[ - Template, Cuboid, Point, PolyLine, Polygon, Bbox, Ellipse, RotatedBox + Template, Cuboid, Point, PolyLine, Polygon, Bbox, Ellipse, RotatedBox, InstanceTag ] @classmethod diff --git a/src/superannotate_schemas/schemas/internal/vector.py b/src/superannotate_schemas/schemas/internal/vector.py index 4ec86bb..392ba23 100644 --- a/src/superannotate_schemas/schemas/internal/vector.py +++ b/src/superannotate_schemas/schemas/internal/vector.py @@ -112,6 +112,7 @@ class Cuboid(VectorInstance): VectorAnnotationTypeEnum.RBBOX: RotatedBox, } + class AnnotationInstance(BaseModel): __root__: Union[ Template, Cuboid, Point, PolyLine, Polygon, Bbox, Ellipse, RotatedBox diff --git a/tests/test_cli.py b/tests/test_cli.py index c968554..5b995e8 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -82,4 +82,5 @@ def test_(self): # pass # print(time.time() - s) import datetime - print((datetime.datetime.now(datetime.timezone.utc)).strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + 'Z') \ No newline at end of file + print((datetime.datetime.now(datetime.timezone.utc)).strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + 'Z') + From bb4506f799115976f924873092ba8860e8029b97 Mon Sep 17 00:00:00 2001 From: Shabin Dilanchian Date: Thu, 20 Jan 2022 10:51:40 +0400 Subject: [PATCH 2/6] Schema update --- src/superannotate_schemas/schemas/base.py | 2 +- tests/test_validators.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/superannotate_schemas/schemas/base.py b/src/superannotate_schemas/schemas/base.py index 360911c..1dd6878 100644 --- a/src/superannotate_schemas/schemas/base.py +++ b/src/superannotate_schemas/schemas/base.py @@ -140,7 +140,7 @@ class BaseMetadata(BaseModel): class BaseImageMetadata(BaseMetadata): width: Optional[StrictInt] height: Optional[StrictInt] - pinned: Optional[bool] + pinned: Optional[StrictBool] class Correspondence(BaseModel): diff --git a/tests/test_validators.py b/tests/test_validators.py index 939a233..1962ba7 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -2147,11 +2147,11 @@ def test_validate_vector_empty_annotation_bad_role(self): }, "width":480, "height":270, + "pinned": [ "fasdf" ], "name":"1 copy_001.jpg", "projectId":181302, "isPredicted":false, "status":"Completed", - "pinned":false, "annotatorEmail":null, "qaEmail":null }, @@ -2209,4 +2209,5 @@ def test_validate_vector_empty_annotation_bad_role(self): data = json.loads(f.read()) validator = AnnotationValidators.get_validator("vector")(data) self.assertFalse(validator.is_valid()) - self.assertEqual(len(validator.generate_report()), 113) \ No newline at end of file + print(validator.generate_report()) + self.assertEqual(len(validator.generate_report()), 191) \ No newline at end of file From 2f23534eaf5952df891e56632dab8421c8c49d3f Mon Sep 17 00:00:00 2001 From: Shabin Dilanchian Date: Thu, 20 Jan 2022 12:40:33 +0400 Subject: [PATCH 3/6] Update base schema --- src/superannotate_schemas/schemas/base.py | 6 +++--- src/superannotate_schemas/schemas/external/vector.py | 6 +++++- src/superannotate_schemas/schemas/internal/vector.py | 9 ++++++++- tests/test_validators.py | 10 +++++++--- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/superannotate_schemas/schemas/base.py b/src/superannotate_schemas/schemas/base.py index 1dd6878..baed528 100644 --- a/src/superannotate_schemas/schemas/base.py +++ b/src/superannotate_schemas/schemas/base.py @@ -65,8 +65,8 @@ class AxisPoint(BaseModel): class BaseAttribute(BaseModel): id: Optional[StrictInt] group_id: Optional[StrictInt] = Field(alias="groupId") - name: Optional[NotEmptyStr] - group_name: Optional[NotEmptyStr] = Field(alias="groupName") + name: NotEmptyStr + group_name: NotEmptyStr = Field(alias="groupName") class Tag(BaseModel): @@ -121,7 +121,7 @@ class BaseInstance(TrackableModel, TimedBaseModel): class_name: Optional[NotEmptyStr] = Field(None, alias="className") -class InstanceTag(BaseInstance): +class BaseInstanceTag(BaseInstance): type: TagTypeEnum probability: Optional[StrictInt] = Field(100) attributes: Optional[List[BaseAttribute]] = Field(list()) diff --git a/src/superannotate_schemas/schemas/external/vector.py b/src/superannotate_schemas/schemas/external/vector.py index 220b7f3..d04be70 100644 --- a/src/superannotate_schemas/schemas/external/vector.py +++ b/src/superannotate_schemas/schemas/external/vector.py @@ -21,10 +21,14 @@ from superannotate_schemas.schemas.base import NotEmptyStr from superannotate_schemas.schemas.base import StrictNumber from superannotate_schemas.schemas.base import Tag -from superannotate_schemas.schemas.base import InstanceTag +from superannotate_schemas.schemas.base import BaseInstanceTag from superannotate_schemas.schemas.enums import VectorAnnotationTypeEnum +class InstanceTag(BaseInstanceTag): + class_name: NotEmptyStr + + class Attribute(BaseAttribute): name: NotEmptyStr group_name: NotEmptyStr = Field(alias="groupName") diff --git a/src/superannotate_schemas/schemas/internal/vector.py b/src/superannotate_schemas/schemas/internal/vector.py index 392ba23..16cc89b 100644 --- a/src/superannotate_schemas/schemas/internal/vector.py +++ b/src/superannotate_schemas/schemas/internal/vector.py @@ -10,6 +10,7 @@ from superannotate_schemas.schemas.base import Tag from superannotate_schemas.schemas.base import AxisPoint from superannotate_schemas.schemas.base import VectorAnnotationTypeEnum +from superannotate_schemas.schemas.base import BaseInstanceTag from superannotate_schemas.schemas.base import StrictNumber from superannotate_schemas.schemas.base import INVALID_DICT_MESSAGE from superannotate_schemas.schemas.base import BaseModel @@ -24,6 +25,11 @@ from pydantic.error_wrappers import ErrorWrapper + +class InstanceTag(BaseInstanceTag): + class_id: StrictInt + + class Attribute(BaseAttribute): id: StrictInt group_id: StrictInt = Field(alias="groupId") @@ -110,12 +116,13 @@ class Cuboid(VectorInstance): VectorAnnotationTypeEnum.POLYLINE: PolyLine, VectorAnnotationTypeEnum.ELLIPSE: Ellipse, VectorAnnotationTypeEnum.RBBOX: RotatedBox, + VectorAnnotationTypeEnum.TAG: InstanceTag, } class AnnotationInstance(BaseModel): __root__: Union[ - Template, Cuboid, Point, PolyLine, Polygon, Bbox, Ellipse, RotatedBox + Template, Cuboid, Point, PolyLine, Polygon, Bbox, Ellipse, RotatedBox, InstanceTag ] @classmethod diff --git a/tests/test_validators.py b/tests/test_validators.py index 1962ba7..facd2cd 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -310,7 +310,12 @@ def test_validate_document_annotation_wrong_class_id(self, mock_print): "email": "some.email@gmail.com", "role": "Admin" }, - "attributes": [], + "attributes": [ + { + "id": 1175876, + "groupId": 338357 + } + ], "creationType": "Manual", "className": "vid" }], @@ -324,8 +329,7 @@ def test_validate_document_annotation_wrong_class_id(self, mock_print): data = json.loads(f.read()) validator = AnnotationValidators.get_validator("document")(data) self.assertFalse(validator.is_valid()) - self.assertEqual(validator.generate_report(), - "instances[0].classId integer type expected") + self.assertEqual(len(validator.generate_report()), 198) def test_validate_document_annotation_with_null_created_at(self): with tempfile.TemporaryDirectory() as tmpdir_name: From 15d855754f02372aee3774442ed414f91d43d076 Mon Sep 17 00:00:00 2001 From: Vaghinak Basentsyan Date: Mon, 24 Jan 2022 16:36:02 +0400 Subject: [PATCH 4/6] Created annotation classes schemas --- src/superannotate_schemas/schemas/base.py | 2 +- src/superannotate_schemas/schemas/classes.py | 49 +++++++++++++++++++ src/superannotate_schemas/schemas/enums.py | 5 ++ .../schemas/external/pixel.py | 4 +- .../schemas/internal/pixel.py | 4 +- src/superannotate_schemas/validators.py | 1 + 6 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 src/superannotate_schemas/schemas/classes.py diff --git a/src/superannotate_schemas/schemas/base.py b/src/superannotate_schemas/schemas/base.py index d8522a4..84ef8ee 100644 --- a/src/superannotate_schemas/schemas/base.py +++ b/src/superannotate_schemas/schemas/base.py @@ -228,7 +228,7 @@ class BaseVectorInstance(BaseImageAnnotationInstance): # is_predicted: Optional[StrictBool] = Field(None, alias="isPredicted") -class PixelColor(BaseModel): +class HexColor(BaseModel): __root__: ColorType @validator("__root__") diff --git a/src/superannotate_schemas/schemas/classes.py b/src/superannotate_schemas/schemas/classes.py new file mode 100644 index 0000000..638f876 --- /dev/null +++ b/src/superannotate_schemas/schemas/classes.py @@ -0,0 +1,49 @@ +from typing import Optional +from typing import List + +from superannotate_schemas.schemas.base import BaseModel +from superannotate_schemas.schemas.base import TrackableModel +from superannotate_schemas.schemas.base import TimedBaseModel +from superannotate_schemas.schemas.base import StrictInt +from superannotate_schemas.schemas.base import StrictStr +from superannotate_schemas.schemas.base import HexColor +from superannotate_schemas.schemas.enums import ClassTypeEnum + + +class Attribute(TimedBaseModel): + id: Optional[StrictInt] + group_id: Optional[StrictInt] + project_id: Optional[StrictInt] + name: StrictStr + count: Optional[StrictInt] + + def __hash__(self): + return hash(f"{self.id}{self.group_id}{self.name}") + + +class AttributeGroup(TimedBaseModel): + id: Optional[StrictInt] + class_id: Optional[StrictInt] + name: StrictStr + is_multiselect: Optional[bool] + attributes: List[Attribute] + + def __hash__(self): + return hash(f"{self.id}{self.class_id}{self.name}") + + +class AnnotationClass(TimedBaseModel): + id: Optional[StrictInt] + project_id: Optional[StrictInt] + type: ClassTypeEnum = ClassTypeEnum.OBJECT + name: StrictStr + color: HexColor + count: Optional[StrictInt] + attribute_groups: List[AttributeGroup] + + def __hash__(self): + return hash(f"{self.id}{self.type}{self.name}") + + +class AnnotationClasses(BaseModel): + __root__: List[AnnotationClass] diff --git a/src/superannotate_schemas/schemas/enums.py b/src/superannotate_schemas/schemas/enums.py index 0b8557b..d7be2f0 100644 --- a/src/superannotate_schemas/schemas/enums.py +++ b/src/superannotate_schemas/schemas/enums.py @@ -38,3 +38,8 @@ class BaseImageRoleEnum(str, Enum): ADMIN = "Admin" ANNOTATOR = "Annotator" QA = "QA" + + +class ClassTypeEnum(str, Enum): + OBJECT = "object" + TAG = "tag" diff --git a/src/superannotate_schemas/schemas/external/pixel.py b/src/superannotate_schemas/schemas/external/pixel.py index b21b3d5..23de3a1 100644 --- a/src/superannotate_schemas/schemas/external/pixel.py +++ b/src/superannotate_schemas/schemas/external/pixel.py @@ -6,7 +6,7 @@ from superannotate_schemas.schemas.base import BaseImageMetadata from superannotate_schemas.schemas.base import NotEmptyStr from superannotate_schemas.schemas.base import StrictStr -from superannotate_schemas.schemas.base import PixelColor +from superannotate_schemas.schemas.base import HexColor from superannotate_schemas.schemas.base import Tag from superannotate_schemas.schemas.base import Comment @@ -25,7 +25,7 @@ class MetaData(BaseImageMetadata): class AnnotationPart(BaseModel): - color: PixelColor + color: HexColor class AnnotationInstance(BaseImageAnnotationInstance): diff --git a/src/superannotate_schemas/schemas/internal/pixel.py b/src/superannotate_schemas/schemas/internal/pixel.py index 3d73ec1..0b4d981 100644 --- a/src/superannotate_schemas/schemas/internal/pixel.py +++ b/src/superannotate_schemas/schemas/internal/pixel.py @@ -2,7 +2,7 @@ from typing import Optional from superannotate_schemas.schemas.base import BaseImageMetadata as Metadata -from superannotate_schemas.schemas.base import PixelColor +from superannotate_schemas.schemas.base import HexColor from superannotate_schemas.schemas.base import BaseAttribute from superannotate_schemas.schemas.base import BaseImageAnnotationInstance from superannotate_schemas.schemas.base import Tag @@ -19,7 +19,7 @@ class Attribute(BaseAttribute): class AnnotationPart(BaseModel): - color: PixelColor + color: HexColor class AnnotationInstance(BaseImageAnnotationInstance): diff --git a/src/superannotate_schemas/validators.py b/src/superannotate_schemas/validators.py index a093e03..3072b3d 100644 --- a/src/superannotate_schemas/validators.py +++ b/src/superannotate_schemas/validators.py @@ -95,6 +95,7 @@ class AnnotationValidators: ValidatorFactory.get_validator(ExternalDocumentAnnotation), ValidatorFactory.get_validator(InternalDocumentAnnotation) ) + } @classmethod From 0e3b63c149aa7b55e39c08032a25cb9fadf452ed Mon Sep 17 00:00:00 2001 From: Shabin Dilanchian Date: Thu, 20 Jan 2022 12:40:33 +0400 Subject: [PATCH 5/6] Update base schema --- src/superannotate_schemas/bin/interface.py | 3 ++- src/superannotate_schemas/schemas/base.py | 4 ++-- tests/test_validators.py | 10 +++++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/superannotate_schemas/bin/interface.py b/src/superannotate_schemas/bin/interface.py index ae10627..7cd5f18 100644 --- a/src/superannotate_schemas/bin/interface.py +++ b/src/superannotate_schemas/bin/interface.py @@ -1,4 +1,5 @@ import os +from os.path import expanduser import json import errno from pathlib import Path @@ -61,7 +62,7 @@ def validate(*paths, project_type, internal=False, verbose=False, report_path=No if verbose: print(f"{'-'* 4}{path}\n{report}") if report_path: - with open(f"{report_path}/{uniquify(Path(path).name)}") as validation_report: + with open(uniquify(f"{report_path}/{(Path(path).name)}"), "w") as validation_report: validation_report.write(report) else: validation_result.append({path: False}) diff --git a/src/superannotate_schemas/schemas/base.py b/src/superannotate_schemas/schemas/base.py index 0290f48..d8522a4 100644 --- a/src/superannotate_schemas/schemas/base.py +++ b/src/superannotate_schemas/schemas/base.py @@ -64,8 +64,8 @@ class AxisPoint(BaseModel): class BaseAttribute(BaseModel): id: Optional[StrictInt] group_id: Optional[StrictInt] = Field(alias="groupId") - name: Optional[NotEmptyStr] - group_name: Optional[NotEmptyStr] = Field(alias="groupName") + name: NotEmptyStr + group_name: NotEmptyStr = Field(alias="groupName") class Tag(BaseModel): diff --git a/tests/test_validators.py b/tests/test_validators.py index 1962ba7..facd2cd 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -310,7 +310,12 @@ def test_validate_document_annotation_wrong_class_id(self, mock_print): "email": "some.email@gmail.com", "role": "Admin" }, - "attributes": [], + "attributes": [ + { + "id": 1175876, + "groupId": 338357 + } + ], "creationType": "Manual", "className": "vid" }], @@ -324,8 +329,7 @@ def test_validate_document_annotation_wrong_class_id(self, mock_print): data = json.loads(f.read()) validator = AnnotationValidators.get_validator("document")(data) self.assertFalse(validator.is_valid()) - self.assertEqual(validator.generate_report(), - "instances[0].classId integer type expected") + self.assertEqual(len(validator.generate_report()), 198) def test_validate_document_annotation_with_null_created_at(self): with tempfile.TemporaryDirectory() as tmpdir_name: From fbbf0af38673dbcb1c86beb6b5daea8ded5c1014 Mon Sep 17 00:00:00 2001 From: Vaghinak Basentsyan Date: Thu, 27 Jan 2022 13:53:37 +0400 Subject: [PATCH 6/6] tod --- src/superannotate_schemas/schemas/base.py | 4 ++-- src/superannotate_schemas/schemas/classes.py | 1 - src/superannotate_schemas/validators.py | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/superannotate_schemas/schemas/base.py b/src/superannotate_schemas/schemas/base.py index 85d0c57..c9056bb 100644 --- a/src/superannotate_schemas/schemas/base.py +++ b/src/superannotate_schemas/schemas/base.py @@ -26,7 +26,7 @@ from superannotate_schemas.schemas.enums import BaseImageRoleEnum from superannotate_schemas.schemas.enums import VectorAnnotationTypeEnum from superannotate_schemas.schemas.enums import AnnotationStatusEnum -from superannotate_schemas.schemas.enums import TagTypeEnum +from superannotate_schemas.schemas.enums import ClassTypeEnum from superannotate_schemas.schemas.constances import DATE_REGEX from superannotate_schemas.schemas.constances import DATE_TIME_FORMAT_ERROR_MESSAGE from superannotate_schemas.schemas.constances import POINT_LABEL_VALUE_FORMAT_ERROR_MESSAGE @@ -122,7 +122,7 @@ class BaseInstance(TrackableModel, TimedBaseModel): class BaseInstanceTag(BaseInstance): - type: TagTypeEnum + type: ClassTypeEnum probability: Optional[StrictInt] = Field(100) attributes: Optional[List[BaseAttribute]] = Field(list()) diff --git a/src/superannotate_schemas/schemas/classes.py b/src/superannotate_schemas/schemas/classes.py index 638f876..314b870 100644 --- a/src/superannotate_schemas/schemas/classes.py +++ b/src/superannotate_schemas/schemas/classes.py @@ -2,7 +2,6 @@ from typing import List from superannotate_schemas.schemas.base import BaseModel -from superannotate_schemas.schemas.base import TrackableModel from superannotate_schemas.schemas.base import TimedBaseModel from superannotate_schemas.schemas.base import StrictInt from superannotate_schemas.schemas.base import StrictStr diff --git a/src/superannotate_schemas/validators.py b/src/superannotate_schemas/validators.py index 3072b3d..ea4ee8f 100644 --- a/src/superannotate_schemas/validators.py +++ b/src/superannotate_schemas/validators.py @@ -15,6 +15,7 @@ from superannotate_schemas.schemas.internal import VectorAnnotation as InternalVectorAnnotation from superannotate_schemas.schemas.internal import VideoAnnotation as InternalVideoAnnotation from superannotate_schemas.schemas.internal import DocumentAnnotation as InternalDocumentAnnotation +from superannotate_schemas.schemas.classes import AnnotationClass from superannotate_schemas.schemas.base import BaseModel @@ -95,7 +96,6 @@ class AnnotationValidators: ValidatorFactory.get_validator(ExternalDocumentAnnotation), ValidatorFactory.get_validator(InternalDocumentAnnotation) ) - } @classmethod