fix(whole-body): discover sim adapters in registry#2653
Conversation
registry.discover() only scanned dimos/hardware/whole_body, so the sim adapter sim_mujoco_g1 was never imported/registered and `dimos --simulation mujoco run unitree-g1-groot-wbc` raised "Unknown whole-body adapter: sim_mujoco_g1". Also scan dimos/simulation/adapters/whole_body (flat modules), which the registry docstring already documents. ImportError is handled gracefully so hardware-only installs are unaffected.
| def _discover_flat(self, pkg_path: str, dir_path: str) -> None: | ||
| for entry in sorted(os.listdir(dir_path)): | ||
| if not entry.endswith(".py") or entry.startswith(("_", ".")): | ||
| continue | ||
| try: | ||
| mod = importlib.import_module(f"{pkg_path}.{entry[:-3]}") | ||
| except ImportError as e: | ||
| logger.warning(f"Skipping whole-body adapter {entry}: {e}") | ||
| continue | ||
| if hasattr(mod, "register"): | ||
| mod.register(self) |
There was a problem hiding this comment.
The per-module
except ImportError in _discover_flat will not catch Exception subclasses raised by a broken mod.register(self) call. If any sim adapter's register() raises (e.g., a constructor call with a bad default), the exception propagates out of _discover_flat, out of discover(), and ultimately fails the module-level import of registry.py — crashing the whole application. Consider a guarded call here, consistent with the "graceful skip" intent of the rest of the method.
| def _discover_flat(self, pkg_path: str, dir_path: str) -> None: | |
| for entry in sorted(os.listdir(dir_path)): | |
| if not entry.endswith(".py") or entry.startswith(("_", ".")): | |
| continue | |
| try: | |
| mod = importlib.import_module(f"{pkg_path}.{entry[:-3]}") | |
| except ImportError as e: | |
| logger.warning(f"Skipping whole-body adapter {entry}: {e}") | |
| continue | |
| if hasattr(mod, "register"): | |
| mod.register(self) | |
| if hasattr(mod, "register"): | |
| try: | |
| mod.register(self) | |
| except Exception as e: # noqa: BLE001 | |
| logger.warning(f"Skipping whole-body adapter {entry} (register() failed): {e}") |
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## main #2653 +/- ##
=======================================
Coverage 71.10% 71.10%
=======================================
Files 897 897
Lines 80290 80290
Branches 7183 7183
=======================================
+ Hits 57088 57090 +2
+ Misses 21319 21318 -1
+ Partials 1883 1882 -1
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
|
Want your agent to iterate on Greptile's feedback? Try greploops. |
What
In
dimos/hardware/whole_body/registry.py, madediscover()also scan the sim adapter root (dimos/simulation/adapters/whole_body/) via a new_discover_flat()helper — so flat<name>.pyadapter modules get imported and registered. GracefulImportErrorskip so hardware-only installs are unaffected. (~20 lines,registry.pyonly.)Why
discover()only scanneddimos/hardware/whole_body/, so the sim adaptersim_mujoco_g1was never registered —dimos --simulation mujoco run unitree-g1-groot-wbccrashed withKeyError: Unknown whole-body adapter: sim_mujoco_g1. The registry's own docstring already says it should scan both roots, so this makes the code match the documented intent. (Same fix Pim intended in the closed part-3 PR #2225, isolated as a surgical change.)How tested
SimMujocoG1WholeBodyAdapter connected, GR00T policyarmed,TickLoop started at 50.0Hz, robot pose rendering in the viewer.transport_lcm/transport_rospath is untouched and ordered first).ruff check+ruff format --checkpass;mypyclean on the file.Contributor License Agreement