Skip to content

Commit abb435a

Browse files
authored
chore: Mark the classification as read only. Set at creation time (#1013)
1 parent 1e785a2 commit abb435a

File tree

4 files changed

+34
-6
lines changed

4 files changed

+34
-6
lines changed

encord/objects/classification.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class Classification(OntologyElement):
5555
in the ontology tree corresponding to this classification.
5656
attributes (List[Attribute]): List of `Attribute` instances that define
5757
the semantic meaning or properties associated with the classification.
58-
level (OntologyClassificationLevel | None): The hierarchical level of
58+
_level (OntologyClassificationLevel | None): The hierarchical level of
5959
this classification (for example: `GLOBAL`). Optional: defaults to None.
6060
6161
Example:
@@ -72,7 +72,7 @@ class Classification(OntologyElement):
7272
uid: int
7373
feature_node_hash: str
7474
attributes: List[Attribute]
75-
level: OntologyClassificationLevel | None = None
75+
_level: OntologyClassificationLevel | None = None
7676

7777
@property
7878
def title(self) -> str:
@@ -83,6 +83,15 @@ def title(self) -> str:
8383
"""
8484
return self.attributes[0].name
8585

86+
@property
87+
def level(self) -> OntologyClassificationLevel | None:
88+
"""Get the level of the classification.
89+
90+
Returns:
91+
OntologyClassificationLevel | None: The level of the classification.
92+
"""
93+
return self._level
94+
8695
@property
8796
def children(self) -> Sequence[OntologyElement]:
8897
"""Returns the attributes of the classification as children elements.
@@ -126,7 +135,7 @@ def from_dict(cls, d: dict) -> Classification:
126135
uid=int(d["id"]),
127136
feature_node_hash=d["featureNodeHash"],
128137
attributes=attributes_ret,
129-
level=level,
138+
_level=level,
130139
)
131140

132141
def to_dict(self) -> Dict[str, Any]:

encord/objects/ontology_structure.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from uuid import uuid4
1717

1818
from encord.exceptions import OntologyError
19-
from encord.objects.classification import Classification
19+
from encord.objects.classification import Classification, OntologyClassificationLevel
2020
from encord.objects.common import Shape
2121
from encord.objects.constants import AVAILABLE_COLORS
2222
from encord.objects.ontology_element import (
@@ -230,12 +230,14 @@ def add_classification(
230230
self,
231231
uid: Optional[int] = None,
232232
feature_node_hash: Optional[str] = None,
233+
level: Optional[OntologyClassificationLevel] = None,
233234
) -> Classification:
234235
"""Adds a classification definition to the ontology.
235236
236237
Args:
237238
uid: Integer identifier of the object. Normally auto-generated; omit this unless the aim is to create an exact clone of existing structure.
238239
feature_node_hash: Global identifier of the object. Normally auto-generated; omit this unless the aim is to create an exact clone of existing structure.
240+
level: The level at which this classification applies. See :py:class:`encord.objects.classification.OntologyClassificationLevel` enum for possible values.
239241
240242
Returns:
241243
Classification: The created classification node. Note that classification attribute should be further specified by calling its `add_attribute()` method.
@@ -258,7 +260,7 @@ def add_classification(
258260
if any([cls.feature_node_hash == feature_node_hash for cls in self.classifications]):
259261
raise ValueError(f"Duplicate feature_node_hash '{feature_node_hash}'")
260262

261-
cls = Classification(uid=uid, feature_node_hash=feature_node_hash, attributes=list())
263+
cls = Classification(uid=uid, feature_node_hash=feature_node_hash, attributes=list(), _level=level)
262264
self.classifications.append(cls)
263265
return cls
264266

tests/objects/classifications/test_global_classification.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import dataclasses
12
from dataclasses import asdict
23
from unittest.mock import Mock
34

@@ -20,6 +21,22 @@ def test_global_ontology_serde() -> None:
2021
assert Classification.from_dict(global_classification_dict) == GLOBAL_CLASSIFICATION
2122

2223

24+
def test_ontology_level_serde() -> None:
25+
classification_without_level = dataclasses.replace(GLOBAL_CLASSIFICATION, _level=None)
26+
27+
classification_dict_without_level_key = GLOBAL_CLASSIFICATION.to_dict()
28+
del classification_dict_without_level_key["level"]
29+
assert Classification.from_dict(classification_dict_without_level_key) == classification_without_level
30+
31+
classification_dict_with_level_none = GLOBAL_CLASSIFICATION.to_dict()
32+
classification_dict_with_level_none["level"] = None
33+
assert Classification.from_dict(classification_dict_with_level_none) == classification_without_level
34+
35+
classification_dict_with_invalid_level = GLOBAL_CLASSIFICATION.to_dict()
36+
classification_dict_with_invalid_level["level"] = "not-a-real-level"
37+
assert Classification.from_dict(classification_dict_with_invalid_level) == classification_without_level
38+
39+
2340
def test_global_classification_image_group(all_types_ontology) -> None:
2441
label_row_metadata_dict = asdict(FAKE_LABEL_ROW_METADATA)
2542
label_row_metadata_dict["frames_per_second"] = None # not a thing in image groups

tests/objects/data/all_types_ontology_structure.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
GLOBAL_CLASSIFICATION = Classification(
1515
uid=4,
1616
feature_node_hash="3DuQbFx4",
17-
level=OntologyClassificationLevel.GLOBAL,
17+
_level=OntologyClassificationLevel.GLOBAL,
1818
attributes=[
1919
ChecklistAttribute(
2020
uid=[4, 1],

0 commit comments

Comments
 (0)