Skip to content

Commit 70757fd

Browse files
committed
Add source_ontology_name with validators
1 parent 156eda2 commit 70757fd

File tree

3 files changed

+28
-5
lines changed

3 files changed

+28
-5
lines changed

libs/labelbox/src/labelbox/data/annotation_types/relationship.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ class Type(Enum):
1414
UNIDIRECTIONAL = "unidirectional"
1515
BIDIRECTIONAL = "bidirectional"
1616

17-
source: Union[ObjectAnnotation, ClassificationAnnotation]
17+
source: Optional[Union[ObjectAnnotation, ClassificationAnnotation]] = None
18+
source_ontology_name: Optional[str] = None
1819
target: ObjectAnnotation
1920
type: Type = Type.UNIDIRECTIONAL
2021
readonly: Optional[bool] = None
@@ -27,6 +28,18 @@ def check_readonly(self):
2728
)
2829
return self
2930

31+
@model_validator(mode="after")
32+
def validate_source_fields(self):
33+
if self.source is None and self.source_ontology_name is None:
34+
raise ValueError("Either source or source_ontology_name must be provided")
35+
return self
36+
37+
@model_validator(mode="after")
38+
def validate_source_consistency(self):
39+
if self.source is not None and self.source_ontology_name is not None:
40+
raise ValueError("Only one of 'source' or 'source_ontology_name' may be provided")
41+
return self
42+
3043

3144
class RelationshipAnnotation(BaseAnnotation):
3245
value: Relationship

libs/labelbox/src/labelbox/data/serialization/ndjson/label.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ def _create_relationship_annotations(
209209
- For other target annotations: source must be ObjectAnnotation
210210
- Target:
211211
- Target must always be ObjectAnnotation
212+
ValueError: If relationship validation fails:
213+
- For PDF target annotations: either source or source_ontology_name must be provided
212214
"""
213215
for annotation in label.annotations:
214216
if isinstance(annotation, RelationshipAnnotation):
@@ -221,13 +223,17 @@ def _create_relationship_annotations(
221223
if isinstance(
222224
target.value, (DocumentRectangle, DocumentEntity)
223225
):
224-
if not isinstance(
226+
if source is not None and not isinstance(
225227
source, (ObjectAnnotation, ClassificationAnnotation)
226228
):
227229
raise TypeError(
228230
f"Unable to create relationship with invalid source. For PDF targets, "
229231
f"source must be ObjectAnnotation or ClassificationAnnotation. Got: {type(source)}"
230232
)
233+
if source is None and annotation.value.source_ontology_name is None:
234+
raise ValueError(
235+
"Unable to create relationship - either source or source_ontology_name must be provided"
236+
)
231237
elif not isinstance(source, ObjectAnnotation):
232238
raise TypeError(
233239
f"Unable to create relationship with non ObjectAnnotation source: {type(source)}"
@@ -239,7 +245,7 @@ def _create_relationship_annotations(
239245
f"Unable to create relationship with non ObjectAnnotation target: {type(target)}"
240246
)
241247

242-
if not source._uuid:
248+
if source is not None and not source._uuid:
243249
source._uuid = uuid1
244250
if not target._uuid:
245251
target._uuid = uuid2

libs/labelbox/src/labelbox/data/serialization/ndjson/relationship.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111

1212

1313
class _Relationship(BaseModel):
14-
source: str
14+
source: Optional[str] = None
1515
target: str
1616
type: str
1717
readonly: Optional[bool] = None
18+
sourceOntologyName: Optional[str] = None
1819

1920

2021
class NDRelationship(NDAnnotation):
@@ -25,11 +26,13 @@ def to_common(
2526
annotation: "NDRelationship",
2627
source: SUPPORTED_ANNOTATIONS,
2728
target: SUPPORTED_ANNOTATIONS,
29+
source_ontology_name: Optional[str] = None,
2830
) -> RelationshipAnnotation:
2931
return RelationshipAnnotation(
3032
name=annotation.name,
3133
value=Relationship(
3234
source=source,
35+
source_ontology_name=source_ontology_name,
3336
target=target,
3437
type=Relationship.Type(annotation.relationship.type),
3538
readonly=annotation.relationship.readonly,
@@ -50,8 +53,9 @@ def from_common(
5053
name=annotation.name,
5154
dataRow=DataRow(id=data.uid, global_key=data.global_key),
5255
relationship=_Relationship(
53-
source=str(relationship.source._uuid),
56+
source=str(relationship.source._uuid) if relationship.source else None,
5457
target=str(relationship.target._uuid),
58+
sourceOntologyName=relationship.source_ontology_name,
5559
type=relationship.type.value,
5660
readonly=relationship.readonly,
5761
),

0 commit comments

Comments
 (0)