Skip to content

Commit

Permalink
Merge pull request #42 from flferretti/feature/auto_sdf_detection
Browse files Browse the repository at this point in the history
Automatically detect `sdf` extension from parsed string
  • Loading branch information
diegoferigo authored Sep 23, 2024
2 parents 0985ca9 + 4d27396 commit 0cc5039
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 30 deletions.
47 changes: 23 additions & 24 deletions src/rod/sdf/sdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def load(sdf: pathlib.Path | str, is_urdf: bool | None = None) -> Sdf:
Args:
sdf: The SDF resource to load.
is_urdf: Marks the SDF resource as an URDF to convert.
is_urdf: Force the SDF resource to be treated as URDF if the automatic detection fails.
Returns:
The parsed SDF file.
Expand All @@ -66,29 +66,28 @@ def load(sdf: pathlib.Path | str, is_urdf: bool | None = None) -> Sdf:
except ValueError:
MAX_PATH = os.pathconf("/", "PC_PATH_MAX")

# Get the SDF/URDF string from the input resource.
# If is_urdf is None and the input resource is a file path, we try to guess
# the is_urdf flag checking the file extension.

# Check first if it's a Path object
if isinstance(sdf, pathlib.Path):
sdf_string = sdf.read_text()
is_urdf = is_urdf if is_urdf is not None else sdf.suffix == ".urdf"

# Then, check if it's a string with a path
elif (
isinstance(sdf, str)
and len(sdf) <= MAX_PATH
and pathlib.Path(sdf).is_file()
):
sdf_string = pathlib.Path(sdf).read_text(encoding="utf-8")
is_urdf = (
is_urdf if is_urdf is not None else pathlib.Path(sdf).suffix == ".urdf"
)

# Finally, it must be a SDF/URDF string
else:
if is_urdf is not None:
sdf_string = sdf
else:
match sdf:
# Case 1: It's a Path object
case pathlib.Path():
sdf_string = sdf.read_text()
is_urdf = sdf.suffix == ".urdf"

# Case 2: It's a string with a path
case str() if len(sdf) <= MAX_PATH and pathlib.Path(sdf).is_file():
sdf_string = pathlib.Path(sdf).read_text(encoding="utf-8")
is_urdf = pathlib.Path(sdf).suffix == ".urdf"

# Case 3: It's an SDF/URDF string
case str():
sdf_string = sdf
is_urdf = "<robot>" in sdf_string

# Case 4: Raise an error for unsupported types
case _:
raise TypeError(f"Unsupported type for 'sdf': {type(sdf)}")

# Convert SDF to URDF if needed (it requires system executables)
if is_urdf:
Expand All @@ -101,7 +100,7 @@ def load(sdf: pathlib.Path | str, is_urdf: bool | None = None) -> Sdf:
try:
xml_dict = xmltodict.parse(xml_input=sdf_string)
except Exception as exc:
raise exc("Failed to parse 'sdf' argument") from exc
raise RuntimeError("Failed to parse 'sdf' argument") from exc

# Look for the top-level <sdf> element
try:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_urdf_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def test_urdf_exporter(robot: Robot) -> None:
original_urdf_path = ModelFactory.get_model_description(robot=robot)

# Load the URDF (it gets converted to SDF internally).
sdf = rod.Sdf.load(sdf=original_urdf_path, is_urdf=True)
sdf = rod.Sdf.load(sdf=original_urdf_path)

# Export the URDF from the in-memory SDF-based description.
exported_urdf_string = rod.urdf.exporter.UrdfExporter().to_urdf_string(sdf=sdf)
Expand Down
6 changes: 1 addition & 5 deletions tests/test_urdf_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ def test_urdf_parsing(robot: Robot) -> None:
with pytest.raises(RuntimeError):
_ = rod.Sdf.load(sdf=urdf_path.read_text(), is_urdf=False)

# Check that it fails if is_urdf=False and the resource is an urdf string
with pytest.raises(RuntimeError):
_ = rod.Sdf.load(sdf=urdf_path.read_text(), is_urdf=None)

# The following instead should succeed
_ = rod.Sdf.load(sdf=urdf_path, is_urdf=None)
_ = rod.Sdf.load(sdf=urdf_path, is_urdf=True)
Expand All @@ -47,7 +43,7 @@ def test_urdf_parsing(robot: Robot) -> None:
_ = rod.Sdf.load(sdf=urdf_path.read_text(), is_urdf=True)

# Load once again the urdf
rod_sdf = rod.Sdf.load(sdf=urdf_path, is_urdf=True)
rod_sdf = rod.Sdf.load(sdf=urdf_path)

# There should be only one model
assert len(rod_sdf.models()) == 1
Expand Down

0 comments on commit 0cc5039

Please sign in to comment.