diff --git a/requirements_dev.txt b/requirements_dev.txt deleted file mode 100644 index 9415ce9fc..000000000 --- a/requirements_dev.txt +++ /dev/null @@ -1,2 +0,0 @@ -superannotate_schemas>=v1.0.45dev5 - diff --git a/requirements_prod.txt b/requirements_prod.txt deleted file mode 100644 index 61bea0eb7..000000000 --- a/requirements_prod.txt +++ /dev/null @@ -1 +0,0 @@ -superannotate_schemas==1.0.45 diff --git a/setup.py b/setup.py index b5b1d95b1..7094269e1 100644 --- a/setup.py +++ b/setup.py @@ -12,24 +12,16 @@ def get_version(): sdk_version = get_version() - -requirements_path = "requirements_{}.txt".format('dev' if 'dev' in sdk_version else 'prod') - requirements = [] with open("requirements.txt") as f: requirements.extend(f.read().splitlines()) -with open(requirements_path) as f: - requirements.extend(f.read().splitlines()) - - with open('README.md') as f: readme = f.read() readme = "\n".join(readme.split('\n')[2:]) - setup( name='superannotate', version=sdk_version, diff --git a/src/superannotate/lib/core/entities/__init__.py b/src/superannotate/lib/core/entities/__init__.py index cc1767cf4..b01465a63 100644 --- a/src/superannotate/lib/core/entities/__init__.py +++ b/src/superannotate/lib/core/entities/__init__.py @@ -18,13 +18,7 @@ from lib.core.entities.project_entities import TeamEntity from lib.core.entities.project_entities import UserEntity from lib.core.entities.project_entities import WorkflowEntity -from superannotate_schemas.schemas.internal.document import DocumentAnnotation -from superannotate_schemas.schemas.internal.pixel import PixelAnnotation -from superannotate_schemas.schemas.internal.vector import VectorAnnotation -from superannotate_schemas.schemas.internal.video import VideoAnnotation -from superannotate_schemas.schemas.internal.video import ( - VideoAnnotation as VideoExportAnnotation, -) + # from lib.core.entities.project_entities import ProjectEntity diff --git a/src/superannotate/lib/core/entities/project_entities.py b/src/superannotate/lib/core/entities/project_entities.py index 244bca0c9..bb9aec7bc 100644 --- a/src/superannotate/lib/core/entities/project_entities.py +++ b/src/superannotate/lib/core/entities/project_entities.py @@ -5,16 +5,7 @@ from typing import List from typing import Union -from lib.core.enums import ClassTypeEnum from lib.core.enums import SegmentationStatus -from superannotate_schemas.schemas.classes import AnnotationClass - - -class AnnotationClassEntity(AnnotationClass): - def deserialize(self): - data = self.dict() - data["type"] = ClassTypeEnum.get_value(data["type"]) - return data class BaseEntity(ABC): diff --git a/src/superannotate/lib/core/reporter.py b/src/superannotate/lib/core/reporter.py index 89c119e39..96d47e8b7 100644 --- a/src/superannotate/lib/core/reporter.py +++ b/src/superannotate/lib/core/reporter.py @@ -79,9 +79,6 @@ def disable_warnings(self): def disable_info(self): self._log_info = False - def enable_warnings(self): - self._log_warning = True - def enable_info(self): self._log_info = True @@ -127,14 +124,6 @@ def update_progress(self, value: int = 1): if self.progress_bar: self.progress_bar.update(value) - def generate_report(self) -> str: - report = "" - if self.info_messages: - report += "\n".join(self.info_messages) - if self.warning_messages: - report += "\n".join(self.warning_messages) - return report - def store_message(self, key: str, value: str): self.custom_messages[key].add(value) diff --git a/src/superannotate/lib/core/response.py b/src/superannotate/lib/core/response.py index 107bd28c3..49d6b035c 100644 --- a/src/superannotate/lib/core/response.py +++ b/src/superannotate/lib/core/response.py @@ -27,10 +27,6 @@ def report(self): def report(self, value: str): self._report.append(value) - @property - def report_messages(self): - return self._report - @property def status(self): return self._status diff --git a/src/superannotate/lib/core/serviceproviders.py b/src/superannotate/lib/core/serviceproviders.py index 1e8ab2e81..671cca8a7 100644 --- a/src/superannotate/lib/core/serviceproviders.py +++ b/src/superannotate/lib/core/serviceproviders.py @@ -242,11 +242,6 @@ def set_project_workflow_attributes_bulk( ): raise NotImplementedError - def get_pre_annotation_upload_data( - self, project_id: int, team_id: int, image_ids: List[int], folder_id: int - ): - raise NotImplementedError - def get_annotation_upload_data( self, project_id: int, team_id: int, image_ids: List[int], folder_id: int ) -> ServiceResponse: diff --git a/src/superannotate/lib/core/usecases/images.py b/src/superannotate/lib/core/usecases/images.py index 32f07d18f..296457dee 100644 --- a/src/superannotate/lib/core/usecases/images.py +++ b/src/superannotate/lib/core/usecases/images.py @@ -50,55 +50,6 @@ logger = get_default_logger() -class GetImagesUseCase(BaseUseCase): - def __init__( - self, - project: ProjectEntity, - folder: FolderEntity, - images: BaseReadOnlyRepository, - annotation_status: str = None, - image_name_prefix: str = None, - ): - super().__init__() - self._project = project - self._folder = folder - self._images = images - self._annotation_status = annotation_status - self._image_name_prefix = image_name_prefix - - def validate_project_type(self): - if self._project.type in constances.LIMITED_FUNCTIONS: - raise AppValidationException( - constances.LIMITED_FUNCTIONS[self._project.type] - ) - - def validate_annotation_status(self): - if ( - self._annotation_status - and self._annotation_status.lower() - not in constances.AnnotationStatus.values() - ): - raise AppValidationException("Invalid annotations status.") - - def execute(self): - if self.is_valid(): - condition = ( - Condition("team_id", self._project.team_id, EQ) - & Condition("project_id", self._project.id, EQ) - & Condition("folder_id", self._folder.uuid, EQ) - ) - if self._image_name_prefix: - condition = condition & Condition("name", self._image_name_prefix, EQ) - if self._annotation_status: - condition = condition & Condition( - "annotation_status", - constances.AnnotationStatus.get_value(self._annotation_status), - EQ, - ) - self._response.data = self._images.get_all(condition) - return self._response - - class GetImageUseCase(BaseUseCase): def __init__( self, @@ -134,41 +85,6 @@ def execute(self): return self._response -class GetAllImagesUseCase(BaseUseCase): - def __init__( - self, - project: ProjectEntity, - service_provider: SuperannotateServiceProvider, - annotation_status: str = None, - name_prefix: str = None, - ): - super().__init__() - self._project = project - self._service_provider = service_provider - self._annotation_status = annotation_status - self._name_prefix = name_prefix - - @property - def annotation_status(self): - return constances.AnnotationStatus.get_value(self._annotation_status) - - def execute(self): - condition = ( - Condition("team_id", self._project.team_id, EQ) - & Condition("project_id", self._project.id, EQ) - & Condition("folder_id", 0, EQ) - ) - if self._annotation_status: - condition &= Condition("annotation_status", self.annotation_status, EQ) - if self._name_prefix: - condition &= Condition("name", self._name_prefix, EQ) - images_list = self._service_provider.list_images( - query_string=condition.build_query() - ) - self._response.data = [ImageEntity.from_dict(**image) for image in images_list] - return self._response - - class GetBulkImages(BaseUseCase): def __init__( self, @@ -1963,35 +1879,6 @@ def execute(self): self._annotation_classes_repo.delete(uuid=self.uuid) -class GetAnnotationClassUseCase(BaseUseCase): - def __init__( - self, - annotation_classes_repo: BaseManageableRepository, - annotation_class_name: str, - ): - super().__init__() - self._annotation_classes_repo = annotation_classes_repo - self._annotation_class_name = annotation_class_name - - def execute(self): - classes = self._annotation_classes_repo.get_all( - condition=Condition("name", self._annotation_class_name, EQ) - ) - self._response.data = classes[0] - return self._response - - -class UploadFileToS3UseCase(BaseUseCase): - def __init__(self, to_s3_bucket, path, s3_key: str): - super().__init__() - self._to_s3_bucket = to_s3_bucket - self._path = path - self._s3_key = s3_key - - def execute(self): - self._to_s3_bucket.upload_file(str(self._path), self._s3_key) - - class ExtractFramesUseCase(BaseInteractiveUseCase): def __init__( self, diff --git a/src/superannotate/lib/core/validators.py b/src/superannotate/lib/core/validators.py deleted file mode 100644 index f2ef3e43c..000000000 --- a/src/superannotate/lib/core/validators.py +++ /dev/null @@ -1,56 +0,0 @@ -import copy -from abc import ABCMeta -from abc import abstractmethod -from typing import Any -from typing import Type - -from pydantic import BaseModel -from pydantic import Extra - - -class BaseValidator(metaclass=ABCMeta): - MODEL: BaseModel() - - def __init__(self, data: Any, allow_extra: bool = True): - self.data = data - self._validation_output = None - self._extra = Extra.allow if allow_extra else Extra.forbid - - @classmethod - def validate(cls, data: Any, extra=True): - return cls.MODEL(**data) - - def _validate(self): - model = copy.deepcopy(self.MODEL) - model.Config.extra = self._extra - self.data = model(**self.data).dict(by_alias=True, exclude_none=True) - - @abstractmethod - def is_valid(self) -> bool: - raise NotImplementedError - - @abstractmethod - def generate_report(self) -> str: - raise NotImplementedError - - -class BaseAnnotationValidator(metaclass=ABCMeta): - @staticmethod - @abstractmethod - def get_pixel_validator() -> Type[BaseValidator]: - raise NotImplementedError - - @staticmethod - @abstractmethod - def get_vector_validator() -> Type[BaseValidator]: - raise NotImplementedError - - @staticmethod - @abstractmethod - def get_video_validator() -> Type[BaseValidator]: - raise NotImplementedError - - @staticmethod - @abstractmethod - def get_document_validator() -> Type[BaseValidator]: - raise NotImplementedError diff --git a/src/superannotate/lib/infrastructure/controller.py b/src/superannotate/lib/infrastructure/controller.py index a9988cbd4..fdead6263 100644 --- a/src/superannotate/lib/infrastructure/controller.py +++ b/src/superannotate/lib/infrastructure/controller.py @@ -39,7 +39,6 @@ from lib.infrastructure.repositories import WorkflowRepository from lib.infrastructure.services import SuperannotateBackendService from superannotate.logger import get_default_logger -from superannotate_schemas.validators import AnnotationValidators def build_condition(**kwargs) -> Condition: @@ -193,10 +192,6 @@ def get_s3_repository(self, team_id: int, project_id: int, folder_id: int): def s3_repo(self): return S3Repository - @property - def annotation_validators(self) -> AnnotationValidators: - return AnnotationValidators() - class Controller(BaseController): DEFAULT = None @@ -444,26 +439,6 @@ def clone_project( ) return use_case.execute() - def interactive_attach_urls( - self, - project_name: str, - files: List[ImageEntity], - folder_name: str = None, - annotation_status: str = None, - upload_state_code: int = None, - ): - project = self._get_project(project_name) - folder = self._get_folder(project, folder_name) - - return usecases.InteractiveAttachFileUrlsUseCase( - project=project, - folder=folder, - attachments=files, - backend_service_provider=self._backend_client, - annotation_status=annotation_status, - upload_state_code=upload_state_code, - ) - def create_folder(self, project: str, folder_name: str): project = self._get_project(project) folder = FolderEntity( @@ -543,25 +518,6 @@ def search_team_contributors(self, **kwargs): ) return use_case.execute() - def search_images( - self, - project_name: str, - folder_path: str = None, - annotation_status: str = None, - image_name_prefix: str = None, - ): - project = self._get_project(project_name) - folder = self._get_folder(project, folder_path) - - use_case = usecases.GetImagesUseCase( - project=project, - folder=folder, - images=self.images, - annotation_status=annotation_status, - image_name_prefix=image_name_prefix, - ) - return use_case.execute() - def _get_image( self, project: ProjectEntity, @@ -678,48 +634,6 @@ def update_image( use_case = usecases.UpdateImageUseCase(image=image, images=self.images) return use_case.execute() - def bulk_copy_images( - self, - project_name: str, - from_folder_name: str, - to_folder_name: str, - image_names: List[str], - include_annotations: bool, - include_pin: bool, - ): - project = self._get_project(project_name) - from_folder = self._get_folder(project, from_folder_name) - to_folder = self._get_folder(project, to_folder_name) - use_case = usecases.ImagesBulkCopyUseCase( - project=project, - from_folder=from_folder, - to_folder=to_folder, - image_names=image_names, - backend_service_provider=self._backend_client, - include_annotations=include_annotations, - include_pin=include_pin, - ) - return use_case.execute() - - def bulk_move_images( - self, - project_name: str, - from_folder_name: str, - to_folder_name: str, - image_names: List[str], - ): - project = self._get_project(project_name) - from_folder = self._get_folder(project, from_folder_name) - to_folder = self._get_folder(project, to_folder_name) - use_case = usecases.ImagesBulkMoveUseCase( - project=project, - from_folder=from_folder, - to_folder=to_folder, - image_names=image_names, - backend_service_provider=self._backend_client, - ) - return use_case.execute() - def get_project_metadata( self, project_name: str, @@ -957,17 +871,6 @@ def delete_annotation_class(self, project_name: str, annotation_class_name: str) ) return use_case.execute() - def get_annotation_class(self, project_name: str, annotation_class_name: str): - project = self._get_project(project_name) - use_case = usecases.GetAnnotationClassUseCase( - annotation_class_name=annotation_class_name, - annotation_classes_repo=AnnotationClassRepository( - service=self._backend_client, - project=project, - ), - ) - return use_case.execute() - def download_annotation_classes(self, project_name: str, download_path: str): project = self._get_project(project_name) use_case = usecases.DownloadAnnotationClassesUseCase( @@ -1242,22 +1145,6 @@ def run_prediction( ) return use_case.execute() - def list_images( - self, - project_name: str, - annotation_status: str = None, - name_prefix: str = None, - ): - project = self._get_project(project_name) - - use_case = usecases.GetAllImagesUseCase( - project=project, - service_provider=self._backend_client, - annotation_status=annotation_status, - name_prefix=name_prefix, - ) - return use_case.execute() - def search_models( self, name: str, diff --git a/src/superannotate/lib/infrastructure/repositories.py b/src/superannotate/lib/infrastructure/repositories.py index 184dbeccd..772038c7b 100644 --- a/src/superannotate/lib/infrastructure/repositories.py +++ b/src/superannotate/lib/infrastructure/repositories.py @@ -301,18 +301,6 @@ def delete(self, uuid: int): annotation_class_id=uuid, ) - def bulk_insert(self, entities: List[AnnotationClassEntity]): - res = self._service.set_annotation_classes( - self.project.id, self.project.team_id, entities - ) - if "error" in res: - raise AppException(res["error"]) - - return [self.dict2entity(i) for i in res] - - def update(self, entity: AnnotationClassEntity): - raise NotImplementedError - @staticmethod def dict2entity(data: dict) -> AnnotationClassEntity: return AnnotationClassEntity( diff --git a/src/superannotate/lib/infrastructure/services.py b/src/superannotate/lib/infrastructure/services.py index f5da1a316..cc271fa1b 100644 --- a/src/superannotate/lib/infrastructure/services.py +++ b/src/superannotate/lib/infrastructure/services.py @@ -83,8 +83,7 @@ def __init__( def assets_provider_url(self): if self.api_url != constance.BACKEND_URL: return "https://assets-provider.devsuperannotate.com/api/v1.01/" - # return "https://e53a-178-160-196-42.ngrok.io/api/v1.01/" - return "https://assets-provider.superannotate.com/api/v1/" + return "https://assets-provider.superannotate.com/api/v1.01/" @lru_cache(maxsize=32) def _get_session(self, thread_id, ttl=None): # noqa @@ -282,7 +281,6 @@ class SuperannotateBackendService(BaseBackendService): URL_GET_EXPORTS = "exports" URL_GET_CLASS = "class/{}" URL_ANNOTATION_UPLOAD_PATH_TOKEN = "images/getAnnotationsPathsAndTokens" - URL_PRE_ANNOTATION_UPLOAD_PATH_TOKEN = "images/getPreAnnotationsPathsAndTokens" URL_GET_TEMPLATES = "templates" URL_PROJECT_WORKFLOW_ATTRIBUTE = "project/{}/workflow_attribute" URL_MODELS = "ml_models" @@ -304,7 +302,6 @@ class SuperannotateBackendService(BaseBackendService): URL_VALIDATE_SAQUL_QUERY = "/images/parse/query/advanced" URL_LIST_SUBSETS = "/project/{project_id}/subset" URL_CREATE_CUSTOM_SCHEMA = "/project/{project_id}/custom/metadata/schema" - URL_GET_CUSTOM_SCHEMA = "/project/{project_id}/custom/metadata/schema" URL_UPLOAD_CUSTOM_VALUE = "/project/{project_id}/custom/metadata/item" URL_UPLOAD_ANNOTATIONS = "items/annotations/upload" URL_ANNOTATION_SCHEMAS = "items/annotations/schema" @@ -992,25 +989,6 @@ def get_annotation_upload_data( ) return response - def get_pre_annotation_upload_data( - self, project_id: int, team_id: int, image_ids: List[int], folder_id: int - ): - get_annotation_upload_data_url = urljoin( - self.api_url, self.URL_PRE_ANNOTATION_UPLOAD_PATH_TOKEN - ) - response = self._request( - get_annotation_upload_data_url, - "post", - data={ - "project_id": project_id, - "team_id": team_id, - "ids": image_ids, - "folder_id": folder_id, - }, - content_type=UploadAnnotationAuthData, - ) - return response - def get_templates(self, team_id: int): get_templates_url = urljoin(self.api_url, self.URL_GET_TEMPLATES) response = self._request(get_templates_url, "get", params={"team_id": team_id}) diff --git a/tests/integration/annotations/test_annotations_pre_processing.py b/tests/integration/annotations/test_annotations_pre_processing.py index 5b2c29ef4..6637cd2e1 100644 --- a/tests/integration/annotations/test_annotations_pre_processing.py +++ b/tests/integration/annotations/test_annotations_pre_processing.py @@ -1,18 +1,16 @@ -import tempfile -from collections import defaultdict -from pathlib import Path +import json import os +import tempfile from os.path import join -import json +from pathlib import Path + import pytest -from unittest.mock import patch -from unittest.mock import MagicMock from src.superannotate import SAClient -sa = SAClient() -from superannotate_schemas.schemas.base import CreationTypeEnum from tests.integration.base import BaseTestCase +sa = SAClient() + class TestAnnotationUploadVector(BaseTestCase): PROJECT_NAME = "TestAnnotationUploadVectorPreProcessing" @@ -35,10 +33,9 @@ def test_annotation_last_action_and_creation_type(self): sa.download_image_annotations(self.PROJECT_NAME, self.IMAGE_NAME, tmp_dir) annotation = json.load(open(join(tmp_dir, f"{self.IMAGE_NAME}___objects.json"))) for instance in annotation["instances"]: - self.assertEqual(instance["creationType"], CreationTypeEnum.PRE_ANNOTATION.value) + self.assertEqual(instance["creationType"], "Preannotation") assert annotation["metadata"]["lastAction"]["email"] == sa.controller.team_data.creator_id self.assertEqual( type(annotation["metadata"]["lastAction"]["timestamp"]), int ) - diff --git a/tests/integration/classes/test_classes_serialization.py b/tests/integration/classes/test_classes_serialization.py index 7ff139d3e..0ce70ae07 100644 --- a/tests/integration/classes/test_classes_serialization.py +++ b/tests/integration/classes/test_classes_serialization.py @@ -3,8 +3,9 @@ from typing import List from unittest import TestCase -from pydantic import parse_obj_as from pydantic import ValidationError +from pydantic import parse_obj_as + from superannotate.lib.app.serializers import BaseSerializer from superannotate.lib.core.entities.classes import AnnotationClassEntity from superannotate.lib.core.entities.classes import AttributeGroup @@ -56,8 +57,5 @@ def test_group_type_wrong_arg(self): attribute_groups=[AttributeGroup(name="sad", is_multiselect="True", group_type="asd")] ) except ValidationError as e: - assert [ - 'group_type', 'Invalid', 'value,', 'permitted:', "'radio',", "'checklist',", "'numeric',", "'text'" - ] == wrap_error(e).split() - - + assert ['group_type', 'Available', 'values', 'are:', 'RADIO,', 'CHECKLIST,', 'NUMERIC,', + 'TEXT'] == wrap_error(e).split() diff --git a/tests/unit/test_validators.py b/tests/unit/test_validators.py deleted file mode 100644 index 9ddaddacb..000000000 --- a/tests/unit/test_validators.py +++ /dev/null @@ -1,1932 +0,0 @@ -import json -import os -import tempfile -from os.path import dirname -from unittest import TestCase -from unittest.mock import patch - -from src.superannotate import SAClient - -sa = SAClient() - -VECTOR_ANNOTATION_JSON_WITH_BBOX = { - 'metadata': { - 'name': 'example_image_1.jpg', 'width': 1024, 'height': 683, 'status': 'Completed', 'pinned': False, - 'isPredicted': None, 'projectId': None, 'annotatorEmail': None, 'qaEmail': None - }, 'instances': [ - { - 'type': 'bbox', 'classId': 72274, 'probability': 100, 'points': { - 'x2': 465.23, 'y1': 341.5, 'y2': 357.09 - }, - 'groupId': 0, 'pointLabels': {}, 'locked': False, 'visible': False, - 'attributes': [ - { - 'id': 117845, 'groupId': 28230, 'name': '2', 'groupName': 'Num doors' - } - ], - 'trackingId': 'aaa97f80c9e54a5f2dc2e920fc92e5033d9af45b', - # 'createdBy': None, 'creationType': None, 'updatedAt': None, 'updatedBy': None, 'error': None, 'createdAt': None, - 'className': 'Personal vehicle' - } - ] -} - - -class TestValidators(TestCase): - TEST_VECTOR_FOLDER_PATH = "data_set/sample_project_vector" - VECTOR_JSON = "example_image_1.jpg___objects.json" - - @property - def vector_folder_path(self): - return os.path.join(dirname(dirname(__file__)), self.TEST_VECTOR_FOLDER_PATH) - - def test_validate_annotations_should_note_raise_errors(self): - with open(os.path.join(self.vector_folder_path, self.VECTOR_JSON), "r") as f: - report = sa.controller.validate_annotations("vector", json.load(f)).data - assert not report - - def test_validate_annotation_with_wrong_bbox(self): - report = sa.controller.validate_annotations("vector", VECTOR_ANNOTATION_JSON_WITH_BBOX).data - assert ("instances[0].points", "'x1' is a required property") == report[0] - - def test_validate_annotation_without_metadata(self): - report = sa.controller.validate_annotations("vector", {"instances": []}).data - assert ("", "'metadata' is a required property") == report[0] - - -class TestTypeHandling(TestCase): - ANNOTATION = """ - { - "metadata": { - "name": "example_image_1.jpg", - "width": 1024, - "height": 683, - "status": "Completed", - "pinned": false, - "isPredicted": null, - "projectId": null, - "annotatorEmail": null, - "qaEmail": null - }, - "instances": [ - { - "type": "invalid_type", - "classId": 72274, - "probability": 100, - "points": { - - "x2": 465.23, - "y1": 341.5, - "y2": 357.09 - }, - "groupId": 0, - "pointLabels": {}, - "locked": false, - "visible": false, - "attributes": [ - { - "id": 117845, - "groupId": 28230, - "name": "2", - "groupName": "Num doors" - } - ], - "trackingId": "aaa97f80c9e54a5f2dc2e920fc92e5033d9af45b", - "error": null, - "createdAt": null, - "createdBy": null, - "creationType": null, - "updatedAt": null, - "updatedBy": null, - "className": "Personal vehicle" - } - ] - } - """ - - TEST_VECTOR_FOLDER_PATH = "data_set/sample_project_vector" - VECTOR_JSON = "example_image_1.jpg___objects.json" - - @property - def vector_folder_path(self): - return os.path.join(dirname(dirname(__file__)), self.TEST_VECTOR_FOLDER_PATH) - - def test_validate_document_annotation_without_classname(self): - with tempfile.TemporaryDirectory() as tmpdir_name: - with open(f"{tmpdir_name}/test_validate_document_annotation_without_classname.json", - "w") as test_validate_document_annotation_without_classname: - test_validate_document_annotation_without_classname.write( - ''' - { - "metadata": { - "name": "text_file_example_1", - "status": "NotStarted", - "url": "https://sa-public-files.s3.us-west-2.amazonaws.com/Text+project/text_file_example_1.txt", - "projectId": 167826, - "annotatorEmail": null, - "qaEmail": null, - "lastAction": { - "email": "some.email@gmail.com", - "timestamp": 1636620976450 - } - }, - "instances": [{ - "type": "entity", - "start": 253, - "end": 593, - "classId": -1, - "createdAt": "2021-10-22T10:40:26.151Z", - "createdBy": { - "email": "some.email@gmail.com", - "role": "Admin" - }, - "updatedAt": "2021-10-22T10:40:29.953Z", - "updatedBy": { - "email": "some.email@gmail.com", - "role": "Admin" - }, - "attributes": [], - "creationType": "Manual" - }], - "tags": [], - "freeText": "" - } - ''' - ) - - self.assertTrue(sa.validate_annotations("Document", os.path.join(self.vector_folder_path, - f"{tmpdir_name}/test_validate_document_annotation_without_classname.json"))) - - @patch('builtins.print') - def test_validate_annotation_with_wrong_bbox(self, mock_print): - with tempfile.TemporaryDirectory() as tmpdir_name: - with open(f"{tmpdir_name}/vector.json", "w") as vector_json: - vector_json.write(self.ANNOTATION) - sa.validate_annotations("vector", os.path.join(self.vector_folder_path, f"{tmpdir_name}/vector.json")) - mock_print.assert_any_call('instances[0] invalid instance') - - def test_validate_document_annotation(self): - with tempfile.TemporaryDirectory() as tmpdir_name: - with open(f"{tmpdir_name}/doc.json", "w") as doc_json: - doc_json.write( - ''' - { - "metadata": { - "name": "text_file_example_1", - "status": "NotStarted", - "url": "https://sa-public-files.s3.us-west-2.amazonaws.com/Text+project/text_file_example_1.txt", - "projectId": 167826, - "annotatorEmail": null, - "qaEmail": null, - "lastAction": { - "email": "some.email@gmail.com", - "timestamp": 1636620976450 - } - }, - "instances": [], - "tags": [], - "freeText": "" - } - ''' - ) - self.assertTrue( - sa.validate_annotations("Document", os.path.join(self.vector_folder_path, f"{tmpdir_name}/doc.json"))) - - def test_validate_pixel_annotation(self): - with tempfile.TemporaryDirectory() as tmpdir_name: - with open(f"{tmpdir_name}/pixel.json", "w") as pix_json: - pix_json.write( - ''' - { - "metadata": { - "lastAction": { - "email": "some.email@gmail.com", - "timestamp": 1636627539398 - }, - "width": 1024, - "height": 683, - "name": "example_image_1.jpg", - "projectId": 164324, - "isPredicted": false, - "isSegmented": false, - "status": "NotStarted", - "pinned": false, - "annotatorEmail": null, - "qaEmail": null - }, - "comments": [], - "tags": [], - "instances": [] - } - ''' - ) - self.assertTrue( - sa.validate_annotations("Pixel", os.path.join(self.vector_folder_path, f"{tmpdir_name}/pixel.json"))) - - def test_validate_video_export_annotation(self): - with tempfile.TemporaryDirectory() as tmpdir_name: - with open(f"{tmpdir_name}/video_export.json", "w") as video_export: - video_export.write( - ''' - { - "metadata": { - "name": "video.mp4", - "width": 848, - "height": 476, - "status": "NotStarted", - "url": "https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_480_1_5MG.mp4", - "duration": 2817000, - "projectId": 164334, - "error": null, - "annotatorEmail": null, - "qaEmail": null, - "lastAction": { - "timestamp": 1636384061135, - "email": "some.email@gmail.com" - } - }, - "instances": [], - "tags": [] - } - ''' - ) - self.assertTrue(sa.validate_annotations("Video", os.path.join(self.vector_folder_path, - f"{tmpdir_name}/video_export.json"))) - - def test_validate_vector_empty_annotation(self): - with tempfile.TemporaryDirectory() as tmpdir_name: - with open(f"{tmpdir_name}/vector_empty.json", "w") as vector_empty: - vector_empty.write( - ''' - { - "metadata": { - "lastAction": { - "email": "some.email@gmail.com", - "timestamp": 1636627956948 - }, - "width": 1024, - "height": 683, - "name": "example_image_1.jpg", - "projectId": 162462, - "isPredicted": false, - "status": "NotStarted", - "pinned": false, - "annotatorEmail": null, - "qaEmail": null - }, - "comments": [], - "tags": [], - "instances": [] - } - ''' - ) - self.assertTrue(sa.validate_annotations("Vector", os.path.join(self.vector_folder_path, - f"{tmpdir_name}/vector_empty.json"))) - - def test_validate_error_message_format(self): - data = ''' - { - "metadata": {} - } - ''' - - report = sa.controller.validate_annotations("vector", json.loads(data)).data - assert ('metadata', '\'name\' is a required property') in report - - def test_validate_document_annotation_wrong_class_id(self): - data = ''' - { - "metadata": { - "name": "text_file_example_1", - "status": "NotStarted", - "url": "https://sa-public-files.s3.us-west-2.amazonaws.com/Text+project/text_file_example_1.txt", - "projectId": 167826, - "annotatorEmail": null, - "qaEmail": null, - "lastAction": { - "email": "some.email@gmail.com", - "timestamp": 1636620976450 - } - }, - "instances": [{ - "type": "entity", - "start": 253, - "end": 593, - "classId": "string", - "createdAt": "2021-10-22T10:40:26.151Z", - "createdBy": { - "email": "some.email@gmail.com", - "role": "Admin" - }, - "updatedAt": "2021-10-22T10:40:29.953Z", - "updatedBy": { - "email": "some.email@gmail.com", - "role": "Admin" - }, - "attributes": [], - "creationType": "Manual", - "className": "vid" - }], - "tags": [], - "freeText": "" - } - ''' - report = sa.controller.validate_annotations("document", json.loads(data)).data - assert ('instances[0].classId', '\'string\' is not of type \'integer\'') in report - - def test_validate_document_annotation_with_null_created_at(self): - with tempfile.TemporaryDirectory() as tmpdir_name: - with open(f"{tmpdir_name}/test_validate_document_annotation_with_null_created_at.json", - "w") as test_validate_document_annotation_with_null_created_at: - test_validate_document_annotation_with_null_created_at.write( - ''' - { - "metadata": { - "name": "text_file_example_1", - "status": "NotStarted", - "url": "https://sa-public-files.s3.us-west-2.amazonaws.com/Text+project/text_file_example_1.txt", - "projectId": 167826, - "annotatorEmail": null, - "qaEmail": null, - "lastAction": { - "email": "some.email@gmail.com", - "timestamp": 1636620976450 - } - }, - "instances": [{ - "type": "entity", - "start": 253, - "end": 593, - "classId": 1, - "createdAt": null, - "createdBy": { - "email": "some.email@gmail.com", - "role": "Admin" - }, - "updatedAt": null, - "updatedBy": { - "email": "some.email@gmail.com", - "role": "Admin" - }, - "attributes": [], - "creationType": "Manual", - "className": "vid" - }], - "tags": [], - "freeText": "" - } - ''' - ) - self.assertTrue(sa.validate_annotations("Document", os.path.join(self.vector_folder_path, - f"{tmpdir_name}/test_validate_document_annotation_with_null_created_at.json"))) - - def test_validate_vector_instance_type_and_attr_annotation(self): - data = ''' - { - "metadata": { - "lastAction": { - "email": "some.email@gmail.com", - "timestamp": 1636958573242 - }, - "width": 1234, - "height": 1540, - "name": "t.png", - "projectId": 164988, - "isPredicted": false, - "status": "Completed", - "pinned": false, - "annotatorEmail": null, - "qaEmail": null - }, - "comments": [], - "tags": [], - "instances": [ - { - "classId": 880080, - "probability": 100, - "points": { - "x1": 148.99, - "x2": 1005.27, - "y1": 301.96, - "y2": 1132.36 - }, - "groupId": 0, - "pointLabels": {}, - "locked": false, - "visible": true, - "attributes": [], - "trackingId": null, - "error": null, - "createdAt": "2021-11-15T06:43:09.812Z", - "createdBy": { - "email": "shab.prog@gmail.com", - "role": "Admin" - }, - "creationType": "Manual", - "updatedAt": "2021-11-15T06:43:13.831Z", - "updatedBy": { - "email": "shab.prog@gmail.com", - "role": "Admin" - }, - "className": "kj" - } - ] - } - ''' - report = sa.controller.validate_annotations("vector", json.loads(data)).data - assert ('instances[0]', 'type required') in report - - @patch('builtins.print') - def test_validate_vector_invalid_instance_type_and_attr_annotation(self, mock_print): - with tempfile.TemporaryDirectory() as tmpdir_name: - with open(f"{tmpdir_name}/test_validate_vector_invalid_instace_type_and_attr_annotation.json", - "w") as test_validate_vector_invalid_instace_type_and_attr_annotation: - test_validate_vector_invalid_instace_type_and_attr_annotation.write( - ''' - { - "metadata": { - "lastAction": { - "email": "some.email@gmail.com", - "timestamp": 1636958573242 - }, - "width": 1234, - "height": 1540, - "name": "t.png", - "projectId": 164988, - "isPredicted": false, - "status": "Completed", - "pinned": false, - "annotatorEmail": null, - "qaEmail": null - }, - "comments": [], - "tags": [], - "instances": [ - { - "type": "bad_type", - "classId": 880080, - "probability": 100, - "points": { - "x1": 148.99, - "x2": 1005.27, - "y1": 301.96, - "y2": 1132.36 - }, - "groupId": 0, - "pointLabels": {}, - "locked": false, - "visible": true, - "attributes": [], - "trackingId": null, - "error": null, - "createdAt": "2021-11-15T06:43:09.812Z", - "createdBy": { - "email": "shab.prog@gmail.com", - "role": "Admin" - }, - "creationType": "Manual", - "updatedAt": "2021-11-15T06:43:13.831Z", - "updatedBy": { - "email": "shab.prog@gmail.com", - "role": "Admin" - }, - "className": "kj" - } - ] - } - ''' - ) - - sa.validate_annotations( - "Vector", - os.path.join(self.vector_folder_path, - f"{tmpdir_name}/test_validate_vector_invalid_instace_type_and_attr_annotation.json") - ) - mock_print.assert_any_call('instances[0] invalid instance') - - def test_validate_video_invalid_instance_type_and_attr_annotation(self): - data = ''' - { - "metadata": { - "name": "video.mp4", - "width": 480, - "height": 270, - "status": "NotStarted", - "url": "https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_480_1_5MG.mp4", - "duration": 30526667, - "projectId": 152038, - "error": null, - "annotatorEmail": null, - "qaEmail": null - }, - "instances": [ - { - "meta": { - "type": "bbox", - "classId": 859496, - "className": "vid", - "pointLabels": { - "3": "point label bro" - }, - "start": 0, - "end": 30526667 - }, - "parameters": [ - { - "start": 0, - "end": 30526667, - "timestamps": [ - { - "points": { - "x1": 223.32, - "y1": 78.45, - "x2": 312.31, - "y2": 176.66 - }, - "timestamp": 0, - "attributes": [] - }, - { - "points": { - "x1": 182.08, - "y1": 33.18, - "x2": 283.45, - "y2": 131.39 - }, - "timestamp": 17271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.32, - "y1": 36.33, - "x2": 284.01, - "y2": 134.54 - }, - "timestamp": 18271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 181.49, - "y1": 45.09, - "x2": 283.18, - "y2": 143.3 - }, - "timestamp": 19271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 181.9, - "y1": 48.35, - "x2": 283.59, - "y2": 146.56 - }, - "timestamp": 19725864, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 181.49, - "y1": 52.46, - "x2": 283.18, - "y2": 150.67 - }, - "timestamp": 20271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 181.49, - "y1": 63.7, - "x2": 283.18, - "y2": 161.91 - }, - "timestamp": 21271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.07, - "y1": 72.76, - "x2": 283.76, - "y2": 170.97 - }, - "timestamp": 22271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.07, - "y1": 81.51, - "x2": 283.76, - "y2": 179.72 - }, - "timestamp": 23271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.42, - "y1": 97.19, - "x2": 284.11, - "y2": 195.4 - }, - "timestamp": 24271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.42, - "y1": 97.19, - "x2": 284.11, - "y2": 195.4 - }, - "timestamp": 30526667, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - } - ] - } - ] - }, - { - "meta": { - "type": "bbox", - "classId": 859496, - "className": "vid", - "start": 29713736, - "end": 30526667 - }, - "parameters": [ - { - "start": 29713736, - "end": 30526667, - "timestamps": [ - { - "points": { - "x1": 132.82, - "y1": 129.12, - "x2": 175.16, - "y2": 188 - }, - "timestamp": 29713736, - "attributes": [] - }, - { - "points": { - "x1": 132.82, - "y1": 129.12, - "x2": 175.16, - "y2": 188 - }, - "timestamp": 30526667, - "attributes": [] - } - ] - } - ] - }, - { - "meta": { - "type": "bad_type", - "classId": 859496, - "className": "vid", - "start": 5528212, - "end": 7083022 - }, - "parameters": [ - { - "start": 5528212, - "end": 7083022, - "timestamps": [ - { - "timestamp": 5528212, - "attributes": [] - }, - { - "timestamp": 6702957, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "timestamp": 7083022, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - } - ] - } - ] - } - ], - "tags": [ - "some tag" - ] - } - ''' - - report = sa.controller.validate_annotations("video", json.loads(data)).data - assert ('instances[2]', 'invalid instance') in report - - def test_validate_video_invalid_instance_without_type_and_attr_annotation(self): - data = ''' - { - "metadata": { - "name": "video.mp4", - "width": 480, - "height": 270, - "status": "NotStarted", - "url": "https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_480_1_5MG.mp4", - "duration": 30526667, - "projectId": 152038, - "error": null, - "annotatorEmail": null, - "qaEmail": null - }, - "instances": [ - { - "meta": { - "type": "bbox", - "classId": 859496, - "className": "vid", - "pointLabels": { - "3": "point label bro" - }, - "start": 0, - "end": 30526667 - }, - "parameters": [ - { - "start": 0, - "end": 30526667, - "timestamps": [ - { - "points": { - "x1": 223.32, - "y1": 78.45, - "x2": 312.31, - "y2": 176.66 - }, - "timestamp": 0, - "attributes": [] - }, - { - "points": { - "x1": 182.08, - "y1": 33.18, - "x2": 283.45, - "y2": 131.39 - }, - "timestamp": 17271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.32, - "y1": 36.33, - "x2": 284.01, - "y2": 134.54 - }, - "timestamp": 18271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 181.49, - "y1": 45.09, - "x2": 283.18, - "y2": 143.3 - }, - "timestamp": 19271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 181.9, - "y1": 48.35, - "x2": 283.59, - "y2": 146.56 - }, - "timestamp": 19725864, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 181.49, - "y1": 52.46, - "x2": 283.18, - "y2": 150.67 - }, - "timestamp": 20271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 181.49, - "y1": 63.7, - "x2": 283.18, - "y2": 161.91 - }, - "timestamp": 21271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.07, - "y1": 72.76, - "x2": 283.76, - "y2": 170.97 - }, - "timestamp": 22271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.07, - "y1": 81.51, - "x2": 283.76, - "y2": 179.72 - }, - "timestamp": 23271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.42, - "y1": 97.19, - "x2": 284.11, - "y2": 195.4 - }, - "timestamp": 24271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.42, - "y1": 97.19, - "x2": 284.11, - "y2": 195.4 - }, - "timestamp": 30526667, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - } - ] - } - ] - }, - { - "meta": { - "type": "bbox", - "classId": 859496, - "className": "vid", - "start": 29713736, - "end": 30526667 - }, - "parameters": [ - { - "start": 29713736, - "end": 30526667, - "timestamps": [ - { - "points": { - "x1": 132.82, - "y1": 129.12, - "x2": 175.16, - "y2": 188 - }, - "timestamp": 29713736, - "attributes": [] - }, - { - "points": { - "x1": 132.82, - "y1": 129.12, - "x2": 175.16, - "y2": 188 - }, - "timestamp": 30526667, - "attributes": [] - } - ] - } - ] - }, - { - "meta": { - "classId": 859496, - "className": "vid", - "start": 5528212, - "end": 7083022 - }, - "parameters": [ - { - "start": 5528212, - "end": 7083022, - "timestamps": [ - { - "timestamp": 5528212, - "attributes": [] - }, - { - "timestamp": 6702957, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "timestamp": 7083022, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - } - ] - } - ] - } - ], - "tags": [ - "some tag" - ] - } - ''' - report = sa.controller.validate_annotations("video", json.loads(data)).data - assert ('instances[2]', 'type required') in report - - def test_validate_vector_template_polygon_polyline_min_annotation(self): - data = ''' - { - "metadata": { - "lastAction": { - "email": "some@some.com", - "timestamp": 1636964198056 - }, - "width": "1234", - "height": 1540, - "name": "t.png", - "projectId": 164988, - "isPredicted": false, - "status": "Completed", - "pinned": false, - "annotatorEmail": null, - "qaEmail": null - }, - "comments": [], - "tags": [], - "instances": [ - { - "type": "template", - "classId": 880080, - "probability": 100, - "points": [ - ], - "connections": [ - { - "id": 1, - "from": 1, - "to": 2 - } - ], - "groupId": 0, - "pointLabels": {}, - "locked": false, - "visible": true, - "attributes": [], - "templateId": 4728, - "trackingId": null, - "error": null, - "createdAt": "2021-11-15T08:24:40.712Z", - "createdBy": { - "email": "shab.prog@gmail.com", - "role": "Admin" - }, - "creationType": "Manual", - "updatedAt": "2021-11-15T08:24:46.440Z", - "updatedBy": { - "email": "shab.prog@gmail.com", - "role": "Admin" - }, - "className": "kj", - "templateName": "templ1" - }, - { - "type": "polygon", - "classId": 880080, - "probability": 100, - "points": [ - 233.69 - ], - "groupId": 0, - "pointLabels": {}, - "locked": true, - "visible": true, - "attributes": [], - "trackingId": null, - "error": null, - "createdAt": "2021-11-15T08:18:16.103Z", - "createdBy": { - "email": "some@some.com", - "role": "Admin" - }, - "creationType": "Manual", - "updatedAt": "2021-11-15T08:18:20.233Z", - "updatedBy": { - "email": "some@some.com", - "role": "Admin" - }, - "className": "kj" - }, - { - "type": "polyline", - "classId": 880080, - "probability": 100, - "points": [ - 218.22 - ], - "groupId": 0, - "pointLabels": {}, - "locked": false, - "visible": true, - "attributes": [], - "trackingId": null, - "error": null, - "createdAt": "2021-11-15T08:18:06.203Z", - "createdBy": { - "email": "some@some.com", - "role": "Admin" - }, - "creationType": "Manual", - "updatedAt": "2021-11-15T08:18:13.439Z", - "updatedBy": { - "email": "some@some.com", - "role": "Admin" - }, - "className": "kj" - }, - { - "type": "bbox", - "classId": 880080, - "probability": 100, - "points": { - "x1": 487.78, - "x2": 1190.87, - "y1": 863.91, - "y2": 1463.78 - }, - "groupId": 0, - "pointLabels": {}, - "locked": false, - "visible": true, - "attributes": [], - "trackingId": null, - "error": null, - "createdAt": "2021-11-15T06:43:09.812Z", - "createdBy": { - "email": "some@some.com", - "role": "Admin" - }, - "creationType": "Manual", - "updatedAt": "2021-11-15T08:16:48.807Z", - "updatedBy": { - "email": "some@some.com", - "role": "Admin" - }, - "className": "kj" - } - ] - } - ''' - - report = sa.controller.validate_annotations("vector", json.loads(data)).data - assert [ - ('instances[0].points', '[] is too short'), - ('instances[1].points', '[233.69] is too short'), - ('instances[2].', "'x' is a required property"), - ('instances[2].', "'y' is a required property"), - ('metadata.width', "'1234' is not of type 'integer'") - ] == report - - def test_validate_video_point_labels(self): - data = ''' - { - "metadata": { - "name": "video.mp4", - "width": 480, - "height": 270, - "status": "NotStarted", - "url": "https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_480_1_5MG.mp4", - "duration": 30526667, - "projectId": 152038, - "error": null, - "annotatorEmail": null, - "qaEmail": null - }, - "instances": [ - { - "meta": { - "type": "bbox", - "classId": 859496, - "className": "vid", - "pointLabels": "bad_point_label", - "start": 0, - "end": 30526667 - }, - "parameters": [ - { - "start": 0, - "end": 30526667, - "timestamps": [ - { - "points": { - "x1": 223.32, - "y1": 78.45, - "x2": 312.31, - "y2": 176.66 - }, - "timestamp": 0, - "attributes": [] - }, - { - "points": { - "x1": 182.08, - "y1": 33.18, - "x2": 283.45, - "y2": 131.39 - }, - "timestamp": 17271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.32, - "y1": 36.33, - "x2": 284.01, - "y2": 134.54 - }, - "timestamp": 18271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 181.49, - "y1": 45.09, - "x2": 283.18, - "y2": 143.3 - }, - "timestamp": 19271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 181.9, - "y1": 48.35, - "x2": 283.59, - "y2": 146.56 - }, - "timestamp": 19725864, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 181.49, - "y1": 52.46, - "x2": 283.18, - "y2": 150.67 - }, - "timestamp": 20271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 181.49, - "y1": 63.7, - "x2": 283.18, - "y2": 161.91 - }, - "timestamp": 21271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.07, - "y1": 72.76, - "x2": 283.76, - "y2": 170.97 - }, - "timestamp": 22271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.07, - "y1": 81.51, - "x2": 283.76, - "y2": 179.72 - }, - "timestamp": 23271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.42, - "y1": 97.19, - "x2": 284.11, - "y2": 195.4 - }, - "timestamp": 24271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.42, - "y1": 97.19, - "x2": 284.11, - "y2": 195.4 - }, - "timestamp": 30526667, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - } - ] - } - ] - }, - { - "meta": { - "type": "bbox", - "classId": 859496, - "className": "vid", - "start": 29713736, - "end": 30526667 - }, - "parameters": [ - { - "start": 29713736, - "end": 30526667, - "timestamps": [ - { - "points": { - "x1": 132.82, - "y1": 129.12, - "x2": 175.16, - "y2": 188 - }, - "timestamp": 29713736, - "attributes": [] - }, - { - "points": { - "x1": 132.82, - "y1": 129.12, - "x2": 175.16, - "y2": 188 - }, - "timestamp": 30526667, - "attributes": [] - } - ] - } - ] - }, - { - "meta": { - "type": "event", - "classId": 859496, - "className": "vid", - "start": 5528212, - "end": 7083022 - }, - "parameters": [ - { - "start": 5528212, - "end": 7083022, - "timestamps": [ - { - "timestamp": 5528212, - "attributes": [] - }, - { - "timestamp": 6702957, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "timestamp": 7083022, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - } - ] - } - ] - } - ], - "tags": [ - "some tag" - ] - } - ''' - - report = sa.controller.validate_annotations("video", json.loads(data)).data - assert ('instances[0].meta.pointLabels', "'bad_point_label' is not of type 'object'") in report - - def test_validate_video_point_labels_bad_keys(self): - with tempfile.TemporaryDirectory() as tmpdir_name: - with open(f"{tmpdir_name}/test_validate_video_point_labels_bad_keys.json", - "w") as test_validate_video_point_labels_bad_keys: - test_validate_video_point_labels_bad_keys.write( - ''' - { - "metadata": { - "name": "video.mp4", - "width": 480, - "height": 270, - "status": "NotStarted", - "url": "https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_480_1_5MG.mp4", - "duration": 30526667, - "projectId": 152038, - "error": null, - "annotatorEmail": null, - "qaEmail": null - }, - "instances": [ - { - "meta": { - "type": "bbox", - "classId": 859496, - "className": "vid", - "pointLabels": { - "bad_key_1" : "a", - "bad_key_2" : "b", - " " : "afsd", - "1" : ["fasdf","sdfsdf"] - }, - "start": 0, - "end": 30526667 - }, - "parameters": [ - { - "start": 0, - "end": 30526667, - "timestamps": [ - { - "points": { - "x1": 223.32, - "y1": 78.45, - "x2": 312.31, - "y2": 176.66 - }, - "timestamp": 0, - "attributes": [] - }, - { - "points": { - "x1": 182.08, - "y1": 33.18, - "x2": 283.45, - "y2": 131.39 - }, - "timestamp": 17271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.32, - "y1": 36.33, - "x2": 284.01, - "y2": 134.54 - }, - "timestamp": 18271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 181.49, - "y1": 45.09, - "x2": 283.18, - "y2": 143.3 - }, - "timestamp": 19271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 181.9, - "y1": 48.35, - "x2": 283.59, - "y2": 146.56 - }, - "timestamp": 19725864, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 181.49, - "y1": 52.46, - "x2": 283.18, - "y2": 150.67 - }, - "timestamp": 20271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 181.49, - "y1": 63.7, - "x2": 283.18, - "y2": 161.91 - }, - "timestamp": 21271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.07, - "y1": 72.76, - "x2": 283.76, - "y2": 170.97 - }, - "timestamp": 22271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.07, - "y1": 81.51, - "x2": 283.76, - "y2": 179.72 - }, - "timestamp": 23271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.42, - "y1": 97.19, - "x2": 284.11, - "y2": 195.4 - }, - "timestamp": 24271058, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "points": { - "x1": 182.42, - "y1": 97.19, - "x2": 284.11, - "y2": 195.4 - }, - "timestamp": 30526667, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - } - ] - } - ] - }, - { - "meta": { - "type": "bbox", - "classId": 859496, - "className": "vid", - "start": 29713736, - "end": 30526667 - }, - "parameters": [ - { - "start": 29713736, - "end": 30526667, - "timestamps": [ - { - "points": { - "x1": 132.82, - "y1": 129.12, - "x2": 175.16, - "y2": 188 - }, - "timestamp": 29713736, - "attributes": [] - }, - { - "points": { - "x1": 132.82, - "y1": 129.12, - "x2": 175.16, - "y2": 188 - }, - "timestamp": 30526667, - "attributes": [] - } - ] - } - ] - }, - { - "meta": { - "type": "event", - "classId": 859496, - "className": "vid", - "start": 5528212, - "end": 7083022, - "pointLabels": {} - }, - "parameters": [ - { - "start": 5528212, - "end": 7083022, - "timestamps": [ - { - "timestamp": 5528212, - "attributes": [] - }, - { - "timestamp": 6702957, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "timestamp": "7083022", - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - } - ] - } - ] - }, - { - "parameters": [ - { - "start": 5528212, - "end": 7083022, - "timestamps": [ - { - "timestamp": 5528212, - "attributes": [] - }, - { - "timestamp": 6702957, - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - }, - { - "timestamp": "7083022", - "attributes": [ - { - "id": 1175876, - "groupId": 338357, - "name": "attr", - "groupName": "attr g" - } - ] - } - ] - } - ] - }, - { - "meta": "afsdfadsf" - }, - { - "meta" : [] - } - ], - "tags": [ - 123 - ] - } - ''' - ) - - with open(f"{tmpdir_name}/test_validate_video_point_labels_bad_keys.json", "r") as f: - data = json.loads(f.read()) - validator = AnnotationValidators.get_validator("video")(data) - self.assertFalse(validator.is_valid()) - self.assertEqual(len(validator.generate_report()), 409) diff --git a/tests/unit/test_video_convertor.py b/tests/unit/test_video_convertor.py deleted file mode 100644 index e48b187e7..000000000 --- a/tests/unit/test_video_convertor.py +++ /dev/null @@ -1,231 +0,0 @@ -from unittest import TestCase - -from src.superannotate.lib.core.video_convertor import VideoFrameGenerator - -TEST_SMALL_ANNOTATION = { - "metadata": {"name": "blue cat", "width": 848, "height": 476, "status": "InProgress", - "url": "https://drive.google.com/uc?export=download&id=1BNs7sQqWv0tnQtZYiDhHXUzKTS0mUk3X", - "duration": 2817000, "projectId": 226935, "error": None, "annotatorEmail": None, - "qaEmail": None, - "lastAction": {"timestamp": 1652277982880, "email": "arturn@superannotate.com"}}, - "instances": [{"meta": {"type": "bbox", "classId": 1740965, "className": "class", - "pointLabels": {}, - "createdBy": {"email": "arturn@superannotate.com", "role": "Admin"}, - "createdAt": "2022-05-11T14:06:20.992Z", - "updatedBy": {"email": "arturn@superannotate.com", "role": "Admin"}, - "updatedAt": "2022-05-11T14:06:22.874Z", "start": 203033, - "end": 744547}, "parameters": [{"start": 203033, "end": 744547, - "timestamps": [{"points": { - "x1": 45.73, - "y1": 226.8, - "x2": 208.93, - "y2": 373.74 - }, - "timestamp": 203033, - "attributes": []}, { - "points": { - "x1": 45.73, - "y1": 226.8, - "x2": 208.93, - "y2": 373.74}, - "timestamp": 744547, - "attributes": []}]}]}], - "tags": ["gff"]} - -TEST_ANNOTATION = {"metadata": {"name": "video_file_example_1", "width": 1920, "height": 1080, "status": "InProgress", - "url": "https://sa-public-files.s3.us-west-2.amazonaws.com/Video+project/video_file_example_1.mp4", - "duration": 30526667, "projectId": 202655, "error": None, "annotatorEmail": None, - "qaEmail": None, - "lastAction": {"timestamp": 1652789740739, "email": "arturn@superannotate.com"}}, - "instances": - [ - {"meta": {"type": "bbox", "classId": 1379945, "className": "tree", "pointLabels": {}, - "createdBy": {"email": "arturn@superannotate.com", "role": "Admin"}, - "createdAt": "2022-03-02T12:23:10.887Z", - "updatedBy": {"email": "arturn@superannotate.com", "role": "Admin"}, - "updatedAt": "2022-05-17T12:15:40.728Z", "start": 0, "end": 2515879}, - "parameters": [{"start": 0, "end": 2515879, "timestamps": [ - {"points": {"x1": 496.13, "y1": 132.02, "x2": 898.05, "y2": 515.25}, - "timestamp": 0, "attributes": [ - {"id": 2699916, "groupId": 1096002, "name": "standing", - "groupName": "state"}]}, - {"points": {"x1": 744.37, "y1": 66.41, "x2": 1146.29, "y2": 449.64}, - "timestamp": 640917, "attributes": [ - {"id": 2699917, "groupId": 1096002, "name": "falling", - "groupName": "state"}]}, - {"points": {"x1": 857.56, "y1": 227.21, "x2": 1259.48, "y2": 610.44}, - "timestamp": 1215864, "attributes": [ - {"id": 2699917, "groupId": 1096002, "name": "falling", - "groupName": "state"}]}, - {"points": {"x1": 857.56, "y1": 227.21, "x2": 1259.48, "y2": 610.44}, - "timestamp": 1572238, "attributes": [ - {"id": 2699916, "groupId": 1096002, "name": "standing", - "groupName": "state"}]}, - {"points": {"x1": 1038.3, "y1": 270.54, "x2": 1440.22, "y2": 653.77}, - "timestamp": 2255379, "attributes": [ - {"id": 2699916, "groupId": 1096002, "name": "standing", - "groupName": "state"}]}, - {"points": {"x1": 1038.3, "y1": 270.54, "x2": 1440.22, "y2": 653.77}, - "timestamp": 2515879, "attributes": [ - {"id": 2699917, "groupId": 1096002, "name": "falling", - "groupName": "state"}]}]}]}, { - "meta": {"type": "bbox", "classId": 1379945, "className": "tree", - "pointLabels": {}, - "createdBy": {"email": "arturn@superannotate.com", "role": "Admin"}, - "createdAt": "2022-03-02T12:36:52.126Z", - "updatedBy": {"email": "arturn@superannotate.com", "role": "Admin"}, - "updatedAt": "2022-03-02T12:38:24.056Z", "start": 2790828, - "end": 5068924}, "parameters": [{"start": 2790828, "end": 5068924, - "timestamps": [{"points": {"x1": 507.3, - "y1": 569.55, - "x2": 979.58, - "y2": 965.84}, - "timestamp": 2790828, - "attributes": []}, { - "points": { - "x1": 507.3, - "y1": 569.55, - "x2": 979.58, - "y2": 965.84}, - "timestamp": 2888183, - "attributes": [ - {"id": 2699917, - "groupId": 1096002, - "name": "falling", - "groupName": "state"}]}, - {"points": {"x1": 507.3, - "y1": 569.55, - "x2": 979.58, - "y2": 965.84}, - "timestamp": 5068924, - "attributes": [ - {"id": 2699917, - "groupId": 1096002, - "name": "falling", - "groupName": "state"}]}]}] - }, - { - "meta": {"type": "bbox", "classId": 1379946, "className": "car", "pointLabels": {}, - "createdBy": {"email": "arturn@superannotate.com", "role": "Admin"}, - "createdAt": "2022-03-02T12:39:19.970Z", - "updatedBy": {"email": "arturn@superannotate.com", "role": "Admin"}, - "updatedAt": "2022-03-02T12:41:13.536Z", "start": 4502645, "end": 6723950}, - "parameters": [{"start": 4502645, "end": 6723950, "timestamps": [ - {"points": {"x1": 792.08, "y1": 671.23, "x2": 1178.97, "y2": 987.47}, - "timestamp": 4502645, "attributes": []}, - {"points": {"x1": 792.08, "y1": 671.23, "x2": 1178.97, "y2": 987.47}, - "timestamp": 5330158, "attributes": [ - {"id": 2699918, "groupId": 1096003, "name": "goes", "groupName": "movement"}, - {"id": 2699920, "groupId": 1096004, "name": "lights_on", - "groupName": "lights"}]}, - {"points": {"x1": 792.08, "y1": 671.23, "x2": 1178.97, "y2": 987.47}, - "timestamp": 5825043, "attributes": [ - {"id": 2699920, "groupId": 1096004, "name": "lights_on", - "groupName": "lights"}, {"id": 2699919, "groupId": 1096003, "name": "stops", - "groupName": "movement"}]}, - {"points": {"x1": 792.08, "y1": 671.23, "x2": 1178.97, "y2": 987.47}, - "timestamp": 6303703, "attributes": [ - {"id": 2699919, "groupId": 1096003, "name": "stops", "groupName": "movement"}, - {"id": 2699921, "groupId": 1096004, "name": "lights_off", - "groupName": "lights"}]}, - {"points": {"x1": 792.08, "y1": 671.23, "x2": 1178.97, "y2": 987.47}, - "timestamp": 6723950, "attributes": [ - {"id": 2699919, "groupId": 1096003, "name": "stops", "groupName": "movement"}, - {"id": 2699921, "groupId": 1096004, "name": "lights_off", - "groupName": "lights"}]}]}] - }, - { - "meta": {"type": "event", "classId": 1379946, "className": "car", - "createdBy": {"email": "arturn@superannotate.com", "role": "Admin"}, - "createdAt": "2022-03-02T12:41:39.135Z", - "updatedBy": {"email": "arturn@superannotate.com", "role": "Admin"}, - "updatedAt": "2022-03-02T12:41:39.135Z", "start": 1655026, - "end": 3365220}, "parameters": [{"start": 1655026, "end": 3365220, - "timestamps": [{"timestamp": 1655026, - "attributes": []}, - {"timestamp": 3365220, - "attributes": []}]}] - }, - { - "meta": { - "type": "point", "classId": 1379946, "className": "car", - "createdBy": {"email": "arturn@superannotate.com", "role": "Admin"}, - "createdAt": "2022-05-17T11:38:50.041Z", - "updatedBy": {"email": "arturn@superannotate.com", "role": "Admin"}, - "updatedAt": "2022-05-17T11:50:57.784Z", "start": 617519, "end": 2342388}, - "parameters": [ - { - "start": 617519, "end": 2342388, "timestamps": [ - { - "x": 612.81, "y": 606.79, "timestamp": 617519, "attributes": [ - { - "id": 2699918, "groupId": 1096003, "name": "goes", - "groupName": "movement"}, - {"id": 2699920, "groupId": 1096004, "name": "lights_on", - "groupName": "lights"}]}, - {"x": 653.05, "y": 648.81, "timestamp": 1266439, - "attributes": [ - {"id": 2699918, "groupId": 1096003, - "name": "goes", "groupName": "movement"}, - {"id": 2699920, "groupId": 1096004, - "name": "lights_on", - "groupName": "lights"}]}, - {"x": 691.9399999999999, "y": 682.7099999999999, "timestamp": 1569965, - "attributes": [{"id": 2699918, "groupId": 1096003, "name": "goes", - "groupName": "movement"}, - {"id": 2699921, "groupId": 1096004, "name": "lights_off", - "groupName": "lights"}]}, - {"x": 691.9399999999999, "y": 682.7099999999999, "timestamp": 2342388, - "attributes": [{"id": 2699921, "groupId": 1096004, "name": "lights_off", - "groupName": "lights"}, - {"id": 2699919, "groupId": 1096003, "name": "stops", - "groupName": "movement"}]}]}]}, { - "meta": { - "type": "point", "classId": 1379946, "className": "car", - "createdBy": {"email": "arturn@superannotate.com", "role": "Admin"}, - "createdAt": "2022-05-17T11:40:28.691Z", - "updatedBy": {"email": "arturn@superannotate.com", "role": "Admin"}, - "updatedAt": "2022-05-17T12:02:43.429Z", "start": 2878270, - "end": 5084595}, "parameters": [ - { - "start": 2878270, - "end": 5084595, - "timestamps": [ - { - "x": 915.5, "y": 461.21, - "timestamp": 2878270, - "attributes": [ - {"id": 2699918, - "groupId": 1096003, - "name": "goes", - "groupName": "movement"}, - {"id": 2699920, - "groupId": 1096004, - "name": "lights_on", - "groupName": "lights"}]}, - { - "x": 915.5, "y": 461.21, - "timestamp": 5084595, - "attributes": [ - {"id": 2699918, - "groupId": 1096003, - "name": "goes", - "groupName": "movement"}, - {"id": 2699920, - "groupId": 1096004, - "name": "lights_on", - "groupName": "lights"}]}]}]} - ], - "tags": []} - - -class TestVideoFrameGenerator(TestCase): - ANNOTATIONS_PATH = "data_set/video_annotation" - - def test_frame_generator(self): - generator = VideoFrameGenerator(TEST_SMALL_ANNOTATION, fps=1) - assert 2 == len([i for i in generator]) - - def test_frame_generator_2(self): - generator = VideoFrameGenerator(TEST_ANNOTATION, fps=1) - assert 31 == len([i for i in generator])