Skip to content

Commit d470be0

Browse files
committed
Fix NDVideoText dataRow and schema serialization edge cases
1 parent fcc1107 commit d470be0

2 files changed

Lines changed: 69 additions & 8 deletions

File tree

‎libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py‎

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,20 @@ class NDVideoText(BaseModel):
223223
{"name": "...", "answer": [{"value": "text", "frames": [{"start": 1, "end": 5}]}], ...}
224224
"""
225225

226-
name: str
226+
name: Optional[str] = None
227+
schema_id: Optional[Cuid] = Field(
228+
default=None, serialization_alias="schemaId"
229+
)
227230
answer: List[NDVideoTextAnswer]
228-
dataRow: Dict[str, str]
231+
data_row: DataRow = Field(serialization_alias="dataRow")
232+
233+
model_config = ConfigDict(populate_by_name=True)
234+
235+
@model_validator(mode="after")
236+
def must_set_one(self):
237+
if self.schema_id is None and self.name is None:
238+
raise ValueError("Schema id or name are not set. Set either one.")
239+
return self
229240

230241
@classmethod
231242
def from_video_text_group(
@@ -235,14 +246,10 @@ def from_video_text_group(
235246
data: "GenericDataRowData",
236247
) -> "NDVideoText":
237248
first = annotation_group[0]
238-
data_row = {}
239-
if data.global_key:
240-
data_row["globalKey"] = data.global_key
241-
elif data.uid:
242-
data_row["id"] = data.uid
243249
return cls(
244250
name=first.name,
245-
dataRow=data_row,
251+
schema_id=first.feature_schema_id,
252+
data_row=DataRow(id=data.uid, global_key=data.global_key),
246253
answer=[
247254
NDVideoTextAnswer(value=text_val, frames=ranges)
248255
for text_val, ranges in frame_ranges_by_text.items()

‎libs/labelbox/tests/data/serialization/ndjson/test_video.py‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
import pytest
23
from labelbox.data.annotation_types.classification.classification import (
34
Checklist,
45
ClassificationAnnotation,
@@ -722,6 +723,59 @@ def test_video_classification_text_single_text_across_frames():
722723
assert answer[0]["frames"] == [{"start": 9, "end": 15}]
723724

724725

726+
def test_video_classification_text_with_external_id_raises():
727+
label = Label(
728+
data=GenericDataRowData(external_id="sample-video-external-id"),
729+
annotations=[
730+
VideoClassificationAnnotation(
731+
name="free_text",
732+
frame=9,
733+
segment_index=0,
734+
value=Text(answer="sample text"),
735+
)
736+
],
737+
)
738+
739+
with pytest.raises(ValueError, match="Must set either id or global_key"):
740+
list(NDJsonConverter.serialize([label]))
741+
742+
743+
def test_video_classification_text_with_feature_schema_id_only():
744+
label = Label(
745+
data=GenericDataRowData(global_key="sample-video-schema-id-only"),
746+
annotations=[
747+
VideoClassificationAnnotation(
748+
feature_schema_id="ckrb1sfjx099a0y914hl319ie",
749+
frame=9,
750+
segment_index=0,
751+
value=Text(answer="sample text"),
752+
),
753+
VideoClassificationAnnotation(
754+
feature_schema_id="ckrb1sfjx099a0y914hl319ie",
755+
frame=15,
756+
segment_index=0,
757+
value=Text(answer="sample text"),
758+
),
759+
],
760+
)
761+
762+
serialized = list(NDJsonConverter.serialize([label]))
763+
free_text_rows = [
764+
r
765+
for r in serialized
766+
if r.get("schemaId") == "ckrb1sfjx099a0y914hl319ie"
767+
]
768+
assert len(free_text_rows) == 1
769+
770+
row = free_text_rows[0]
771+
assert row["schemaId"] == "ckrb1sfjx099a0y914hl319ie"
772+
assert "name" not in row
773+
assert row["dataRow"] == {"globalKey": "sample-video-schema-id-only"}
774+
assert row["answer"] == [
775+
{"value": "sample text", "frames": [{"start": 9, "end": 15}]}
776+
]
777+
778+
725779
def test_video_classification_nesting_bbox():
726780
bbox_annotation = [
727781
VideoObjectAnnotation(

0 commit comments

Comments
 (0)