add-new-annotation-types #5
@@ -3,7 +3,7 @@ name: Sync Label Studio
|
||||
on:
|
||||
schedule:
|
||||
# This job will run every day at 03:00 AM
|
||||
- cron: "0 3 * * *"
|
||||
- cron: "0/10 * * * *"
|
||||
|
||||
jobs:
|
||||
sync_storage:
|
||||
|
||||
@@ -5,9 +5,12 @@ Exposes core data transfer objects and enums for use throughout the project.
|
||||
|
||||
from .angle_enum import AngleEnum
|
||||
from .annotation import Annotation
|
||||
from .colour_enum import ColourEnum
|
||||
from .contact_enum import ContactEnum
|
||||
from .depth_enum import DepthEnum
|
||||
from .distance_enum import DistanceEnum
|
||||
from .job import Job
|
||||
from .lighting_enum import LightingEnum
|
||||
from .point_of_view_enum import PointOfViewEnum
|
||||
|
||||
__all__ = [
|
||||
@@ -17,4 +20,7 @@ __all__ = [
|
||||
"DistanceEnum",
|
||||
"Job",
|
||||
"PointOfViewEnum",
|
||||
"ColourEnum",
|
||||
"DepthEnum",
|
||||
"LightingEnum",
|
||||
]
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
"""Definition of Annotation DTO."""
|
||||
|
||||
from .type_checking_base_model import TypeCheckingBaseModel
|
||||
from .distance_enum import DistanceEnum
|
||||
from .angle_enum import AngleEnum
|
||||
from .point_of_view_enum import PointOfViewEnum
|
||||
from .colour_enum import ColourEnum
|
||||
from .contact_enum import ContactEnum
|
||||
from .depth_enum import DepthEnum
|
||||
from .distance_enum import DistanceEnum
|
||||
from .lighting_enum import LightingEnum
|
||||
from .point_of_view_enum import PointOfViewEnum
|
||||
|
||||
|
||||
class Annotation(TypeCheckingBaseModel):
|
||||
"""Data Transfer Object representing an Annotation."""
|
||||
|
||||
distance: DistanceEnum
|
||||
angle: AngleEnum
|
||||
point_of_view: PointOfViewEnum
|
||||
angle_uncertainty: bool
|
||||
colour: ColourEnum
|
||||
colour_uncertainty: bool
|
||||
contact: ContactEnum
|
||||
contact_uncertainty: bool
|
||||
depth: DepthEnum
|
||||
depth_uncertainty: bool
|
||||
distance: DistanceEnum
|
||||
distance_uncertainty: bool
|
||||
lighting: LightingEnum
|
||||
lighting_uncertainty: bool
|
||||
point_of_view: PointOfViewEnum
|
||||
point_of_view_uncertainty: bool
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
"""Definition of ColourEnum DTO."""
|
||||
|
||||
from enum import StrEnum
|
||||
|
||||
|
||||
class ColourEnum(StrEnum):
|
||||
"""Enumeration for Colour values."""
|
||||
|
||||
HIGH = "high"
|
||||
MEDIUM = "medium"
|
||||
LOW = "low"
|
||||
@@ -0,0 +1,11 @@
|
||||
"""Definition of DepthEnum DTO."""
|
||||
|
||||
from enum import StrEnum
|
||||
|
||||
|
||||
class DepthEnum(StrEnum):
|
||||
"""Enumeration for Depth values."""
|
||||
|
||||
HIGH = "high"
|
||||
MEDIUM = "medium"
|
||||
LOW = "low"
|
||||
@@ -0,0 +1,11 @@
|
||||
"""Definition of LightingEnum DTO."""
|
||||
|
||||
from enum import StrEnum
|
||||
|
||||
|
||||
class LightingEnum(StrEnum):
|
||||
"""Enumeration for Lighting values."""
|
||||
|
||||
HIGH = "high"
|
||||
MEDIUM = "medium"
|
||||
LOW = "low"
|
||||
@@ -11,10 +11,13 @@ from python_repositories.adapters import MinioAdapter
|
||||
from data_store.interfaces import AnnotationRepositoryInterface
|
||||
from data_store.dto import (
|
||||
Annotation,
|
||||
DistanceEnum,
|
||||
AngleEnum,
|
||||
PointOfViewEnum,
|
||||
ColourEnum,
|
||||
ContactEnum,
|
||||
DepthEnum,
|
||||
DistanceEnum,
|
||||
LightingEnum,
|
||||
PointOfViewEnum,
|
||||
)
|
||||
|
||||
|
||||
@@ -55,10 +58,20 @@ class AnnotationRepository(MinioAdapter, AnnotationRepositoryInterface):
|
||||
data_str = buffer.read().decode(self.encoding)
|
||||
data = json.loads(data_str)
|
||||
annotation = Annotation(
|
||||
distance=DistanceEnum(data["distance"]),
|
||||
angle=AngleEnum(data["angle"]),
|
||||
point_of_view=PointOfViewEnum(data["point_of_view"]),
|
||||
angle_uncertainty=bool(data["angle_uncertainty"]),
|
||||
colour=ColourEnum(data["colour"]),
|
||||
colour_uncertainty=bool(data["colour_uncertainty"]),
|
||||
contact=ContactEnum(data["contact"]),
|
||||
contact_uncertainty=bool(data["contact_uncertainty"]),
|
||||
depth=DepthEnum(data["depth"]),
|
||||
depth_uncertainty=bool(data["depth_uncertainty"]),
|
||||
distance=DistanceEnum(data["distance"]),
|
||||
distance_uncertainty=bool(data["distance_uncertainty"]),
|
||||
lighting=LightingEnum(data["lighting"]),
|
||||
lighting_uncertainty=bool(data["lighting_uncertainty"]),
|
||||
point_of_view=PointOfViewEnum(data["point_of_view"]),
|
||||
point_of_view_uncertainty=bool(data["point_of_view_uncertainty"]),
|
||||
)
|
||||
except (KeyError, ValueError) as e:
|
||||
self.logger.error(
|
||||
|
||||
@@ -2,14 +2,10 @@
|
||||
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
import json
|
||||
from collections.abc import Generator
|
||||
from uuid import UUID
|
||||
from io import BytesIO
|
||||
import pandas as pd
|
||||
from PIL import Image
|
||||
import pytest
|
||||
import structlog
|
||||
@@ -23,10 +19,13 @@ from data_store.repositories import (
|
||||
)
|
||||
from data_store.dto import (
|
||||
Annotation,
|
||||
DistanceEnum,
|
||||
AngleEnum,
|
||||
PointOfViewEnum,
|
||||
ColourEnum,
|
||||
ContactEnum,
|
||||
DepthEnum,
|
||||
DistanceEnum,
|
||||
LightingEnum,
|
||||
PointOfViewEnum,
|
||||
Job,
|
||||
)
|
||||
|
||||
@@ -114,35 +113,35 @@ def job_id_list() -> Generator[list[UUID]]:
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def csv_data_file(
|
||||
job_id_list: list[UUID],
|
||||
) -> Generator[Path]:
|
||||
"""Create a CSV data file for testing."""
|
||||
# Create csv content
|
||||
csv_data = pd.DataFrame(
|
||||
{
|
||||
"job_id": job_id_list,
|
||||
"distance": [
|
||||
"close",
|
||||
"long",
|
||||
"wrong",
|
||||
],
|
||||
"angle": ["high", "low", "wrong"],
|
||||
"point_of_view": ["frontal", "oblique", "wrong"],
|
||||
"contact": ["offer", "demand", "wrong"],
|
||||
}
|
||||
)
|
||||
# Create data directory and file path
|
||||
data_dir = Path(tempfile.mkdtemp())
|
||||
data_path = data_dir / "annotations.csv"
|
||||
# Write CSV content to file
|
||||
csv_data.to_csv(data_path, header=True, index=False)
|
||||
# @pytest.fixture(scope="session")
|
||||
# def csv_data_file(
|
||||
# job_id_list: list[UUID],
|
||||
# ) -> Generator[Path]:
|
||||
# """Create a CSV data file for testing."""
|
||||
# # Create csv content
|
||||
# csv_data = pd.DataFrame(
|
||||
# {
|
||||
# "job_id": job_id_list,
|
||||
# "distance": [
|
||||
# "close",
|
||||
# "long",
|
||||
# "wrong",
|
||||
# ],
|
||||
# "angle": ["high", "low", "wrong"],
|
||||
# "point_of_view": ["frontal", "oblique", "wrong"],
|
||||
# "contact": ["offer", "demand", "wrong"],
|
||||
# }
|
||||
# )
|
||||
# # Create data directory and file path
|
||||
# data_dir = Path(tempfile.mkdtemp())
|
||||
# data_path = data_dir / "annotations.csv"
|
||||
# # Write CSV content to file
|
||||
# csv_data.to_csv(data_path, header=True, index=False)
|
||||
|
||||
yield data_path
|
||||
# yield data_path
|
||||
|
||||
# Cleanup
|
||||
shutil.rmtree(data_dir)
|
||||
# # Cleanup
|
||||
# shutil.rmtree(data_dir)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
@@ -245,10 +244,20 @@ def annotation_repository() -> Generator[AnnotationRepository]:
|
||||
def annotation() -> Generator[Annotation]:
|
||||
"""Provide a sample annotation for testing."""
|
||||
annotation = Annotation(
|
||||
distance=DistanceEnum.CLOSE,
|
||||
angle=AngleEnum.HIGH,
|
||||
point_of_view=PointOfViewEnum.FRONTAL,
|
||||
angle_uncertainty=True,
|
||||
colour=ColourEnum.HIGH,
|
||||
colour_uncertainty=False,
|
||||
contact=ContactEnum.OFFER,
|
||||
contact_uncertainty=True,
|
||||
depth=DepthEnum.LOW,
|
||||
depth_uncertainty=False,
|
||||
distance=DistanceEnum.CLOSE,
|
||||
distance_uncertainty=True,
|
||||
lighting=LightingEnum.MEDIUM,
|
||||
lighting_uncertainty=False,
|
||||
point_of_view=PointOfViewEnum.FRONTAL,
|
||||
point_of_view_uncertainty=True,
|
||||
)
|
||||
yield annotation
|
||||
|
||||
|
||||
@@ -7,10 +7,13 @@ from uuid import UUID
|
||||
from data_store.repositories.annotation_repository import AnnotationRepository
|
||||
from data_store.dto import (
|
||||
Annotation,
|
||||
DistanceEnum,
|
||||
AngleEnum,
|
||||
PointOfViewEnum,
|
||||
ColourEnum,
|
||||
ContactEnum,
|
||||
DepthEnum,
|
||||
DistanceEnum,
|
||||
LightingEnum,
|
||||
PointOfViewEnum,
|
||||
)
|
||||
|
||||
|
||||
@@ -47,10 +50,20 @@ class TestAnnotationRepository(unittest.TestCase):
|
||||
cls.job_id = UUID("d87022f8-4169-4d69-8512-bbd65cc1cb23")
|
||||
cls.bad_job_id = "not-a-uuid"
|
||||
cls.annotation = Annotation(
|
||||
distance=DistanceEnum.CLOSE,
|
||||
angle=AngleEnum.HIGH,
|
||||
point_of_view=PointOfViewEnum.FRONTAL,
|
||||
angle_uncertainty=True,
|
||||
colour=ColourEnum.HIGH,
|
||||
colour_uncertainty=False,
|
||||
contact=ContactEnum.OFFER,
|
||||
contact_uncertainty=True,
|
||||
depth=DepthEnum.LOW,
|
||||
depth_uncertainty=False,
|
||||
distance=DistanceEnum.CLOSE,
|
||||
distance_uncertainty=True,
|
||||
lighting=LightingEnum.MEDIUM,
|
||||
lighting_uncertainty=False,
|
||||
point_of_view=PointOfViewEnum.FRONTAL,
|
||||
point_of_view_uncertainty=True,
|
||||
)
|
||||
cls.bad_annotation = {"not_an_annotation": "irrelevant value"}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user