Skip to content

Commit b185f89

Browse files
committed
Support project change of ontology
1 parent 33c480f commit b185f89

File tree

3 files changed

+88
-10
lines changed

3 files changed

+88
-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
@@ -659,14 +659,30 @@ def review_metrics(self, net_score) -> int:
659659
def connect_ontology(self, ontology) -> None:
660660
"""
661661
Connects the ontology to the project. If an editor is not setup, it will be connected as well.
662+
This method can be used to change the project's ontology.
662663
663664
Note: For live chat model evaluation projects, the editor setup is skipped because it is automatically setup when the project is created.
664665
665666
Args:
666667
ontology (Ontology): The ontology to attach to the project
668+
669+
Raises:
670+
ValueError: If ontology and project have different media types and ontology has a media type set
667671
"""
668-
if not self.is_empty_ontology():
669-
raise ValueError("Ontology already connected to project.")
672+
# Check media type compatibility
673+
if (
674+
self.media_type != ontology.media_type
675+
and not ontology.media_type == MediaType.Unknown
676+
):
677+
raise ValueError(
678+
"Ontology and project must share the same type, unless the ontology has no type."
679+
)
680+
681+
# Check if project has labels and warn user
682+
if self.get_label_count() > 0:
683+
warnings.warn(
684+
"Project has labels. The new ontology must contain all annotation types."
685+
)
670686

671687
if (
672688
self.labeling_frontend() is None

libs/labelbox/tests/integration/test_project_setup.py

Lines changed: 68 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,70 @@ 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)}",
103+
simple_ontology()
104+
)
105+
106+
# Test connecting ontology with unknown type
107+
project.connect_ontology(unknown_type_ontology)
108+
assert project.ontology().uid == unknown_type_ontology.uid

0 commit comments

Comments
 (0)