Skip to content

Commit 2fe2915

Browse files
refactor: complete migration to structured ValidationErrorCode across all core checks
Signed-off-by: arounamounchili <patouossa.mounchili@gmail.com>
1 parent be87d6a commit 2fe2915

2 files changed

Lines changed: 21 additions & 0 deletions

File tree

core/src/linkforge_core/validation/checks.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ def run(self, robot: Robot, result: ValidationResult) -> None:
4646
result.add_error(
4747
title="No links",
4848
message="Robot must have at least one link",
49+
code=ValidationErrorCode.VALUE_EMPTY,
4950
suggestion="Add a link by marking an object as a robot link in the Link panel",
5051
)
5152

@@ -78,6 +79,7 @@ def _check_duplicates(names: list[str], kind: str, result: ValidationResult) ->
7879
f"{names.count(name)} {kind}s. Each {kind} must have a unique name"
7980
),
8081
affected_objects=[n for n in names if n == name],
82+
code=ValidationErrorCode.DUPLICATE_NAME,
8183
suggestion=f"Rename duplicate {kind}s to unique names (e.g., '{name}_1', '{name}_2')",
8284
)
8385
return # Report once per kind
@@ -100,6 +102,7 @@ def run(self, robot: Robot, result: ValidationResult) -> None:
100102
f"'{joint.parent}' which does not exist"
101103
),
102104
affected_objects=[joint.name],
105+
code=ValidationErrorCode.NOT_FOUND,
103106
suggestion=f"Create a link named '{joint.parent}' or update the joint's parent reference",
104107
)
105108

@@ -111,6 +114,7 @@ def run(self, robot: Robot, result: ValidationResult) -> None:
111114
f"'{joint.child}' which does not exist"
112115
),
113116
affected_objects=[joint.name],
117+
code=ValidationErrorCode.NOT_FOUND,
114118
suggestion=f"Create a link named '{joint.child}' or update the joint's child reference",
115119
)
116120

@@ -138,6 +142,7 @@ def _check_cycles(robot: Robot, result: ValidationResult) -> None:
138142
"Kinematic tree contains a cycle. "
139143
"Links must form a tree structure, not a loop."
140144
),
145+
code=ValidationErrorCode.HAS_CYCLE,
141146
suggestion="Review joint connections to ensure they form a tree (no loops)",
142147
)
143148
except RobotModelError as e:
@@ -148,6 +153,7 @@ def _check_cycles(robot: Robot, result: ValidationResult) -> None:
148153
result.add_error(
149154
title="Kinematic graph error",
150155
message=str(e),
156+
code=ValidationErrorCode.INVALID_VALUE,
151157
suggestion="Check joint and link consistency",
152158
)
153159

@@ -163,6 +169,7 @@ def _check_root(robot: Robot, result: ValidationResult) -> Link | None:
163169
"No root link found. A robot must have exactly one link "
164170
"that is not a child in any joint."
165171
),
172+
code=ValidationErrorCode.NO_ROOT,
166173
suggestion="Ensure exactly one link has no parent joint (the base/root link)",
167174
)
168175
return root
@@ -184,6 +191,7 @@ def _check_root(robot: Robot, result: ValidationResult) -> Link | None:
184191
result.add_error(
185192
title="Root link error",
186193
message=str(e),
194+
code=e.code if hasattr(e, "code") else ValidationErrorCode.INVALID_VALUE,
187195
suggestion="Check the joint connections in your robot tree",
188196
)
189197
else:
@@ -207,6 +215,7 @@ def _check_connectivity(robot: Robot, root: object, result: ValidationResult) ->
207215
title="Disconnected link",
208216
message=f"Link '{link.name}' is not connected to the kinematic tree",
209217
affected_objects=[link.name],
218+
code=ValidationErrorCode.DISCONNECTED,
210219
suggestion=f"Create a joint connecting '{link.name}' to another link in the tree",
211220
)
212221
elif count > 1:
@@ -216,6 +225,7 @@ def _check_connectivity(robot: Robot, root: object, result: ValidationResult) ->
216225
f"Link '{link.name}' has {count} parent joints (should have exactly 1)"
217226
),
218227
affected_objects=[link.name],
228+
code=ValidationErrorCode.MULTIPLE_ROOTS,
219229
suggestion="Remove extra joints. Each link can only have one parent",
220230
)
221231

@@ -231,6 +241,7 @@ def run(self, robot: Robot, result: ValidationResult) -> None:
231241
title="Very low mass",
232242
message=f"Link '{link.name}' has very low mass ({link.mass:.6f} kg).",
233243
affected_objects=[link.name],
244+
code=ValidationErrorCode.INVALID_VALUE,
234245
suggestion="Consider providing a more realistic mass to avoid simulation instability",
235246
)
236247

@@ -239,6 +250,7 @@ def run(self, robot: Robot, result: ValidationResult) -> None:
239250
title="Missing inertia",
240251
message=f"Link '{link.name}' has no inertia tensor defined",
241252
affected_objects=[link.name],
253+
code=ValidationErrorCode.NOT_FOUND,
242254
suggestion="Add an inertial element or use automatic inertia calculation",
243255
)
244256

@@ -254,6 +266,7 @@ def run(self, robot: Robot, result: ValidationResult) -> None:
254266
title="No visual geometry",
255267
message=f"Link '{link.name}' has no visual geometry",
256268
affected_objects=[link.name],
269+
code=ValidationErrorCode.NOT_FOUND,
257270
suggestion="Add visual geometry for better visualization in simulators",
258271
)
259272

@@ -262,6 +275,7 @@ def run(self, robot: Robot, result: ValidationResult) -> None:
262275
title="No collision geometry",
263276
message=f"Link '{link.name}' has no collision geometry",
264277
affected_objects=[link.name],
278+
code=ValidationErrorCode.NOT_FOUND,
265279
suggestion="Add collision geometry for physics simulation",
266280
)
267281

@@ -285,6 +299,7 @@ def run(self, robot: Robot, result: ValidationResult) -> None:
285299
"does not exist in the kinematic tree"
286300
),
287301
affected_objects=[rc_joint.name],
302+
code=ValidationErrorCode.NOT_FOUND,
288303
suggestion="Ensure joint name in control matches a robot joint",
289304
)
290305

@@ -310,6 +325,7 @@ def run(self, robot: Robot, result: ValidationResult) -> None:
310325
title="Invalid mimic target",
311326
message=(f"Joint '{joint.name}' mimics non-existent joint '{current}'"),
312327
affected_objects=[joint.name],
328+
code=ValidationErrorCode.NOT_FOUND,
313329
suggestion=(f"Ensure joint '{current}' exists or update mimic reference"),
314330
)
315331
break
@@ -320,6 +336,7 @@ def run(self, robot: Robot, result: ValidationResult) -> None:
320336
title="Circular mimic dependency",
321337
message=f"Circular mimic dependency detected: {chain}",
322338
affected_objects=list(visited),
339+
code=ValidationErrorCode.HAS_CYCLE,
323340
suggestion="Break the circular mimic chain by changing mimic targets",
324341
)
325342
break

core/src/linkforge_core/validation/result.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ def add_error(
102102
message: str,
103103
affected_objects: list[str] | None = None,
104104
suggestion: str | None = None,
105+
code: ValidationErrorCode | None = None,
105106
auto_fix: Callable[[], None] | None = None,
106107
) -> None:
107108
"""Add an error to the validation result."""
@@ -112,6 +113,7 @@ def add_error(
112113
message=message,
113114
affected_objects=affected_objects or [],
114115
suggestion=suggestion,
116+
code=code,
115117
auto_fix=auto_fix,
116118
)
117119
)
@@ -122,6 +124,7 @@ def add_warning(
122124
message: str,
123125
affected_objects: list[str] | None = None,
124126
suggestion: str | None = None,
127+
code: ValidationErrorCode | None = None,
125128
auto_fix: Callable[[], None] | None = None,
126129
) -> None:
127130
"""Add a warning to the validation result."""
@@ -132,6 +135,7 @@ def add_warning(
132135
message=message,
133136
affected_objects=affected_objects or [],
134137
suggestion=suggestion,
138+
code=code,
135139
auto_fix=auto_fix,
136140
)
137141
)

0 commit comments

Comments
 (0)