Skip to content

[Exp] Warp-first experimental envs implements lazy export + cfg implementation split (#5916)#5943

Merged
hujc7 merged 1 commit into
isaac-sim:release/3.0.0-beta2from
hujc7:jichuanh/cherrypick-5916-release-3.0.0-beta2
Jun 4, 2026
Merged

[Exp] Warp-first experimental envs implements lazy export + cfg implementation split (#5916)#5943
hujc7 merged 1 commit into
isaac-sim:release/3.0.0-beta2from
hujc7:jichuanh/cherrypick-5916-release-3.0.0-beta2

Conversation

@hujc7
Copy link
Copy Markdown
Collaborator

@hujc7 hujc7 commented Jun 3, 2026

Summary

Cherry-pick of #5916 (squash commit 429aff2) onto release/3.0.0-beta2. Fixes NVBug 6121889 (Warp env startup crash with the kit visualizer).

  • Adds Warp-first experimental environments and MDP terms under isaaclab_experimental and isaaclab_tasks_experimental (direct + manager-based cartpole/humanoid/ant/reach/locomotion).
  • Adds lazy __init__.py + .pyi stubs so a clean checkout can resolve the experimental Warp env configs without crashing.
  • Drops a config-load-time pxr leak in the experimental SceneEntityCfg.

Conflict resolution

Three files conflicted, all due to divergence between develop and the release branch:

  1. isaaclab_tasks_experimental/.../direct/cartpole/__init__.py and .../manager_based/classic/cartpole/__init__.py — the develop versions reference the isaaclab_tasks.core package and the renamed agent configs (rl_games_direct_ppo_cfg.yaml, rl_games_manager_ppo_cfg.yaml, etc.) introduced by the core/contrib refactor, which is not on this release branch. Repointed to the release-branch agent package (isaaclab_tasks.direct.cartpole.agents / isaaclab_tasks.manager_based.classic.cartpole) and the release-branch agent filenames (rl_games_ppo_cfg.yaml, rsl_rl_ppo_cfg:CartpolePPORunnerCfg, skrl_ppo_cfg.yaml, sb3_ppo_cfg.yaml).
  2. isaaclab/envs/utils/camera_view.py — followed Warp-first experimental envs implements lazy export + cfg implementation split #5916: hoisted UsdGeom and FrameView from the local function scope to the module top. Used from pxr import UsdGeom (not Sdf, UsdGeom as on develop), since the release file does not contain develop's scenePartition block that uses Sdf. Result is identical to develop's camera_view.py apart from that release-absent block.

The forbidden-imports test modification landed at its release-branch path (test/test_env_cfg_no_forbidden_imports.py) via rename detection.

Validation (release branch + cherry-pick)

Original PR: #5916

@github-actions github-actions Bot added the isaac-lab Related to Isaac Lab team label Jun 3, 2026
Copy link
Copy Markdown

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Lazy Export + Cfg/Implementation Split (Cherry-pick of #5916)

This is a well-structured cherry-pick that addresses a real pain point: importing experimental Warp env configs would eagerly pull in pxr, omni, and other backend modules, crashing if SimulationApp had not yet launched. The fix is architecturally sound and follows patterns already established in the stable isaaclab package.


✅ What Works Well

  1. Lazy export pattern is consistent — Every __init__.pylazy_export() + .pyi stub pair follows the same structure. The .pyi stubs serve dual duty: IDE type resolution and runtime lazy-load manifests.

  2. Cfg/implementation split — Moving *Cfg dataclasses into dedicated *_cfg.py files while keeping the runtime env class in the original module is the correct approach. Config loading (e.g., gymnasium registry env_cfg_entry_point) no longer triggers heavy imports.

  3. TYPE_CHECKING guards — Moving Articulation, ContactSensor, InteractiveScene, etc. under if TYPE_CHECKING: in leaf MDP modules prevents runtime import chains that would pull in the simulator. This is clean and consistent across all affected files.

  4. isinstance(entity.cfg, ArticulationCfg) change in scene_entity_cfg.py — Avoids importing BaseArticulation (which itself imports backend code). Checking the config type is a lightweight proxy that achieves the same dispatch logic without the heavy import.

  5. Conflict resolution — The PR description clearly documents the three conflicts and their resolutions. The choices (keeping release-branch-side deferred imports for camera_view.py) are correct.


⚠️ Observations & Minor Concerns

# File Note
1 actions_cfg.py The class_type: ... | str = "{DIR}.joint_actions:JointPositionAction" pattern assumes the runtime config resolver handles {DIR} string interpolation. This is fine if lazy_export or the manager infrastructure already resolves these—just confirming this pattern is tested.
2 scene_entity_cfg.py The isinstance(entity.cfg, ArticulationCfg) check is semantically slightly different from isinstance(entity, BaseArticulation). If any non-articulation entity happened to use an ArticulationCfg (unlikely but possible with custom wrappers), it would incorrectly enter this branch. Low risk given the current codebase.
3 envs/mdp/__init__.pyi Uses from isaaclab.envs.mdp import * as a fallback for stable MDP terms. If the stable package adds a name that conflicts with an experimental override, the override wins (since it comes after). This is intentional per the comments, but worth a note for future maintainers.
4 schemas_actuators.py / terrains/utils.py / scene_data_provider.py Hoisting pxr / sim_utils imports to module top is the reverse of the typical deferred-import pattern. This works here because these modules are only imported after SimulationApp is already running (they are implementation modules, not config modules). Just ensure nothing transitively imports these at config-load time.

🧪 Test Coverage

  • The test_env_cfg_no_forbidden_imports.py extension to scan isaaclab_tasks_experimental is the right gate — it will catch any regression where a config import pulls in forbidden backend modules.
  • The test correctly imports isaaclab_tasks_experimental to trigger gymnasium registration before scanning.

Summary

No blocking issues. The lazy-export + cfg split pattern is well-executed and solves the eager-import crash reliably. The PR is ready to merge once CI completes.


🔄 Update (1b35411)

Reviewed incremental changes from 1496594f1b354112:

  • P1 Fixed: Agent config file names for Isaac-Cartpole-Direct-Warp-v0 now correctly reference stable_agents (rl_games_ppo_cfg.yaml, etc.) instead of non-existent renamed variants.
  • P1 Fixed: Manager-based cartpole (Isaac-Cartpole-Warp-v0) now imports agents from isaaclab_tasks.manager_based.classic.cartpole and uses agents.__name__ for correct path resolution.
  • P2 (scene_entity_cfg.py hasattr guard): Not addressed — acceptable as low-risk observation.

No new issues found in the incremental diff. LGTM. 👍

@hujc7 hujc7 force-pushed the jichuanh/cherrypick-5916-release-3.0.0-beta2 branch from 1496594 to 56aa42d Compare June 3, 2026 22:52
@hujc7 hujc7 requested a review from Toni-SM as a code owner June 3, 2026 22:52
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jun 3, 2026

Greptile Summary

This cherry-pick onto release/3.0.0-beta2 introduces lazy-loading for the Warp-first experimental packages so that env configs can be imported before SimulationApp launches, and splits the env config dataclasses into dedicated _cfg.py files. It also hoists module-level pxr/sim_utils imports out of function bodies in several isaaclab implementation files.

  • Lazy export + .pyi stubs: managers, envs, envs.mdp, and envs.mdp.actions packages now use lazy_export() with companion .pyi stubs; MDP term files move runtime types under TYPE_CHECKING guards, safe because the files carry from __future__ import annotations.
  • Config/env split: CartpoleWarpEnvCfg, AntWarpEnvCfg, and HumanoidWarpEnvCfg are extracted into separate _cfg.py files; class_type adopts the existing {DIR}.module:Class lazy-string pattern.
  • Agent config file renames in cartpole registrations: Both cartpole gym registrations reference agent config file names (e.g. rl_games_direct_ppo_cfg.yaml, rl_games_manager_ppo_cfg.yaml) that do not exist on disk; these will raise FileNotFoundError or ImportError whenever any RL training framework tries to resolve the agent config.

Confidence Score: 3/5

The lazy-export infrastructure and cfg/env split are correct, but both cartpole gym registrations point to agent config files that do not exist on disk; any RL training run against those environments will immediately fail.

The core architectural changes are sound and consistent with established patterns in the codebase. The pxr hoisting in implementation files is safe because their parent packages use lazy_export. The config/env split for ant and humanoid looks correct. The two cartpole init.py files, however, rename agent config references to file names that do not exist in isaaclab_tasks; every RL framework that tries to load an agent config for these tasks will fail at runtime.

source/isaaclab_tasks_experimental/isaaclab_tasks_experimental/direct/cartpole/init.py and source/isaaclab_tasks_experimental/isaaclab_tasks_experimental/manager_based/classic/cartpole/init.py both reference agent config files that do not exist; the rest of the changed files look safe.

Important Files Changed

Filename Overview
source/isaaclab_tasks_experimental/isaaclab_tasks_experimental/direct/cartpole/init.py Renames agent config references to non-existent file names; env_cfg_entry_point fix is correct but rl_games/rsl_rl/skrl/sb3 cfg names don't match files on disk
source/isaaclab_tasks_experimental/isaaclab_tasks_experimental/manager_based/classic/cartpole/init.py Same broken agent config renames as the direct cartpole; all four RL-framework cfg references point to files that don't exist
source/isaaclab_experimental/isaaclab_experimental/managers/scene_entity_cfg.py Replaces BaseArticulation instance check with ArticulationCfg cfg check (more robust for Warp backends); moves InteractiveScene to TYPE_CHECKING to drop pxr dependency at import time
source/isaaclab_experimental/isaaclab_experimental/envs/mdp/actions/actions_cfg.py Switches class_type to the established {DIR} lazy-string pattern and moves JointPositionAction/JointEffortAction imports under TYPE_CHECKING
source/isaaclab/isaaclab/terrains/utils.py Hoists pxr/sim_utils imports to module top; safe because isaaclab.terrains uses lazy_export
source/isaaclab/isaaclab/sim/schemas/schemas_actuators.py Hoists pxr/ImplicitActuator/resolve_matching_names imports to module top; safe because isaaclab.sim.schemas uses lazy_export
source/isaaclab/isaaclab/scene_data/scene_data_provider.py Hoists pxr/sim_utils imports to module top and fixes alias from isaaclab_sim to sim_utils
source/isaaclab_experimental/isaaclab_experimental/managers/init.py Replaced eager star-import block with lazy_export(); .pyi stub enumerates the full public API
source/isaaclab_experimental/isaaclab_experimental/envs/init.py Replaced eager imports of warp env classes with lazy_export(); stub correctly re-exports all four env types
source/isaaclab_tasks/test/test_env_cfg_no_forbidden_imports.py Correctly extends forbidden-imports test to cover isaaclab_tasks_experimental in both outer process and inner batch script

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["import isaaclab_tasks_experimental"] --> B["gym.register(...)"]
    B --> C["env_cfg_entry_point\n*_cfg.py - pure data, no pxr"]
    B --> D["entry_point\n*_env.py - runtime, pxr OK"]
    B --> E["rl_games/rsl_rl/skrl/sb3 cfg\nrenamed files do not exist"]
    C --> F["*_cfg.py imports\nDirectRLEnvCfg, ArticulationCfg\nlazy, no pxr at load time"]
    G["from isaaclab_experimental.managers import SceneEntityCfg"]
    G --> H["managers/__init__.py\nlazy_export()"]
    H --> I[".pyi stub\nresolves imports lazily"]
    I --> J["scene_entity_cfg.py\nimport ArticulationCfg\nnot BaseArticulation"]
    K["from isaaclab_experimental.envs import mdp"]
    K --> L["envs/__init__.py\nlazy_export()"]
    L --> M["envs/mdp/__init__.py\nlazy_export()"]
    M --> N["actions/__init__.py\nlazy_export()"]
    N --> O["actions_cfg.py\nclass_type = {DIR}.joint_actions:..."]
Loading

Reviews (1): Last reviewed commit: "Warp-first experimental envs implements ..." | Re-trigger Greptile

Comment on lines 24 to 28
"rl_games_cfg_entry_point": f"{stable_agents}:rl_games_direct_ppo_cfg.yaml",
"rsl_rl_cfg_entry_point": f"{stable_agents}.rsl_rl_direct_ppo_cfg:CartpolePPORunnerCfg",
"skrl_cfg_entry_point": f"{stable_agents}:skrl_direct_ppo_cfg.yaml",
"sb3_cfg_entry_point": f"{stable_agents}:sb3_direct_ppo_cfg.yaml",
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Broken agent config file names

The renamed references (rl_games_direct_ppo_cfg.yaml, rsl_rl_direct_ppo_cfg, skrl_direct_ppo_cfg.yaml, sb3_direct_ppo_cfg.yaml) do not exist in isaaclab_tasks.direct.cartpole.agents — the actual files are still rl_games_ppo_cfg.yaml, rsl_rl_ppo_cfg.py, skrl_ppo_cfg.yaml, and sb3_ppo_cfg.yaml. Any attempt to load RL training configs for Isaac-Cartpole-Direct-Warp-v0 (via load_cfg_from_registry or a training script) will fail with a FileNotFoundError or ImportError. The same pattern is broken in manager_based/classic/cartpole/__init__.py (see rl_games_manager_ppo_cfg.yaml etc.).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. This release branch predates the core/contrib task refactor, so the agent configs in isaaclab_tasks.direct.cartpole.agents are still named rl_games_ppo_cfg.yaml / rsl_rl_ppo_cfg / skrl_ppo_cfg.yaml / sb3_ppo_cfg.yaml (the _direct_ infix only exists on develop). The cherry-pick now references the release-branch names. Verified by training Isaac-Cartpole-Direct-Warp-v0 with rl_games: the log loads .../direct/cartpole/agents/rl_games_ppo_cfg.yaml and completes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great context — thanks for the training verification too. The release-branch naming makes sense given the refactor timeline. ✅

Comment on lines +25 to +28
"rl_games_cfg_entry_point": f"{agents.__name__}:rl_games_manager_ppo_cfg.yaml",
"rsl_rl_cfg_entry_point": f"{agents.__name__}.rsl_rl_manager_ppo_cfg:CartpolePPORunnerCfg",
"skrl_cfg_entry_point": f"{agents.__name__}:skrl_manager_ppo_cfg.yaml",
"sb3_cfg_entry_point": f"{agents.__name__}:sb3_manager_ppo_cfg.yaml",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Broken agent config file names (manager-based)

The references to rl_games_manager_ppo_cfg.yaml, rsl_rl_manager_ppo_cfg:CartpolePPORunnerCfg, skrl_manager_ppo_cfg.yaml, and sb3_manager_ppo_cfg.yaml don't match any files in isaaclab_tasks.manager_based.classic.cartpole.agents — only rl_games_ppo_cfg.yaml, rsl_rl_ppo_cfg.py, skrl_ppo_cfg.yaml, and sb3_ppo_cfg.yaml exist there. Attempting to train on Isaac-Cartpole-Warp-v0 with any RL framework will immediately fail to resolve the agent config.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, same root cause as the direct variant — repointed rl_games_manager_ppo_cfg.yaml / rsl_rl_manager_ppo_cfg / skrl_manager_ppo_cfg.yaml / sb3_manager_ppo_cfg.yaml back to the release-branch names (rl_games_ppo_cfg.yaml, rsl_rl_ppo_cfg:CartpolePPORunnerCfg, etc.) in isaaclab_tasks.manager_based.classic.cartpole.agents. All referenced files and the CartpolePPORunnerCfg class exist on this branch.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Consistent fix across both variants.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified — the config entry points now correctly reference the existing files in isaaclab_tasks.manager_based.classic.cartpole.agents. Thanks for the quick fix! ✅


# -- Warp joint mask / ids for articulations
if isinstance(entity, BaseArticulation):
if isinstance(entity.cfg, ArticulationCfg):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Semantic shift from entity-type to cfg-type check

The guard changed from isinstance(entity, BaseArticulation) to isinstance(entity.cfg, ArticulationCfg). For Warp-first backends where the articulation object may not inherit from BaseArticulation, checking the config class is likely more correct. However, if any future scene entity uses an ArticulationCfg but does not expose entity.num_joints / entity.joint_ids (e.g., a thin wrapper or proxy type), this block would hit an AttributeError. Consider adding a hasattr(entity, "num_joints") guard or a comment explaining the assumption that ArticulationCfg always implies the full articulation interface.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is intentional and carried over unchanged from the merged PR #5916. The guard was switched to isinstance(entity.cfg, ArticulationCfg) specifically so the experimental SceneEntityCfg no longer imports BaseArticulation at module top, which transitively pulled scene_data_provider -> pxr during config parsing — the leak this PR exists to fix. For Warp-first backends the articulation object may not subclass BaseArticulation, so the cfg-type check is the deliberate replacement. Validated by test_env_cfg_no_forbidden_imports.py (224 passed, incl. 27 Warp tasks).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense — cfg-type check avoids the transitive pxr import while remaining correct for Warp backends. Good that the import test validates this. ✅

…ion split (isaac-sim#5916)

- Adds Warp-first experimental environments and MDP terms under
`isaaclab_experimental` and `isaaclab_tasks_experimental` (direct +
manager-based cartpole/humanoid/ant/reach/locomotion), with Warp-kernel
implementations of actions, observations, rewards, terminations, and
events.
- Adds lazy `__init__.py` + `.pyi` stubs (with explicit `__all__`)
across the new/updated packages.

- [ ] `./isaaclab.sh -p -m pytest
source/isaaclab_tasks_experimental/test`
- [ ] Train the experimental Warp cartpole/humanoid/ant configs on the
Newton backend and confirm parity with the stable envs.
- [ ] `./isaaclab.sh -p -m pytest
source/isaaclab_physx/test/assets/test_newton_actuators_physx.py
source/isaaclab_newton/test/assets/test_newton_actuators_newton.py`
- [ ] Verify `randomize_rigid_body_scale` raises on Newton and warns
(deprecated) on PhysX.
@hujc7 hujc7 force-pushed the jichuanh/cherrypick-5916-release-3.0.0-beta2 branch from 56aa42d to 1b35411 Compare June 3, 2026 22:57
@hujc7 hujc7 merged commit 842fb04 into isaac-sim:release/3.0.0-beta2 Jun 4, 2026
60 of 61 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants