Skip to content

Commit

Permalink
Import of annotation-level properties
Browse files Browse the repository at this point in the history
  • Loading branch information
JBWilkie committed Sep 12, 2024
1 parent 202ae8c commit f719794
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 11 deletions.
23 changes: 18 additions & 5 deletions darwin/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@
except ImportError:
NDArray = Any # type:ignore

from darwin.future.data_objects.properties import PropertyType, SelectedProperty
from darwin.future.data_objects.properties import (
PropertyType,
SelectedProperty,
PropertyGranularity,
)
from darwin.path_utils import construct_full_path, is_properties_enabled, parse_metadata

# Utility types
Expand Down Expand Up @@ -423,8 +427,7 @@ class Property:
description: Optional[str] = None

# Granularity of the property
# If none, we assume it is a section-level property
granularity: Optional[str] = None
granularity: PropertyGranularity = PropertyGranularity("section")


@dataclass
Expand Down Expand Up @@ -458,17 +461,27 @@ def parse_property_classes(metadata: dict[str, Any]) -> list[PropertyClass]:
assert (
"properties" in metadata_cls
), "Metadata class does not contain properties"
properties = [
Property(
name=p["name"],
type=p["type"],
required=p["required"],
property_values=p["property_values"],
description=p.get("description"),
granularity=PropertyGranularity(p.get("granularity", "section")),
)
for p in metadata_cls["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"]],
properties=properties,
)
)

return classes


Expand Down
25 changes: 21 additions & 4 deletions darwin/future/data_objects/properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import json
import os
from pathlib import Path
from typing import List, Literal, Optional, Tuple
from typing import List, Literal, Optional, Tuple, Union
from enum import Enum

from pydantic import field_validator

Expand All @@ -19,6 +20,12 @@
]


class PropertyGranularity(str, Enum):
section = "section"
annotation = "annotation"
item = "item"


class PropertyValue(DefaultDarwin):
"""
Describes a single option for a property
Expand Down Expand Up @@ -60,6 +67,8 @@ class FullProperty(DefaultDarwin):
type (str): Type of the property
required (bool): If the property is required
options (List[PropertyOption]): List of all options for the property
granularity (PropertyGranularity): Granularity of the property
"""

id: Optional[str] = None
Expand All @@ -73,6 +82,9 @@ class FullProperty(DefaultDarwin):
annotation_class_id: Optional[int] = None
property_values: Optional[List[PropertyValue]] = None
options: Optional[List[PropertyValue]] = None
granularity: PropertyGranularity = PropertyGranularity("section")

# model_config = ConfigDict(use_enum_values=True)

def to_create_endpoint(
self,
Expand All @@ -87,14 +99,16 @@ def to_create_endpoint(
"annotation_class_id": True,
"property_values": {"__all__": {"value", "color"}},
"description": True,
"granularity": True,
}
)

def to_update_endpoint(self) -> Tuple[str, dict]:
if self.id is None:
raise ValueError("id must be set")
updated_base = self.to_create_endpoint()
del updated_base["annotation_class_id"] # can't update this field
del updated_base["annotation_class_id"] # Can't update this field
del updated_base["granularity"] # Can't update this field
return self.id, updated_base


Expand All @@ -110,6 +124,7 @@ class MetaDataClass(DefaultDarwin):
description (Optional[str]): Description of the class
color (Optional[str]): Color of the class in the UI
sub_types (Optional[List[str]]): Sub types of the class
granularity:(PropertyGranularity): Granularity of the property
properties (List[FullProperty]): List of all properties for the class with all options
"""

Expand All @@ -118,6 +133,7 @@ class MetaDataClass(DefaultDarwin):
description: Optional[str] = None
color: Optional[str] = None
sub_types: Optional[List[str]] = None
granularity: PropertyGranularity = PropertyGranularity("section")
properties: List[FullProperty]

@classmethod
Expand All @@ -141,13 +157,14 @@ class SelectedProperty(DefaultDarwin):
Selected property for an annotation found inside a darwin annotation
Attributes:
frame_index (int): Frame index of the annotation
frame_index (int | str): Frame index of the annotation
int for section-level properties, and "global" for annotation-level properties
name (str): Name of the property
type (str | None): Type of the property (if it exists)
value (str): Value of the property
"""

frame_index: Optional[int] = None
frame_index: Optional[Union[int, str]] = None
name: str
type: Optional[str] = None
value: Optional[str] = None
7 changes: 6 additions & 1 deletion darwin/future/tests/core/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
from darwin.future.core.client import ClientCore, DarwinConfig
from darwin.future.data_objects.dataset import DatasetCore
from darwin.future.data_objects.item import ItemCore, ItemLayout, ItemSlot
from darwin.future.data_objects.properties import FullProperty, PropertyValue
from darwin.future.data_objects.properties import (
FullProperty,
PropertyValue,
PropertyGranularity,
)
from darwin.future.data_objects.team import TeamCore, TeamMemberCore
from darwin.future.data_objects.team_member_role import TeamMemberRole
from darwin.future.data_objects.workflow import WorkflowCore
Expand Down Expand Up @@ -38,6 +42,7 @@ def base_property_object(base_property_value: PropertyValue) -> FullProperty:
annotation_class_id=0,
property_values=[base_property_value],
options=[base_property_value],
granularity=PropertyGranularity("section"),
)


Expand Down
4 changes: 4 additions & 0 deletions darwin/importer/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
PropertyType,
PropertyValue,
SelectedProperty,
PropertyGranularity,
)
from darwin.item import DatasetItem
from darwin.path_utils import is_properties_enabled, parse_metadata
Expand Down Expand Up @@ -412,6 +413,7 @@ def _import_properties(
# if property value is None, update annotation_property_map with empty set
if a_prop.value is None:
assert t_prop.id is not None

annotation_property_map[annotation_id][str(a_prop.frame_index)][
t_prop.id
] = set()
Expand Down Expand Up @@ -516,6 +518,7 @@ def _import_properties(
slug=client.default_team,
annotation_class_id=int(annotation_class_id),
property_values=property_values,
granularity=PropertyGranularity(m_prop.granularity.value),
)
create_properties.append(full_property)
continue
Expand Down Expand Up @@ -649,6 +652,7 @@ def _import_properties(
slug=client.default_team,
annotation_class_id=t_prop.annotation_class_id,
property_values=extra_property_values,
granularity=PropertyGranularity(t_prop.granularity.value),
)
console.print(
f"Updating property {full_property.name} ({full_property.type}) with extra metadata values {extra_values}",
Expand Down
3 changes: 2 additions & 1 deletion darwin/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1149,9 +1149,10 @@ def _parse_properties(
) -> Optional[List[SelectedProperty]]:
selected_properties = []
for property in properties:
frame_index = property.get("frame_index")
selected_properties.append(
SelectedProperty(
frame_index=property.get("frame_index", None),
frame_index=frame_index if frame_index is not None else "global",
name=property.get("name", None),
value=property.get("value", None),
)
Expand Down
1 change: 1 addition & 0 deletions tests/darwin/client_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ def test_get_team_properties(self, darwin_client: Client) -> None:
"slug": "property-question",
"team_id": 128,
"type": "multi_select",
"granularity": "section",
},
]
},
Expand Down

0 comments on commit f719794

Please sign in to comment.