Skip to content

[Core] Refactor and cleanup core subpackage for 3.0 [14/N] - #8100

Merged
StafaH merged 10 commits into
isaac-sim:developfrom
StafaH:core-cleanup/14-sim-authoring
Sep 28, 2026
Merged

StafaH merged 10 commits into
isaac-sim:developfrom
StafaH:core-cleanup/14-sim-authoring

Conversation

@StafaH

@StafaH StafaH commented Sep 28, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Part 14 of the split of #7949. This PR cleans up sim authoring: the schema writers in isaaclab.sim.schemas, the spawners, and the mesh converter. It is rebased onto the current develop and ports only the parts of #7949 that still apply there. The authored USD is unchanged, and no public API changes.

Spawners and mesh converter

  • spawners.utils (renamed from spawners._utils, see below) adds a helper:
    • apply_schema_props writes a spawner schema slot. It sends a fragment mapping to the fragment writer, one entry at a time and anchored at the spawned prim, and sends a legacy cfg to the legacy writer. The mesh and shape spawners, spawn_from_mesh, and MeshConverter repeated this branch for their collision, mass, and rigid-body slots; they now call the helper.
  • Material paths are resolved inline at each call site (absolute paths are kept; relative names go under the spawned prim), replacing from_files._resolve_material_path.
  • Existing-prim checks are left to create_prim, which already raises the same ValueError. The spawner bodies are shorter, and spawn_geom_from_prim_type / _spawn_mesh_geom_from_mesh return the prim they create.
  • Mesh spawners share _axis_transform for the cylinder, capsule, and cone axis rotation.
  • Light, sensor, ground plane, and multi-USD spawners:
    • The ground plane hides its light with set_prim_visibility.
    • spawn_multi_usd_file builds MultiAssetSpawnerCfg in one call and no longer runs a hasattr check that was always true.
  • AssetConverterBase has a shorter USD-extension and hash-file check, and writes the config.yaml generation stamp with a single datetime.now() call. The stamp format is the same.

Schema writers

  • apply_rigid_body_properties, apply_collision_properties, and apply_mass_properties now share _apply_api_fragments. Target matching, create_if_missing, the zero-target warning, and result aggregation are unchanged.
  • The joint-drive writers share _write_drive_attributes, which converts angular stiffness and damping from per-radian to per-degree and maps drive_type to the USD type attribute. It is used by apply_drive, _ensure_drive_exists, apply_joint_drive_properties, and modify_joint_drive_properties. Joint-type detection reuses drive_instance_name, including in schemas_actuators.
  • Other shared helpers:
    • _write_mesh_approximation writes and validates the physics:approximation token.
    • _tetrahedralize_surface holds the pytetwild call and the tet-winding fix, moved out of define_deformable_body_properties.
  • Smaller cleanups:
    • activate_contact_sensors counts descendants with Usd.PrimRange.
    • schemas_actuators uses to_camel_case instead of a private camel-case regex.
    • Redundant pass statements are removed from the fragment marker classes.
    • Fragment appliers are called directly as cfg.func(cfg, prim_path, stage). @configclass already turns the func import string into a callable ResolvableString, so the callable(...) else string_to_callable(...) fallback (four schema writers and the physics-material spawner) never ran.

Reflection

  • Replaced avoidable getattr/setattr/hasattr with direct attribute access or an isinstance check wherever the attribute is always defined for the configs that reach that code (actuator authoring, the USD-file and shape spawners, the camera spawner's intrinsics, the fragment annotation lookup). The remaining uses are dynamic by design: iterating dataclass fields, the deprecated alias forwarding, optional class metadata, and mixed config types in the multi-asset wrapper.

No underscore module names or cross-file private helpers in core

  • Renamed the underscore modules: sim/spawners/_utils.py → utils.py, sim/schemas/_backend_hooks.py → backend_hooks.py, actuators/_compat.py → actuator_compat.py, benchmark/_cli.py → cli.py, cloner/_fabric_notices.py → fabric_notices.py, utils/_device.py → device.py. All importers in isaaclab, isaaclab_physx, isaaclab_newton, isaaclab_ov, the benchmark scripts, tests, and docs are updated.
  • Dropped the _ prefix from module-level functions used from other files: limits_equal, resolve_limit_aliases, skip_joint_drive, articulation_root_companion_namespace, apply_namespaced_schemas, drive_instance_name, validate_newton_native_actuator_cfgs, author_actuator_prims, resave_checkpoint_with_metadata, deprecate_field_alias, deprecated_schema_cfg, spawn_from_usd_file, spawn_geom_from_prim_type. They are not added to the package exports.

Not ported from #7949

  • The forwarding-shim refactors in schemas/__init__.py and schemas_cfg.py, the usd_api / physx_api deprecation properties, and the empty _usd_* metadata on deprecated cfgs. These are deprecation-only and will be removed.
  • The _OVERRIDABLE_PROPS constant in the wrappers, a single-use constant.
  • The import-only edits. develop already uses relative imports.

Type of change

  • Refactor (no functional change). The only visible difference is that the ValueError for an unsupported deformable type is now one line, instead of a triple-quoted string with embedded indentation.

Verification

  • USD authoring equivalence, comparing develop sources with this branch in Kit, one fresh stage per case. All 57 cases produce identical exported USDA, return values, and raised errors:
    • Sphere, cuboid, cylinder, capsule, and cone shapes; and sphere, cuboid, cylinder, capsule, cone, and rectangle meshes. Each is spawned plain, with legacy cfgs, and with fragments (including dict targets and absolute material paths).
    • The cable spawner, MeshFileCfg from a trimesh object and from an .obj file, and all five lights.
    • Pinhole and fisheye cameras, and the sensor frame.
    • UsdFileCfg with legacy cfgs and with fragments (articulation root, joint drives, contact sensors, semantics, materials), the compliant-contact spawner, and a ground plane asset.
    • MultiAssetSpawnerCfg and MultiUsdFileCfg, and a surface deformable.
    • The legacy define_/modify_ writers and the fragment apply_* writers, including ensure_drives_exist, the no-target case, mesh collision with an invalid approximation name, and fixed tendons.
    • A MeshConverter run with collision, mesh-collision, mass, and rigid props and make_instanceable, comparing the generated USD layers and config.yaml.
  • Tests, run one file at a time; all pass:
    • Spawners: test_spawn_shapes, test_spawn_meshes, test_spawn_lights, test_spawn_sensors, test_spawn_from_files, test_spawn_wrappers, test_spawn_cable, test_spawn_materials, test_default_ground_plane, test_visual_materials_kitless.
    • Schemas: test_schemas, test_schemas_deprecation, test_schemas_shim, test_schemas_kitless_fixed_joint, test_schema_fragments, test_schema_fragment_parity, test_schema_writer_nested_targets, test_joint_drive_fragments, test_collision_fragments, test_mass_fragments, test_mesh_collision_fragments, test_articulation_fragments, test_material_fragments, test_tendon_fragments, test_tendon_fragments_codeless, test_deformable_backend_split.
    • Converter: test_mesh_converter.
    • Actuator authoring: source/isaaclab/test/actuators, test_newton_actuator_manager_authoring, test_newton_actuators_newton, test_newton_actuators_physx.
  • After the renames, reflection pass, and review fixes, the 57-case USD comparison was rerun against the latest develop (0 differences), and the spawner, schema, fragment, converter, cloner (isaaclab and isaaclab_physx), benchmark CLI, device, Newton schema, and actuator authoring tests were rerun; all pass. Every renamed module and its importers in isaaclab_physx, isaaclab_newton, and isaaclab_ov import cleanly.
  • One-line helpers are kept inline rather than wrapped in functions (e.g. the drive get-or-apply, the passive-drive check, the dataclass-field dict, material paths).
  • After merging the latest develop (including [Core] Make tests backend-agnostic and start them with launch_test_simulation (3/3) #8102), the tests above were rerun and pass. isaaclab_physx/test/sim/test_spawn_meshes.py was run with the tetrahedralization extra, which covers _tetrahedralize_surface; it passes on this branch and on develop.
  • ruff check and ruff format are clean.

Checklist

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks with ./isaaclab.sh --format
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have added a changelog fragment under source/<package>/changelog.d/ for each changed package (see Changelog)
  • If this is a user-visible change, the fragment clearly describes it

Release backport

  • Backport this pull request to the active release branch after it merges into develop

@StafaH
StafaH requested a review from a team September 28, 2026 02:58
@github-actions github-actions Bot added the isaac-lab Related to Isaac Lab team label Sep 28, 2026
@greptile-apps

greptile-apps Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

[Medium risk] Refactors spawner and schema utilities for cleaner code.

The PR appears safe to merge, with a non-blocking change to joint-drive no-target error handling worth correcting.

Findings

  1. P2 No-target calls can raise ▶

Summary

This PR consolidates repeated schema-writing and spawner logic, simplifies prim creation and material-path handling, and extracts deformable-mesh and drive helpers.

  • One joint-drive dispatch change makes a no-target call resolve fragment functions before it can return.

Reviews (1) · Last reviewed commit: "Share schema-writer and spawner helpers ..."

Comment on lines 1389 to 1394
dispatchers = [_resolve_func(cfg) for cfg in fragments]

# match revolute/prismatic joints not excluded by a backend-registered skip predicate;
# non-joint matches (creation_candidates) are ignored silently since a subtree expression
# matches every descendant
# non-joint matches are ignored silently since a subtree expression matches every descendant
targets, _, any_skipped = _match_fragment_targets(
prim_path_expr,
lambda p: (p.IsA(UsdPhysics.RevoluteJoint) or p.IsA(UsdPhysics.PrismaticJoint)) and not _skip_joint_drive(p),
stage,
prim_path_expr, lambda p: _drive_instance_name(p) is not None and not _skip_joint_drive(p), stage
)

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 No-target calls can raise If a joint-drive fragment names a function in an unavailable module, this line raises before checking whether any joints match. Previously, a call with no matching joints returned False with a warning. This can turn an otherwise harmless asset spawn into an exception; resolve the functions only when there are targets.

Suggested change
dispatchers = [_resolve_func(cfg) for cfg in fragments]
# match revolute/prismatic joints not excluded by a backend-registered skip predicate;
# non-joint matches (creation_candidates) are ignored silently since a subtree expression
# matches every descendant
# non-joint matches are ignored silently since a subtree expression matches every descendant
targets, _, any_skipped = _match_fragment_targets(
prim_path_expr,
lambda p: (p.IsA(UsdPhysics.RevoluteJoint) or p.IsA(UsdPhysics.PrismaticJoint)) and not _skip_joint_drive(p),
stage,
prim_path_expr, lambda p: _drive_instance_name(p) is not None and not _skip_joint_drive(p), stage
)
# non-joint matches are ignored silently since a subtree expression matches every descendant
targets, _, any_skipped = _match_fragment_targets(
prim_path_expr, lambda p: _drive_instance_name(p) is not None and not _skip_joint_drive(p), stage
)
dispatchers = [_resolve_func(cfg) for cfg in fragments] if targets else []

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

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.

Isaac Lab Review Bot

Reviewed the sim-authoring deduplication across schema fragment dispatch, joint-drive authoring, mesh conversion, material-path resolution, and spawner creation paths. The patch consistently preserves the existing anchors, ordering, unit conversions, and legacy-writer routing shown in the changed code.

  • Design and architecture: The shared _apply_api_fragments, apply_schema_props, drive-writing, mesh-approximation, and tetrahedralization helpers consolidate duplicated behavior without introducing a new public abstraction or changing backend ownership. Reusing _drive_instance_name and to_camel_case within the schema package is consistent with the existing utility layer.
  • API: Public signatures and defaults remain intact. The fragment writers retain target matching, create_if_missing, warning, and result-aggregation behavior; joint-drive paths retain angular unit conversion and drive_type mapping. The internal geometry helpers now return their created prims, and their changed callers consume those returns consistently.
  • Implementation: The changed producer and consumer paths for schema slots and material paths were traced across shape, mesh, file, and converter spawners. The proposed concern about omitting an explicit to_camel_case convention does not demonstrate a changed attribute name or concrete failure under the utility's current deterministic default, so it does not warrant pre-merge action.

No blocking issues. No inline issue met the actionable-evidence threshold; the assessment above records the review feedback.

Automated review; human maintainers own approval decisions.

apply_func(props_expr(anchor_path, pattern), fragments, create_if_missing=True, stage=stage)


def resolve_material_path(material_path: str, parent_path: str) -> str:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I will inline this the resolve here makes no sense

return success


def _write_mesh_approximation(prim: Usd.Prim, name: str) -> None:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

i will also inline this there is only 2 caller, and one of the caller is going to be deprecated , it doesn't worth to refactor out

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 28, 2026
@StafaH

StafaH commented Sep 28, 2026

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 28, 2026
@StafaH

StafaH commented Sep 28, 2026

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added the ci:run-docker Trigger the on-demand Docker and GPU CI workflow label Sep 28, 2026
@isaaclab-bot isaaclab-bot Bot removed the ci:run-docker Trigger the on-demand Docker and GPU CI workflow label Sep 28, 2026
# Conflicts:
#	source/isaaclab_physx/benchmark/sensors/benchmark_contact_sensor.py
#	source/isaaclab_physx/benchmark/sensors/benchmark_frame_transformer.py
@StafaH

StafaH commented Sep 28, 2026

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 28, 2026
@StafaH
StafaH merged commit d11f811 into isaac-sim:develop Sep 28, 2026
53 checks passed
isaaclab-bot Bot pushed a commit that referenced this pull request Sep 28, 2026
# Description

Part 14 of the split of #7949. This PR cleans up sim authoring: the
schema writers in `isaaclab.sim.schemas`, the spawners, and the mesh
converter. It is rebased onto the current `develop` and ports only the
parts of #7949 that still apply there. The authored USD is unchanged,
and no public API changes.

**Spawners and mesh converter**
- `spawners.utils` (renamed from `spawners._utils`, see below) adds a
helper:
- `apply_schema_props` writes a spawner schema slot. It sends a fragment
mapping to the fragment writer, one entry at a time and anchored at the
spawned prim, and sends a legacy cfg to the legacy writer. The mesh and
shape spawners, `spawn_from_mesh`, and `MeshConverter` repeated this
branch for their collision, mass, and rigid-body slots; they now call
the helper.
- Material paths are resolved inline at each call site (absolute paths
are kept; relative names go under the spawned prim), replacing
`from_files._resolve_material_path`.
- Existing-prim checks are left to `create_prim`, which already raises
the same `ValueError`. The spawner bodies are shorter, and
`spawn_geom_from_prim_type` / `_spawn_mesh_geom_from_mesh` return the
prim they create.
- Mesh spawners share `_axis_transform` for the cylinder, capsule, and
cone axis rotation.
- Light, sensor, ground plane, and multi-USD spawners:
  - The ground plane hides its light with `set_prim_visibility`.
- `spawn_multi_usd_file` builds `MultiAssetSpawnerCfg` in one call and
no longer runs a `hasattr` check that was always true.
- `AssetConverterBase` has a shorter USD-extension and hash-file check,
and writes the `config.yaml` generation stamp with a single
`datetime.now()` call. The stamp format is the same.

**Schema writers**
- `apply_rigid_body_properties`, `apply_collision_properties`, and
`apply_mass_properties` now share `_apply_api_fragments`. Target
matching, `create_if_missing`, the zero-target warning, and result
aggregation are unchanged.
- The joint-drive writers share `_write_drive_attributes`, which
converts angular stiffness and damping from per-radian to per-degree and
maps `drive_type` to the USD `type` attribute. It is used by
`apply_drive`, `_ensure_drive_exists`, `apply_joint_drive_properties`,
and `modify_joint_drive_properties`. Joint-type detection reuses
`drive_instance_name`, including in `schemas_actuators`.
- Other shared helpers:
- `_write_mesh_approximation` writes and validates the
`physics:approximation` token.
- `_tetrahedralize_surface` holds the pytetwild call and the tet-winding
fix, moved out of `define_deformable_body_properties`.
- Smaller cleanups:
  - `activate_contact_sensors` counts descendants with `Usd.PrimRange`.
- `schemas_actuators` uses `to_camel_case` instead of a private
camel-case regex.
- Redundant `pass` statements are removed from the fragment marker
classes.
- Fragment appliers are called directly as `cfg.func(cfg, prim_path,
stage)`. `@configclass` already turns the `func` import string into a
callable `ResolvableString`, so the `callable(...) else
string_to_callable(...)` fallback (four schema writers and the
physics-material spawner) never ran.

**Reflection**
- Replaced avoidable `getattr`/`setattr`/`hasattr` with direct attribute
access or an `isinstance` check wherever the attribute is always defined
for the configs that reach that code (actuator authoring, the USD-file
and shape spawners, the camera spawner's intrinsics, the fragment
annotation lookup). The remaining uses are dynamic by design: iterating
dataclass fields, the deprecated alias forwarding, optional class
metadata, and mixed config types in the multi-asset wrapper.

**No underscore module names or cross-file private helpers in core**
- Renamed the underscore modules: `sim/spawners/_utils.py` → `utils.py`,
`sim/schemas/_backend_hooks.py` → `backend_hooks.py`,
`actuators/_compat.py` → `actuator_compat.py`, `benchmark/_cli.py` →
`cli.py`, `cloner/_fabric_notices.py` → `fabric_notices.py`,
`utils/_device.py` → `device.py`. All importers in `isaaclab`,
`isaaclab_physx`, `isaaclab_newton`, `isaaclab_ov`, the benchmark
scripts, tests, and docs are updated.
- Dropped the `_` prefix from module-level functions used from other
files: `limits_equal`, `resolve_limit_aliases`, `skip_joint_drive`,
`articulation_root_companion_namespace`, `apply_namespaced_schemas`,
`drive_instance_name`, `validate_newton_native_actuator_cfgs`,
`author_actuator_prims`, `resave_checkpoint_with_metadata`,
`deprecate_field_alias`, `deprecated_schema_cfg`, `spawn_from_usd_file`,
`spawn_geom_from_prim_type`. They are not added to the package exports.

**Not ported from #7949**
- The forwarding-shim refactors in `schemas/__init__.py` and
`schemas_cfg.py`, the `usd_api` / `physx_api` deprecation properties,
and the empty `_usd_*` metadata on deprecated cfgs. These are
deprecation-only and will be removed.
- The `_OVERRIDABLE_PROPS` constant in the wrappers, a single-use
constant.
- The import-only edits. `develop` already uses relative imports.

## Type of change

- Refactor (no functional change). The only visible difference is that
the `ValueError` for an unsupported deformable type is now one line,
instead of a triple-quoted string with embedded indentation.

## Verification

- USD authoring equivalence, comparing `develop` sources with this
branch in Kit, one fresh stage per case. All 57 cases produce identical
exported USDA, return values, and raised errors:
- Sphere, cuboid, cylinder, capsule, and cone shapes; and sphere,
cuboid, cylinder, capsule, cone, and rectangle meshes. Each is spawned
plain, with legacy cfgs, and with fragments (including dict targets and
absolute material paths).
- The cable spawner, `MeshFileCfg` from a trimesh object and from an
`.obj` file, and all five lights.
  - Pinhole and fisheye cameras, and the sensor frame.
- `UsdFileCfg` with legacy cfgs and with fragments (articulation root,
joint drives, contact sensors, semantics, materials), the
compliant-contact spawner, and a ground plane asset.
- `MultiAssetSpawnerCfg` and `MultiUsdFileCfg`, and a surface
deformable.
- The legacy `define_`/`modify_` writers and the fragment `apply_*`
writers, including `ensure_drives_exist`, the no-target case, mesh
collision with an invalid approximation name, and fixed tendons.
- A `MeshConverter` run with collision, mesh-collision, mass, and rigid
props and `make_instanceable`, comparing the generated USD layers and
`config.yaml`.
- Tests, run one file at a time; all pass:
- Spawners: `test_spawn_shapes`, `test_spawn_meshes`,
`test_spawn_lights`, `test_spawn_sensors`, `test_spawn_from_files`,
`test_spawn_wrappers`, `test_spawn_cable`, `test_spawn_materials`,
`test_default_ground_plane`, `test_visual_materials_kitless`.
- Schemas: `test_schemas`, `test_schemas_deprecation`,
`test_schemas_shim`, `test_schemas_kitless_fixed_joint`,
`test_schema_fragments`, `test_schema_fragment_parity`,
`test_schema_writer_nested_targets`, `test_joint_drive_fragments`,
`test_collision_fragments`, `test_mass_fragments`,
`test_mesh_collision_fragments`, `test_articulation_fragments`,
`test_material_fragments`, `test_tendon_fragments`,
`test_tendon_fragments_codeless`, `test_deformable_backend_split`.
  - Converter: `test_mesh_converter`.
- Actuator authoring: `source/isaaclab/test/actuators`,
`test_newton_actuator_manager_authoring`,
`test_newton_actuators_newton`, `test_newton_actuators_physx`.
- After the renames, reflection pass, and review fixes, the 57-case USD
comparison was rerun against the latest `develop` (0 differences), and
the spawner, schema, fragment, converter, cloner (`isaaclab` and
`isaaclab_physx`), benchmark CLI, device, Newton schema, and actuator
authoring tests were rerun; all pass. Every renamed module and its
importers in `isaaclab_physx`, `isaaclab_newton`, and `isaaclab_ov`
import cleanly.
- One-line helpers are kept inline rather than wrapped in functions
(e.g. the drive get-or-apply, the passive-drive check, the
dataclass-field dict, material paths).
- After merging the latest `develop` (including #8102), the tests above
were rerun and pass. `isaaclab_physx/test/sim/test_spawn_meshes.py` was
run with the `tetrahedralization` extra, which covers
`_tetrahedralize_surface`; it passes on this branch and on `develop`.
- `ruff check` and `ruff format` are clean.

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] I have added a changelog fragment under
`source/<package>/changelog.d/` for each changed package (see
[Changelog](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html#changelog))
- [x] If this is a user-visible change, the fragment clearly describes
it


## Release backport

- [x] <!-- backport-active-release --> Backport this pull request to the
active release branch after it merges into `develop`

(cherry picked from commit d11f811)
@isaaclab-bot

isaaclab-bot Bot commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

Backported to release/3.0.0 as b8c1a6b.

@StafaH
StafaH deleted the core-cleanup/14-sim-authoring branch October 10, 2026 19:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants