Skip to content

Commit c5f304a

Browse files
committed
[PTDT-4605] Add ability to specify relationship constraints
1 parent 9abd8d0 commit c5f304a

File tree

1 file changed

+53
-24
lines changed

1 file changed

+53
-24
lines changed

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

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,6 @@ class Tool:
7171
instructions = "Classification Example")
7272
tool.add_classification(classification)
7373
74-
relationship_tool = Tool(
75-
tool = Tool.Type.RELATIONSHIP,
76-
name = "Relationship Tool Example",
77-
constraints = [
78-
("source_tool_feature_schema_id_1", "target_tool_feature_schema_id_1"),
79-
("source_tool_feature_schema_id_2", "target_tool_feature_schema_id_2")
80-
]
81-
)
82-
8374
Attributes:
8475
tool: (Tool.Type)
8576
name: (str)
@@ -89,7 +80,6 @@ class Tool:
8980
schema_id: (str)
9081
feature_schema_id: (str)
9182
attributes: (list)
92-
constraints: (list of [str, str]) (only available for RELATIONSHIP tool type)
9383
"""
9484

9585
class Type(Enum):
@@ -113,28 +103,21 @@ class Type(Enum):
113103
schema_id: Optional[str] = None
114104
feature_schema_id: Optional[str] = None
115105
attributes: Optional[FeatureSchemaAttributes] = None
116-
constraints: Optional[Tuple[str, str]] = None
117106

118107
def __post_init__(self):
119-
if self.constraints is not None and self.tool != Tool.Type.RELATIONSHIP:
120-
warnings.warn(
121-
"The constraints attribute is only available for Relationship tool. The provided constraints will be ignored."
122-
)
123-
self.constraints = None
124108
if self.attributes is not None:
125109
warnings.warn(
126110
"The attributes for Tools are in beta. The attribute name and signature may change in the future."
127111
)
128112

129113
@classmethod
130114
def from_dict(cls, dictionary: Dict[str, Any]) -> Dict[str, Any]:
131-
tool = Tool.Type(dictionary["tool"])
132115
return cls(
133116
name=dictionary["name"],
134117
schema_id=dictionary.get("schemaNodeId", None),
135118
feature_schema_id=dictionary.get("featureSchemaId", None),
136119
required=dictionary.get("required", False),
137-
tool=tool,
120+
tool=Tool.Type(dictionary["tool"]),
138121
classifications=[
139122
Classification.from_dict(c)
140123
for c in dictionary["classifications"]
@@ -146,9 +129,6 @@ def from_dict(cls, dictionary: Dict[str, Any]) -> Dict[str, Any]:
146129
]
147130
if dictionary.get("attributes")
148131
else None,
149-
constraints=dictionary.get("constraints", None)
150-
if tool == Tool.Type.RELATIONSHIP
151-
else None,
152132
)
153133

154134
def asdict(self) -> Dict[str, Any]:
@@ -165,9 +145,6 @@ def asdict(self) -> Dict[str, Any]:
165145
"attributes": [a.asdict() for a in self.attributes]
166146
if self.attributes is not None
167147
else None,
168-
"constraints": self.constraints
169-
if self.constraints is not None
170-
else None,
171148
}
172149

173150
def add_classification(self, classification: Classification) -> None:
@@ -178,6 +155,56 @@ def add_classification(self, classification: Classification) -> None:
178155
)
179156
self.classifications.append(classification)
180157

158+
@dataclass
159+
class RelationshipTool(Tool):
160+
"""
161+
A relationship tool to be added to a Project's ontology.
162+
163+
To instantiate, the "tool" and "name" parameters must
164+
be passed in.
165+
166+
The "classifications" parameter holds a list of Classification objects.
167+
This can be used to add nested classifications to a tool.
168+
169+
Example(s):
170+
tool = RelationshipTool(
171+
name = "Relationship Tool example")
172+
constraints = [
173+
("source_tool_feature_schema_id_1", "target_tool_feature_schema_id_1"),
174+
("source_tool_feature_schema_id_2", "target_tool_feature_schema_id_2")
175+
]
176+
)
177+
classification = Classification(
178+
class_type = Classification.Type.TEXT,
179+
instructions = "Classification Example")
180+
tool.add_classification(classification)
181+
182+
Attributes:
183+
tool: Tool.Type.RELATIONSHIP
184+
name: (str)
185+
required: (bool)
186+
color: (str)
187+
classifications: (list)
188+
schema_id: (str)
189+
feature_schema_id: (str)
190+
attributes: (list)
191+
constraints: (list of [str, str])
192+
"""
193+
194+
tool: Type = Tool.Type.RELATIONSHIP
195+
constraints: Optional[List[Tuple[str, str]]] = None
196+
197+
def __post_init__(self):
198+
super().__post_init__()
199+
if self.tool != Tool.Type.RELATIONSHIP:
200+
raise ValueError("RelationshipTool can only be used with Tool.Type.RELATIONSHIP")
201+
202+
def asdict(self) -> Dict[str, Any]:
203+
result = super().asdict()
204+
if self.constraints is not None:
205+
result["constraints"] = self.constraints
206+
return result
207+
181208

182209
"""
183210
The following 2 functions help to bridge the gap between the step reasoning all other tool ontologies.
@@ -188,6 +215,8 @@ def tool_cls_from_type(tool_type: str):
188215
tool_cls = map_tool_type_to_tool_cls(tool_type)
189216
if tool_cls is not None:
190217
return tool_cls
218+
if tool_type == Tool.Type.RELATIONSHIP:
219+
return RelationshipTool
191220
return Tool
192221

193222

0 commit comments

Comments
 (0)