Skip to content

Commit 5d27eeb

Browse files
docs: enhance SRDFParser documentation
Signed-off-by: arounamounchili <patouossa.mounchili@gmail.com>
1 parent f7ae5be commit 5d27eeb

1 file changed

Lines changed: 92 additions & 11 deletions

File tree

core/src/linkforge_core/parsers/srdf_parser.py

Lines changed: 92 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,31 @@
3535

3636
@runtime_checkable
3737
class ITemplateResolver(Protocol):
38-
"""Protocol for resolving templated XML strings (e.g., XACRO, Jinja)."""
38+
"""Protocol for resolving templated XML strings (e.g., XACRO, Jinja).
39+
40+
Implementing this protocol allows the SRDFParser to handle files that
41+
require preprocessing before they can be parsed as standard XML.
42+
"""
3943

4044
def resolve_string(self, xml_string: str) -> str:
41-
"""Resolve a templated string into plain XML."""
45+
"""Resolve a templated string into plain XML.
46+
47+
Args:
48+
xml_string: The raw string containing template directives.
49+
50+
Returns:
51+
A resolved XML string ready for parsing.
52+
"""
4253
...
4354

4455

4556
class SRDFParser(RobotXMLParser[SemanticRobotDescription]):
46-
"""Refined SRDF Parser with MoveIt support."""
57+
"""Semantic Robot Description Format (SRDF) Parser.
58+
59+
This parser converts SRDF XML content into a structured
60+
`SemanticRobotDescription` model. It supports MoveIt-specific tags
61+
such as planning groups, end effectors, and collision disabling.
62+
"""
4763

4864
def __init__(
4965
self,
@@ -71,7 +87,14 @@ def __init__(
7187
self.template_resolver = template_resolver
7288

7389
def _parse_planning_group(self, group_elem: ET.Element) -> PlanningGroup:
74-
"""Parse a planning group including its nested components."""
90+
"""Parse a <group> element into a PlanningGroup model.
91+
92+
Args:
93+
group_elem: The XML element for the group.
94+
95+
Returns:
96+
A populated PlanningGroup instance.
97+
"""
7598
name = group_elem.get("name", "unnamed_group")
7699
links: list[str] = []
77100
joints: list[str] = []
@@ -102,7 +125,14 @@ def _parse_planning_group(self, group_elem: ET.Element) -> PlanningGroup:
102125
)
103126

104127
def _parse_group_state(self, state_elem: ET.Element) -> GroupState:
105-
"""Parse a named group state."""
128+
"""Parse a <group_state> element into a GroupState model.
129+
130+
Args:
131+
state_elem: The XML element for the group state.
132+
133+
Returns:
134+
A populated GroupState instance.
135+
"""
106136
name = state_elem.get("name", "unnamed_state")
107137
group = state_elem.get("group", "")
108138
joint_values: dict[str, float] = {}
@@ -120,7 +150,19 @@ def parse_string(
120150
content: str,
121151
**kwargs: Any,
122152
) -> SemanticRobotDescription:
123-
"""Parse SRDF from string into a SemanticRobotDescription model."""
153+
"""Parse SRDF content from a string.
154+
155+
Args:
156+
content: The raw SRDF XML string.
157+
**kwargs: Additional options for future extensions.
158+
159+
Returns:
160+
A SemanticRobotDescription model representing the SRDF.
161+
162+
Raises:
163+
RobotParserUnexpectedError: If the XML is malformed.
164+
RobotParserXMLRootError: If the root tag is not <robot>.
165+
"""
124166
# Handle templating resolution
125167
if self.template_resolver is not None:
126168
content = self.template_resolver.resolve_string(content)
@@ -146,7 +188,14 @@ def parse_string(
146188
return semantic
147189

148190
def _parse_elements(self, root: ET.Element) -> SemanticRobotDescription:
149-
"""Internal helper to parse all SRDF elements from root."""
191+
"""Iterate through the XML root and parse all supported SRDF tags.
192+
193+
Args:
194+
root: The <robot> XML root element.
195+
196+
Returns:
197+
A SemanticRobotDescription containing all parsed elements.
198+
"""
150199
virtual_joints: list[VirtualJoint] = []
151200
groups: list[PlanningGroup] = []
152201
group_states: list[GroupState] = []
@@ -178,7 +227,14 @@ def _parse_elements(self, root: ET.Element) -> SemanticRobotDescription:
178227
)
179228

180229
def _parse_virtual_joint_elem(self, elem: ET.Element) -> VirtualJoint:
181-
"""Parse virtual_joint element."""
230+
"""Parse a <virtual_joint> element.
231+
232+
Args:
233+
elem: The XML element.
234+
235+
Returns:
236+
A VirtualJoint model.
237+
"""
182238
return VirtualJoint(
183239
name=elem.get("name", "unnamed_vj"),
184240
type=elem.get("type", "fixed"),
@@ -187,7 +243,14 @@ def _parse_virtual_joint_elem(self, elem: ET.Element) -> VirtualJoint:
187243
)
188244

189245
def _parse_end_effector_elem(self, elem: ET.Element) -> EndEffector:
190-
"""Parse end_effector element."""
246+
"""Parse an <end_effector> element.
247+
248+
Args:
249+
elem: The XML element.
250+
251+
Returns:
252+
An EndEffector model.
253+
"""
191254
return EndEffector(
192255
name=elem.get("name", "unnamed_ee"),
193256
group=elem.get("group", ""),
@@ -196,15 +259,33 @@ def _parse_end_effector_elem(self, elem: ET.Element) -> EndEffector:
196259
)
197260

198261
def _parse_disable_collisions_elem(self, elem: ET.Element) -> DisabledCollision:
199-
"""Parse disable_collisions element."""
262+
"""Parse a <disable_collisions> element.
263+
264+
Args:
265+
elem: The XML element.
266+
267+
Returns:
268+
A DisabledCollision model.
269+
"""
200270
return DisabledCollision(
201271
link1=elem.get("link1", ""),
202272
link2=elem.get("link2", ""),
203273
reason=elem.get("reason"),
204274
)
205275

206276
def parse(self, filepath: Path, **kwargs: Any) -> SemanticRobotDescription:
207-
"""Parse SRDF from file."""
277+
"""Load and parse an SRDF file from disk.
278+
279+
Args:
280+
filepath: Path to the .srdf file.
281+
**kwargs: Passed to parse_string.
282+
283+
Returns:
284+
A SemanticRobotDescription model.
285+
286+
Raises:
287+
RobotParserIOError: If the file is missing or exceeds max_file_size.
288+
"""
208289
if not filepath.exists():
209290
raise RobotParserIOError(filepath=filepath, reason="Missing file")
210291

0 commit comments

Comments
 (0)