Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 93 additions & 1 deletion darwin/datatypes.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

from dataclasses import dataclass, field
from enum import Enum, auto
from pathlib import Path
Expand All @@ -20,7 +22,7 @@
except ImportError:
NDArray = Any # type:ignore

from darwin.path_utils import construct_full_path
from darwin.path_utils import construct_full_path, is_properties_enabled, parse_metadata

# Utility types

Expand Down Expand Up @@ -386,6 +388,96 @@ def __str__(self) -> str:
return f"{self.major}.{self.minor}{self.suffix}"


@dataclass
class Property:
"""
Represents a property of an annotation file.
"""

# Name of the property
name: str

# Type of the property
type: str

# Whether the property is required or not
required: bool

# Property options
options: list[dict[str, str]]


@dataclass
class PropertyClass:
name: str
type: str
description: Optional[str]
color: Optional[str] = None
sub_types: Optional[list[str]] = None
properties: Optional[list[Property]] = None


def parse_property_classes(metadata: dict[str, Any]) -> list[PropertyClass]:
"""
Parses the metadata file and returns a list of PropertyClass objects.

Parameters
----------
metadata : dict[str, Any]
The metadata file.

Returns
-------
list[PropertyClass]
A list of PropertyClass objects.
"""
assert "classes" in metadata, "Metadata does not contain classes"

classes = []
for metadata_cls in metadata["classes"]:
assert (
"properties" in metadata_cls
), "Metadata class does not contain properties"
classes.append(
PropertyClass(
name=metadata_cls["name"],
type=metadata_cls["type"],
description=metadata_cls.get("description"),
color=metadata_cls.get("color"),
sub_types=metadata_cls.get("sub_types"),
properties=[Property(**p) for p in metadata_cls["properties"]],
)
)

return classes


def split_paths_by_metadata(
path, dir: str = ".v7", filename: str = "metadata.json"
) -> tuple[Path, Optional[list[PropertyClass]]]:
"""
Splits the given path into two: the path to the metadata file and the path to the properties

Parameters
----------
path : Path
The path to the export directory.

Returns
-------
tuple[Path, Optional[list[PropertyClass]]]
A tuple containing the path to the metadata file and the list of property classes.
"""
if not is_properties_enabled(path, dir, filename):
return path, None

metadata_path = path / dir / filename
metadata = parse_metadata(metadata_path)
property_classes = parse_property_classes(metadata)

return metadata_path, property_classes


@dataclass
class AnnotationFile:
"""
Expand Down
58 changes: 57 additions & 1 deletion darwin/path_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from pathlib import PurePosixPath
from __future__ import annotations

import json
from pathlib import Path, PurePosixPath
from typing import Optional, Tuple


Expand Down Expand Up @@ -41,3 +44,56 @@ def deconstruct_full_path(filename: str) -> Tuple[str, str]:
"""
posix_path = PurePosixPath("/") / filename
return str(posix_path.parent), posix_path.name


def parse_metadata(path: Path) -> dict:
"""
Returns the parsed metadata file.

Parameters
----------
path : Path
The path to the metadata file.

Returns
-------
dict
The parsed metadata file.
"""
with open(path) as f:
metadata = json.load(f)

return metadata


def is_properties_enabled(
export_dir_path: Path,
dir: str = ".v7",
filename: str = "metadata.json",
annotations_dir: str = "annotations",
) -> bool:
"""
Returns whether the given export directory has properties enabled.

Parameters
----------
export_dir_path : Path
The path to the export directory.

Returns
-------
bool
Whether the given export directory has properties enabled.
"""
path = export_dir_path / dir
if not path.exists():
annotations_path = export_dir_path / annotations_dir
for annotation_path in annotations_path.rglob("*"):
with open(annotation_path) as f:
if '"properties"' in f.read():
return True
return False

metadata_path = path / filename
metadata_classes = parse_metadata(metadata_path).get("classes", [])
return any(_cls.get("properties") for _cls in metadata_classes)
Loading