diff --git a/source/isaaclab/changelog.d/sylvesterkaczmarek-fix-backend-fallback.rst b/source/isaaclab/changelog.d/sylvesterkaczmarek-fix-backend-fallback.rst new file mode 100644 index 000000000000..5414a814009f --- /dev/null +++ b/source/isaaclab/changelog.d/sylvesterkaczmarek-fix-backend-fallback.rst @@ -0,0 +1,5 @@ +Fixed +^^^^^ + +* Fixed backend factory resolution raising before simulator initialization by using the team-confirmed ``newton`` + fallback when no ``SimulationContext`` exists. diff --git a/source/isaaclab/isaaclab/utils/backend_utils.py b/source/isaaclab/isaaclab/utils/backend_utils.py index ad350e3cadac..4f0614232bcc 100644 --- a/source/isaaclab/isaaclab/utils/backend_utils.py +++ b/source/isaaclab/isaaclab/utils/backend_utils.py @@ -73,13 +73,16 @@ def register(cls, name: str, sub_class) -> None: def _get_backend(cls, *args, **kwargs) -> str: """Return active backend name for this factory. - Falls back to ``"physx"`` for backward compatibility when no simulation - context is initialized yet. + Falls back to ``"newton"`` when no simulation context is initialized yet. """ # Import lazily to avoid import cycles at module load time. from isaaclab.sim.simulation_context import SimulationContext - manager_name = SimulationContext.instance().physics_manager.__name__.lower() + sim_context = SimulationContext.instance() + if sim_context is None: + return "newton" + + manager_name = sim_context.physics_manager.__name__.lower() if manager_name.startswith("newton"): return "newton" if manager_name.startswith("ovphysx"): diff --git a/source/isaaclab/isaaclab/visualizers/base_visualizer.py b/source/isaaclab/isaaclab/visualizers/base_visualizer.py index b76417a55abb..5dc259a3950d 100644 --- a/source/isaaclab/isaaclab/visualizers/base_visualizer.py +++ b/source/isaaclab/isaaclab/visualizers/base_visualizer.py @@ -153,8 +153,11 @@ def physics_backend(self) -> str | None: Backend name string, or ``None`` when no simulation context is active yet. """ try: + from isaaclab.sim.simulation_context import SimulationContext from isaaclab.utils.backend_utils import FactoryBase + if SimulationContext.instance() is None: + return None return FactoryBase._get_backend() except Exception: return None diff --git a/source/isaaclab/test/utils/test_backend_utils.py b/source/isaaclab/test/utils/test_backend_utils.py index 0b056ffa2f52..dae867231f8b 100644 --- a/source/isaaclab/test/utils/test_backend_utils.py +++ b/source/isaaclab/test/utils/test_backend_utils.py @@ -5,6 +5,7 @@ """Tests for backend module resolution.""" +from isaaclab.sim.simulation_context import SimulationContext from isaaclab.utils.backend_utils import FactoryBase @@ -24,3 +25,10 @@ def test_get_module_name_preserves_other_backend_conventions(monkeypatch): assert FactoryBase._get_package_name("newton") == "isaaclab_newton" assert FactoryBase._get_module_name("physx") == "isaaclab_physx.assets.articulation" assert FactoryBase._get_module_name("newton") == "isaaclab_newton.assets.articulation" + + +def test_factory_backend_falls_back_to_newton_without_simulation_context(monkeypatch): + """Backend resolution uses Newton before a simulation context exists.""" + monkeypatch.setattr(SimulationContext, "_instance", None) + + assert FactoryBase._get_backend() == "newton"