[Fix] Make generated template projects import without Kit (no eager omni.ext)#5941
[Fix] Make generated template projects import without Kit (no eager omni.ext)#5941hujc7 wants to merge 4 commits into
Conversation
There was a problem hiding this comment.
Review Summary
Well-structured fix PR that addresses two distinct but related template-generator issues. The approach is sound and the test coverage is excellent.
Overall assessment: ✅ Approve-worthy — clean, minimal, well-tested fixes with thorough regression coverage.
Architecture & Design
Import Safety Fix (NVBug 6251247)
The fix correctly separates the UI extension loading path from the package import path:
__init__ext— Removes the eagerfrom .ui_extension_example import *, replacing it with a clear comment explaining why.extension.toml— Adds[[python.module]] name = "{{ name }}.ui_extension_example"so Kit's extension manager still discovers and loads theIExtsubclass at runtime.ui_extension_example.py— Adds the previously-missingimport omni.ui.
This is the correct architectural choice over lazy-importing: the UI extension is only consumed by Kit's module scanner, so it should be declared in extension.toml rather than imported at package level.
Error Handling Fix
The generator.py change to raise FileNotFoundError instead of silently continuing when a template is missing is the right call — projects now fail at generation time rather than at train time with a cryptic missing-config error.
Test Coverage Analysis
The test suite is comprehensive with excellent regression guards:
| Test | What it validates |
|---|---|
test_generated_env_modules_have_no_forbidden_top_level_imports |
AST-based check for pxr/omni/carb/isaacsim/usdrt at module scope |
test_each_requested_agent_cfg_file_is_generated |
No silently-skipped agent configs |
test_generated_python_is_syntactically_valid |
AST + compile check on all generated .py |
test_extension_toml_registers_ui_extension_as_separate_module |
Both halves of the import-safety fix |
test_generated_package_import_is_omni_and_pxr_free |
Subprocess import with omni/pxr blocker |
The subprocess-based import-safety test (test_generated_package_import_is_omni_and_pxr_free) is particularly well-designed — it uses a custom sys.meta_path finder to block omni/pxr imports and verifies the package still loads cleanly.
🔄 Follow-up Review — 374d842 (2026-06-04)
✅ Previous Concern Resolved
The stray debug comment in __init__ext (#rj: what's the consequence of this change?...) has been removed. This was the only blocking issue from my previous review.
No New Issues Introduced
The new commit cleanly addresses the feedback with no regressions:
- All existing tests should continue to pass
- New test coverage is thorough and well-designed
- Changelog fragment is properly formatted
LGTM. Ready for merge.
🔄 Follow-up Review — 911435d6 (2026-06-04)
New Changes (NVBug 6251258/6257159 — Manager-Based pxr Fix)
The new commits add a second fix addressing eager pxr imports in manager-based template projects:
mdp/__init__.py— Replaced wildcard re-exports withlazy_export()fromisaaclab.utils.module, deferring heavy imports until actually accessed.mdp/__init__.pyi— Added type stub for IDE support without runtime cost.mdp/rewards.py— Movedfrom isaaclab.assets import ArticulationintoTYPE_CHECKINGguard to break thepxrimport chain.- New test —
test_generated_manager_based_env_cfg_resolution_is_omni_and_pxr_freevalidates env config instantiation in a subprocess withomni/pxrblocked. - Changelog — Updated with the additional fix description.
Assessment
✅ No issues found. The lazy_export() + TYPE_CHECKING pattern is the correct approach for keeping template projects importable before Kit launches. Test coverage mirrors the existing import-safety test with the same subprocess-blocker strategy.
LGTM. Still approve-worthy.
🔄 Follow-up Review — e03366b5 (2026-06-04)
Trivial Cleanup
Single commit removes redundant source/isaaclab_rl/changelog.d/template-generator-tests.skip — an empty changelog fragment from the chained test branch that's no longer needed since the single jichuanh-fix-template-generator.rst fragment already covers the isaaclab_rl change.
✅ No issues. No code changes. LGTM.
| self.newton_sensor.utils.create_default_light(enable_shadows=self.cfg.enable_shadows) | ||
| ======= | ||
| if newton_model.shape_count > 0 and newton_model.bvh_shapes is None: | ||
| newton.geometry.build_bvh_shape(newton_model, newton_model.state()) |
There was a problem hiding this comment.
🚨 Unresolved merge conflict markers — this file has <<<<<<< Updated upstream / ======= / >>>>>>> Stashed changes blocks that will cause a SyntaxError at import time. Looks like a git stash pop or merge left conflicts that were accidentally committed.
|
|
||
| from .preset_target import PresetTarget | ||
|
|
||
| <<<<<<< Updated upstream |
There was a problem hiding this comment.
🚨 Unresolved merge conflict markers throughout this file — there are ~8 conflict blocks (<<<<<<< Updated upstream / >>>>>>> Stashed changes). This will not parse as valid Python. The refactoring here (removing deprecation helpers, renaming newton_mjwarp → newton) also seems like a significant scope expansion beyond the PR title — consider splitting into a separate PR once conflicts are resolved.
d19e140 to
7f56599
Compare
3a7aab3 to
a1477e0
Compare
The generated project package imported the example UI extension (ui_extension_example.py -> import omni.ext) from its __init__, so importing the project headless (e.g. Gym registration before SimulationApp) failed with "ModuleNotFoundError: No module named 'omni.ext'". Load the UI extension via its own config/extension.toml [[python.module]] entry instead, keeping the package root omni-free, and add the missing omni.ui import the example relies on. Also make the generator fail loudly when a requested agent config template is missing: it previously skipped silently, emitting a project whose Gym registration referenced a non-existent config file. Extend the template-generator tests with regression coverage: omni/pxr import-safety of the generated package, extension.toml UI-module registration, generated-code syntax validity, no top-level backend imports in generated env modules, and per-library agent-config completeness. NVBug 6251247
a1477e0 to
374d842
Compare
| @@ -10,5 +10,8 @@ Python module serving as a project/extension template. | |||
| # Register Gym environments. | |||
| from .tasks import * | |||
|
|
|||
There was a problem hiding this comment.
#rj: what's the consequence of this change? does it require all other scripts to import?) looks like an inline reviewer note that was accidentally committed. Should be removed before merge.
The skrl training scripts resolve the env config (resolve_task_config) before launch_simulation boots Kit, so the env config and the MDP terms it references must import without pxr. Generated manager-based projects loaded pxr eagerly two ways: the task mdp package re-exported isaaclab.envs.mdp with a star import, which force-resolves the whole lazy namespace, and mdp/rewards.py imported Articulation at module scope for a type-only annotation. Both pulled pxr before Kit, aborting startup with "TfNotice ... has not been created yet". Switch the generated mdp package to lazy_export() with a .pyi stub and guard the Articulation import under TYPE_CHECKING, matching the patterns used across isaaclab and PR isaac-sim#5916. Add a regression test that resolves the generated env config with omni and pxr import-blocked.
The template-generator CI tests land together with the import-safety fixes in this PR, so the single Fixed fragment (jichuanh-fix-template-generator.rst) already represents the isaaclab_rl change. Remove the empty template-generator-tests.skip carried from the chained test branch so one fragment per package remains.
1. Summary
SimulationApp):import <project>failed withModuleNotFoundError: No module named 'omni.ext'. The package root no longer imports the example UI extension, so it stays omni-free. (NVBug 6251247)develop. Includes the template-generator test scaffolding (also proposed in Adds CI tests for template generator #5885, commit preserved) plus new regression coverage — 15 tests.2. Changes
2.1 Generator (
tools/template)templates/extension/__init__ext: drop the eagerfrom .ui_extension_example import *from the package root.templates/extension/config/extension.toml: register<name>.ui_extension_exampleas its own[[python.module]]so Kit still loads the UI extension (Kit imports eachpython.moduleby name and scans it foromni.ext.IExt).templates/extension/ui_extension_example.py: add the missingimport omni.ui.generator.py: raise (instead of silentlycontinue-ing) when anagents/<rl_library>_<algorithm>_cfgtemplate is missing.2.2 Tests
extension.tomlUI-module registration, generated-.pyast/compilevalidity, no top-level backend imports in generated env modules, per-library agent-config completeness.3. Design note: why not lazy-import
omni.extomni.ext/ExampleExtensionare consumed only by Kit's extension manager (via[[python.module]]), never on the headless path. The correct fix is to not import it at the package root, not to defer it.4. Out of scope / known limitations
MotionLoader+collect_reference_motions+ AMP observations) that a generic generated env cannot provide — seecontrib/humanoid_amp. PPO trains as-generated.free()/omni.UsdMdl TfNoticestartup crashes (NVBug 6257159, 6251258) are a separate core issue already fixed by deferring pxr ([Fix] Defer pxr loading in isaaclab.sim, .assets, .scene, and .sim/utils #5826) and cherry-picked torelease/3.0.0-beta2.5. Test plan
./isaaclab.sh -p -m pytest source/isaaclab_rl/test/test_template_generator.py→ 15 passed__init__ext/extension.tomlfix (verified by reverting)./isaaclab.sh -f(pre-commit) clean