Skip to content

Commit 1784891

Browse files
authored
Support project change of ontology (#1972)
2 parents 0bb159d + 5da21c2 commit 1784891

File tree

3 files changed

+87
-10
lines changed

3 files changed

+87
-10
lines changed

libs/labelbox/src/labelbox/schema/ontology.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
FeatureSchemaAttributes,
3131
)
3232
import warnings
33+
from labelbox.schema.project import MediaType
3334

3435

3536
class DeleteFeatureFromOntologyResult:
@@ -195,6 +196,7 @@ class Ontology(DbObject):
195196
normalized = Field.Json("normalized")
196197
object_schema_count = Field.Int("object_schema_count")
197198
classification_schema_count = Field.Int("classification_schema_count")
199+
media_type = Field.Enum(MediaType, "media_type", "mediaType")
198200

199201
projects = Relationship.ToMany("Project", True)
200202
created_by = Relationship.ToOne("User", False, "created_by")

libs/labelbox/src/labelbox/schema/project.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -666,14 +666,30 @@ def review_metrics(self, net_score) -> int:
666666
def connect_ontology(self, ontology) -> None:
667667
"""
668668
Connects the ontology to the project. If an editor is not setup, it will be connected as well.
669+
This method can be used to change the project's ontology.
669670
670671
Note: For live chat model evaluation projects, the editor setup is skipped because it is automatically setup when the project is created.
671672
672673
Args:
673674
ontology (Ontology): The ontology to attach to the project
675+
676+
Raises:
677+
ValueError: If ontology and project have different media types and ontology has a media type set
674678
"""
675-
if not self.is_empty_ontology():
676-
raise ValueError("Ontology already connected to project.")
679+
# Check media type compatibility
680+
if (
681+
self.media_type != ontology.media_type
682+
and not ontology.media_type == MediaType.Unknown
683+
):
684+
raise ValueError(
685+
"Ontology and project must share the same type, unless the ontology has no type."
686+
)
687+
688+
# Check if project has labels and warn user
689+
if self.get_label_count() > 0:
690+
warnings.warn(
691+
"Project has labels. The new ontology must contain all annotation types."
692+
)
677693

678694
if (
679695
self.labeling_frontend() is None

libs/labelbox/tests/integration/test_project_setup.py

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from datetime import datetime, timedelta, timezone
33

44
import pytest
5+
from labelbox.schema.media_type import MediaType
56

67

78
def simple_ontology():
@@ -38,11 +39,69 @@ def test_project_editor_setup(client, project, rand_gen):
3839
] == [ontology_name]
3940

4041

41-
def test_project_connect_ontology_cant_call_multiple_times(
42-
client, project, rand_gen
43-
):
44-
ontology_name = f"test_project_editor_setup_ontology_name-{rand_gen(str)}"
45-
ontology = client.create_ontology(ontology_name, simple_ontology())
46-
project.connect_ontology(ontology)
47-
with pytest.raises(ValueError):
48-
project.connect_ontology(ontology)
42+
def test_project_connect_ontology_multiple_times(client, project, rand_gen):
43+
"""Test that we can connect multiple ontologies in sequence."""
44+
# Connect first ontology
45+
ontology_name_1 = (
46+
f"test_project_connect_ontology_multiple_times_1-{rand_gen(str)}"
47+
)
48+
ontology_1 = client.create_ontology(ontology_name_1, simple_ontology())
49+
project.connect_ontology(ontology_1)
50+
assert project.ontology().name == ontology_name_1
51+
52+
# Connect second ontology
53+
ontology_name_2 = (
54+
f"test_project_connect_ontology_multiple_times_2-{rand_gen(str)}"
55+
)
56+
ontology_2 = client.create_ontology(ontology_name_2, simple_ontology())
57+
project.connect_ontology(ontology_2)
58+
assert project.ontology().name == ontology_name_2
59+
60+
61+
def test_project_connect_ontology_with_different_media_types(client, rand_gen):
62+
"""Test connecting ontologies with different media types to a project"""
63+
# Create a new project with Image media type
64+
project_name = f"test_project_media_type_{rand_gen(str)}"
65+
project = client.create_project(
66+
name=project_name, media_type=MediaType.Image
67+
)
68+
69+
try:
70+
# Create ontologies with different media types
71+
ontology_1 = client.create_ontology(
72+
f"test_ontology_1_{rand_gen(str)}",
73+
simple_ontology(),
74+
media_type=MediaType.Image, # Same media type as project
75+
)
76+
77+
ontology_2 = client.create_ontology(
78+
f"test_ontology_2_{rand_gen(str)}",
79+
simple_ontology(),
80+
media_type=MediaType.Video, # Different media type
81+
)
82+
83+
# Test connecting ontology with same media type
84+
project.connect_ontology(ontology_1)
85+
assert project.ontology().uid == ontology_1.uid
86+
87+
# Test connecting ontology with different media type
88+
with pytest.raises(ValueError) as exc_info:
89+
project.connect_ontology(ontology_2)
90+
assert "Ontology and project must share the same type" in str(
91+
exc_info.value
92+
)
93+
finally:
94+
# Clean up
95+
project.delete()
96+
97+
98+
def test_project_connect_ontology_with_unknown_type(client, project, rand_gen):
99+
"""Test connecting ontology with unknown media type to a project"""
100+
# Create ontology with unknown media type
101+
unknown_type_ontology = client.create_ontology(
102+
f"test_unknown_type_{rand_gen(str)}", simple_ontology()
103+
)
104+
105+
# Test connecting ontology with unknown type
106+
project.connect_ontology(unknown_type_ontology)
107+
assert project.ontology().uid == unknown_type_ontology.uid

0 commit comments

Comments
 (0)