Skip to content

Commit dd790a7

Browse files
committed
[PTDT-4605] Add ability to specify relationship constraints
1 parent 5c7857c commit dd790a7

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
@@ -70,15 +70,6 @@ class Tool:
7070
instructions = "Classification Example")
7171
tool.add_classification(classification)
7272
73-
relationship_tool = Tool(
74-
tool = Tool.Type.RELATIONSHIP,
75-
name = "Relationship Tool Example",
76-
constraints = [
77-
("source_tool_feature_schema_id_1", "target_tool_feature_schema_id_1"),
78-
("source_tool_feature_schema_id_2", "target_tool_feature_schema_id_2")
79-
]
80-
)
81-
8273
Attributes:
8374
tool: (Tool.Type)
8475
name: (str)
@@ -88,7 +79,6 @@ class Tool:
8879
schema_id: (str)
8980
feature_schema_id: (str)
9081
attributes: (list)
91-
constraints: (list of [str, str]) (only available for RELATIONSHIP tool type)
9282
"""
9383

9484
class Type(Enum):
@@ -112,28 +102,21 @@ class Type(Enum):
112102
schema_id: Optional[str] = None
113103
feature_schema_id: Optional[str] = None
114104
attributes: Optional[FeatureSchemaAttributes] = None
115-
constraints: Optional[Tuple[str, str]] = None
116105

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

128112
@classmethod
129113
def from_dict(cls, dictionary: Dict[str, Any]) -> Dict[str, Any]:
130-
tool = Tool.Type(dictionary["tool"])
131114
return cls(
132115
name=dictionary["name"],
133116
schema_id=dictionary.get("schemaNodeId", None),
134117
feature_schema_id=dictionary.get("featureSchemaId", None),
135118
required=dictionary.get("required", False),
136-
tool=tool,
119+
tool=Tool.Type(dictionary["tool"]),
137120
classifications=[
138121
Classification.from_dict(c)
139122
for c in dictionary["classifications"]
@@ -145,9 +128,6 @@ def from_dict(cls, dictionary: Dict[str, Any]) -> Dict[str, Any]:
145128
]
146129
if dictionary.get("attributes")
147130
else None,
148-
constraints=dictionary.get("constraints", None)
149-
if tool == Tool.Type.RELATIONSHIP
150-
else None,
151131
)
152132

153133
def asdict(self) -> Dict[str, Any]:
@@ -164,9 +144,6 @@ def asdict(self) -> Dict[str, Any]:
164144
"attributes": [a.asdict() for a in self.attributes]
165145
if self.attributes is not None
166146
else None,
167-
"constraints": self.constraints
168-
if self.constraints is not None
169-
else None,
170147
}
171148

172149
def add_classification(self, classification: Classification) -> None:
@@ -177,6 +154,56 @@ def add_classification(self, classification: Classification) -> None:
177154
)
178155
self.classifications.append(classification)
179156

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

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

192221

0 commit comments

Comments
 (0)