From 09ea5d3d59c3ff6d82eff81816b8a63acf95de9c Mon Sep 17 00:00:00 2001 From: Peter Corke Date: Sat, 4 Jul 2026 15:40:28 +1000 Subject: [PATCH 1/2] fix(models): distinguish not-found vs renamed robot_descriptions models _load_rd_module raised the same generic ValueError whether a model name was a genuine typo or had simply moved to a different name under robot_descriptions. Now checks robot_descriptions' static DESCRIPTIONS registry (no network needed) to tell the two cases apart and names the correct current model name when one exists. Also renders "robot_descriptions" as a clickable terminal hyperlink (OSC 8, degrades to plain text on terminals that don't support it) rather than a bare word, since users calling roboticstoolbox have no reason to already know that package exists. Rehearsed: genuine-typo case, a real rename case (adam_lite -> adam_lite_mj_description, found via DESCRIPTIONS), and confirmed the successful-load path (UR5) is unaffected. Co-Authored-By: Claude Sonnet 5 --- src/roboticstoolbox/models/URDF/URDFRobot.py | 40 +++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/roboticstoolbox/models/URDF/URDFRobot.py b/src/roboticstoolbox/models/URDF/URDFRobot.py index 32389f232..3dd38b344 100644 --- a/src/roboticstoolbox/models/URDF/URDFRobot.py +++ b/src/roboticstoolbox/models/URDF/URDFRobot.py @@ -46,6 +46,34 @@ def _register_rd_packages(urdf_path: Path) -> None: break +_RD_URL = "https://github.com/robot-descriptions/robot_descriptions.py" + + +def _rd_link() -> str: + """Render "robot_descriptions" as a clickable terminal hyperlink (OSC 8). + + Terminals that don't understand OSC 8 just display the plain text, so + this degrades safely everywhere. + """ + return f"\033]8;;{_RD_URL}\033\\robot_descriptions\033]8;;\033\\" + + +def _find_rd_rename(robot_name: str, tried: list[str]) -> str | None: + """Look for another robot_descriptions entry for the same robot under a + name we didn't try, e.g. an alternate/newer naming convention. + + Returns the matching name, or None if robot_descriptions has nothing + registered for ``robot_name`` at all. + """ + import robot_descriptions + + prefix = f"{robot_name}_" + for key in robot_descriptions.DESCRIPTIONS: + if key not in tried and key.startswith(prefix): + return key + return None + + def _load_rd_module(robot_name: str): """Import the robot_descriptions submodule for ``robot_name``, trying the current name first and falling back to older/newer naming schemes. @@ -67,9 +95,17 @@ def _load_rd_module(robot_name: str): except ImportError as e: last_error = e continue + + renamed_to = _find_rd_rename(robot_name, candidates) + if renamed_to is not None: + raise ValueError( + f"Toolbox uses {_rd_link()} to provide URDF robot models. The " + f'requested model named "{robot_name}" is now named "{renamed_to}".' + ) from last_error + raise ValueError( - f"Robot model '{robot_name}' is not available. Check the spelling, or " - "that any optional dependency required for this model is installed." + f"Toolbox uses {_rd_link()} to provide URDF robot models. The " + f'requested model named "{robot_name}" can not be found.' ) from last_error From 7033340848e71b3025b48c0162178e46a1deeb80 Mon Sep 17 00:00:00 2001 From: Peter Corke Date: Sat, 4 Jul 2026 15:48:58 +1000 Subject: [PATCH 2/2] fix(models): reject MuJoCo-suffixed robot_descriptions names explicitly If a requested model name contains "_mj_" it's asking for a MuJoCo (MJCF) variant, which this URDF-loading path can't use. Raise a specific error rather than either silently attempting an MJCF clone or falling through to the generic not-found/renamed messages. Rehearsed: "test_mj_robot" and "aloha_mj_description" both raise the new message; genuine not-found, rename, and success paths unaffected. Co-Authored-By: Claude Sonnet 5 --- src/roboticstoolbox/models/URDF/URDFRobot.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/roboticstoolbox/models/URDF/URDFRobot.py b/src/roboticstoolbox/models/URDF/URDFRobot.py index 3dd38b344..565c05500 100644 --- a/src/roboticstoolbox/models/URDF/URDFRobot.py +++ b/src/roboticstoolbox/models/URDF/URDFRobot.py @@ -82,6 +82,13 @@ def _load_rd_module(robot_name: str): -> ``ur5_official_description``); trying alternates here means callers and model classes don't need to track that migration themselves. """ + if "_mj_" in robot_name: + raise ValueError( + f"Toolbox uses {_rd_link()} to provide URDF robot models. The " + f'requested model named "{robot_name}" is a MuJoCo model not a ' + "URDF model." + ) + candidates = [f"{robot_name}_description", f"{robot_name}_official_description"] last_error: ImportError | None = None for candidate in candidates: