Skip to content

Fix converted assets spawning without physics, and add an importers extra - #6935

Open
hujc7 wants to merge 12 commits into
isaac-sim:developfrom
hujc7:jichuanh/usd-exchange-provider
Open

Fix converted assets spawning without physics, and add an importers extra#6935
hujc7 wants to merge 12 commits into
isaac-sim:developfrom
hujc7:jichuanh/usd-exchange-provider

Conversation

@hujc7

@hujc7 hujc7 commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Kit-less conversion could not work. The standalone URDF/MJCF importers require usd-exchange, Isaac Lab required usd-core on x86_64, and both install a complete pxr into the same directory — co-installing silently replaces one OpenUSD with the other, and uninstalling either deletes files the survivor needs. No resolver reports it; the collision only happens on disk.

Unify on usd-exchange, and ship the importers as an opt-in importers extra. They cannot be a base dependency: the wheel contributes to the isaacsim namespace, so beside a full Isaac Sim it displaces the Kit extension serving the same import (No module named 'isaacsim.asset'). Packaging cannot express "install unless Isaac Sim is present".

Also fixes converted assets spawning with no physics — previously #6881, folded here.

Based on #6866 by @kellyguo11.

What changed

  • usd-exchange on all platforms; usd-core removed. Newton selects [sim], not [sim,importers], whose extra pulls usd-core back in; the mesh-processing packages it carried are declared directly.
  • importers extra, declared conflicting with isaacsim in [tool.uv].conflicts. ./isaaclab.sh --install now rejects any conflicting pair from pyproject.toml, covering four pairs that were declared but unenforced.
  • Converters select a "Physics" variant on the generated USD; select_usd_variants raises for a required set that is absent or lacks the requested variant instead of composing nothing.
  • MuJoCo's USD schemas go on OpenUSD's plugin search path — its schema registry is built once and ignores plugins registered afterwards.
  • Converter tests run in the kit-less image, selected by a kitless marker rather than a list in the workflow.

Testing

Check Result
./isaaclab.sh --install 'newton,rl[rsl-rl],importers' then convert a URDF 10 joints, 1 articulation root
uv sync --extra importers / --extra isaacsim both resolve; together refused
Newton kit-less, converters, metadata contracts 430 + 52 passed
kit-less suite selection (-m kitless) 84/86 collected, 0 errors

Follow-up

usd-exchange 2.3.0 vendors OpenUSD 25.05, which predates the UsdPhysicsParsingUtility fix (upstream issue 4002, public 26.05). Measured on the shape upstream added as its regression test: 15/15 crashed, 0/15 with PXR_WORK_THREAD_LIMIT=1. usd-exchange MR !257 moves the default flavor to 26.08 and resolves it.

A standalone pip install isaaclab[importers] from outside a checkout needs --index-strategy unsafe-best-match --prerelease allow; inside a checkout uv reads both from [tool.uv].

@github-actions github-actions Bot added documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team infrastructure labels Aug 6, 2026
@hujc7 hujc7 changed the title Install the standalone URDF/MJCF importers by default Add an importers extra for the standalone URDF/MJCF importers Aug 7, 2026
@hujc7 hujc7 changed the title Add an importers extra for the standalone URDF/MJCF importers Fix converted assets spawning without physics, and add an importers extra Aug 7, 2026
hujc7 added 4 commits August 7, 2026 12:37
usd-core and usd-exchange each install a complete pxr into the same
directory, so co-installing them silently replaces one OpenUSD with the
other and uninstalling either deletes files the survivor still needs. No
resolver reports it: they are separate distributions and the collision
only happens on disk.

Isaac Lab required usd-core on x86_64 while the standalone URDF and MJCF
importers require usd-exchange, so the two could not be combined. Use
usd-exchange everywhere, which also aligns x86_64 with aarch64. Newton
selects [sim] rather than [sim,importers], whose extra pulls usd-core
back in; the mesh-processing packages that extra carried are declared
directly.

Based on isaac-sim#6866 by @kellyguo11.
The importers let conversion run without Isaac Sim, but the wheel
contributes to the isaacsim namespace: beside a full Isaac Sim it
displaces the Kit extension serving the same import and conversion fails
with "No module named 'isaacsim.asset'". Packaging cannot express
"install unless Isaac Sim is present", so ship them opt-in.

The pair is declared in tool.uv.conflicts, which binds uv sync. The
install CLI installs each feature in its own pip pass, so no resolver
ever sees a combination there; it now reads the same table and rejects
any declared conflict, covering the four pairs that were previously
declared and unenforced as well.

Also put MuJoCo's USD schemas on OpenUSD's plugin search path. They are a
codeless plugin registered when mujoco-usd-converter is imported, but
OpenUSD builds its schema registry once and ignores plugins registered
afterwards, so MJCF conversion failed whenever anything queried a schema
first.
The URDF and MJCF importers put the physics description behind a
"Physics" variant set, and the Isaac Sim importer extensions leave it
unselected. An unselected variant set contributes nothing, so those
assets composed with no joints, articulation roots, or mass properties.

Select a variant during conversion, configurable through
AssetConverterBaseCfg.physics_variant and defaulting to the
backend-portable one. Conversion raises when the asset does not offer the
requested variant rather than substituting another backend's.

At spawn time, select_usd_variants now raises for a "Physics" set that is
absent or lacks the requested variant. USD accepts a selection naming a
variant that does not exist and composes the prim as if nothing were
selected, which loses the physics with no diagnostic. Other variant sets
keep warning and continuing, which is what they were introduced for.

class_to_dict serialized enum members by expanding their internals, so
the new enum field wrote unusable entries into config.yaml;
update_class_from_dict now rebuilds the member from its value.
The kit-less container is where the standalone importers actually serve
conversion, so the URDF and MJCF converter tests belong in its
validation. Mark them, and the suites already running there, with a
kitless marker so the workflow selects by marker rather than by a list
it has to be edited to extend.

The image has no Isaac Sim, so pytest cannot be pointed at a directory:
collecting one imports every module in it and most of the suite builds an
AppLauncher at import time. Files are discovered by grepping for the
marker, which needs no import.
@hujc7
hujc7 force-pushed the jichuanh/usd-exchange-provider branch from c16c09c to ed60409 Compare August 7, 2026 19:42
@hujc7
hujc7 marked this pull request as ready for review August 8, 2026 00:00
@hujc7
hujc7 requested a review from a team August 8, 2026 00:00
One fragment per touched package: fold the usd-exchange entry into the
single isaaclab fragment, and skip isaaclab_newton, where the change is
pytest markers only.
@greptile-apps

greptile-apps Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR standardizes kit-less OpenUSD packaging on usd-exchange, adds an isolated importer extra, and ensures converted assets select a usable physics variant.

  • Adds importer conflict handling and kit-less converter coverage.
  • Exposes MuJoCo schemas before OpenUSD registry initialization.
  • Adds physics-variant validation and enum-aware configuration serialization.
  • Updates dependency resolution, documentation, and installation contracts.

Confidence Score: 4/5

The PR appears safe to merge, with non-blocking fixes recommended for the mismatched pytest marker registration and contradictory co-installation guidance.

The implementation changes do not leave an established blocking failure, but test-marker validation and importer installation documentation are inconsistent with the newly introduced contracts.

Files Needing Attention: pyproject.toml; docs/source/how-to/import_new_asset.rst

Important Files Changed

Filename Overview
pyproject.toml Adds the importer extra and USD-provider constraints, but registers importers while the new tests use the kitless marker.
source/isaaclab/isaaclab/cli/commands/install.py Maps the new importer feature to its root extra and rejects root-extra conflicts before installation.
source/isaaclab/isaaclab/sim/converters/asset_converter_base.py Selects the configured physics variant after conversion and delays cache-hash persistence until conversion succeeds.
source/isaaclab/isaaclab/sim/utils/prims.py Makes missing or invalid Physics variant selections fail explicitly while preserving lenient optional variants.
source/isaaclab/isaaclab/utils/dict.py Serializes enum members by value and reconstructs existing enum-typed fields during configuration updates.
source/isaaclab/isaaclab/init.py Adds the MuJoCo schema plugin directory to OpenUSD's discovery path during Isaac Lab import.
docs/source/how-to/import_new_asset.rst Documents the new importer extra but retains a contradictory paragraph implying it can coexist safely with Isaac Sim.
.github/actions/validate-kitless-image/action.yml Dynamically discovers kit-less tests by marker text and executes them in the container.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Input[URDF or MJCF] --> Importer{Runtime}
  Importer -->|Isaac Sim| Kit[Kit importer extension]
  Importer -->|Kit-less| Isolated[isaacsim-asset-isolated]
  Kit --> USD[Generated USD]
  Isolated --> USD
  USD --> Variant[Select Physics variant]
  Variant --> Asset[Spawnable physics asset]
Loading

Comments Outside Diff (1)

  1. docs/source/how-to/import_new_asset.rst, line 72-74 (link)

    P2 Remove contradictory coexistence guidance

    These lines describe a supported fallback order when Isaac Sim and the standalone importer share an environment, contradicting the preceding warning and package metadata that the pair cannot coexist. Plain pip does not enforce the uv conflict, so this guidance can lead users to an environment where the isolated wheel displaces isaacsim.asset and conversion fails.

Reviews (1): Last reviewed commit: "Merge remote-tracking branch 'upstream/d..." | Re-trigger Greptile

Comment thread pyproject.toml Outdated
"benchmark: test covers the Isaac Lab benchmark framework and infrastructure",
"rendering: test exercises the rendering / camera / visualizer pipeline",
"smoke: tests for core installation, task, and RL functionality",
"importers: test must pass inside the Kit-less container, which has no Isaac Sim runtime",

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 Register the kitless marker

The new converter tests and container selection use pytest.mark.kitless, but this configuration registers importers instead. This produces unknown-marker warnings and makes collection fail under --strict-markers.

Suggested change
"importers: test must pass inside the Kit-less container, which has no Isaac Sim runtime",
"kitless: test must pass inside the Kit-less container, which has no Isaac Sim runtime",

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 in 2f6bf12. The marker is now registered as kitless, matching the six test files and the -m kitless selection in validate-kitless-image. It had been renamed along with the extra by a bulk rename that should only have touched the extra name.

@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

The OpenUSD provider consolidation and converter variant-selection changes are coherent, but four integration gaps need correction: the kit-less marker is registered under the wrong name, kit-less URDF tests write into a read-only mount, the importers conflict omits the Isaac-Sim-bearing teleop extra, and installer conflict detection does not expand optional submodule tokens to their actual root extras.

  • Design and architecture: The opt-in importers extra and installer-side enforcement appropriately model its incompatibility with Isaac Sim. However, teleop directly installs Isaac Sim and therefore also needs an explicit conflict with importers. The installer must additionally expand optional submodules through OPTIONAL_SUBMODULE_ROOT_EXTRAS; otherwise mimic can install the teleop root extra without triggering its declared OV conflicts.
  • API: The nested AssetConverterBaseCfg.PhysicsVariant and exported REQUIRED_VARIANT_SETS are documented consistently, and the stricter select_usd_variants behavior is recorded in the changelog. No separate public API defect was identified, but packaging conflict behavior exposed through the install CLI remains incomplete for teleop and mimic requests.
  • Implementation: The conversion hash is correctly written only after successful variant selection, and enum serialization is symmetric. The CI integration is currently inconsistent: tests and the action use kitless, while pytest registers importers. Moreover, selecting the full URDF converter module for kit-less CI runs tests that create output beneath source/, which the action mounts read-only; those outputs need a writable temporary directory.

Minor fixes needed. Posted 4 actionable findings inline.

The full PR diff was reviewed; some supplemental surrounding file context was omitted.

Automated review; human maintainers own approval decisions.

Comment thread pyproject.toml Outdated
"benchmark: test covers the Isaac Lab benchmark framework and infrastructure",
"rendering: test exercises the rendering / camera / visualizer pipeline",
"smoke: tests for core installation, task, and RL functionality",
"importers: test must pass inside the Kit-less container, which has no Isaac Sim runtime",

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.

🟡 Warning · Implementation — Registered marker name does not match tests

The tests and .github/actions/validate-kitless-image/action.yml use pytest.mark.kitless (grep for pytest\.mark\.kitless, then pytest -m kitless), but the marker registered here is named importers. So kitless stays unregistered and raises PytestUnknownMarkWarning on every marked module (failing under --strict-markers), while the registered importers marker selects nothing. Rename the registration to kitless.

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 in 2f6bf12 — registered as kitless. Caused by a bulk rename of the extra (kitlessimporters) that also caught the marker string, leaving all six marked modules with an unregistered marker.

Comment thread pyproject.toml
[{ extra = "isaacsim" }, { extra = "ov" }],
[{ extra = "isaacsim" }, { extra = "ovphysx" }],
# both supply the ``isaacsim.asset`` importers; together the wheel shadows the Kit extension
[{ extra = "isaacsim" }, { extra = "importers" }],

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.

🟡 Warning · Design Architecture — teleop does not inherit the importers conflict

The teleop extra installs isaacsim[all,extscache] directly, which is why the table already mirrors (isaacsim, ov) with (teleop, ov). Only (isaacsim, importers) was added, so uv sync --extra teleop --extra importers resolves and ./isaaclab.sh -i teleop,importers passes the new check, co-installing isaacsim-asset-isolated beside a real Isaac Sim — exactly the shadowing this extra exists to prevent. Add (teleop, importers).

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 in 2f6bf12: added [{ extra = "teleop" }, { extra = "importers" }]. Correct — teleop lists isaacsim[all,extscache]==6.0.1.0 directly, so it inherits the incompatibility, and the table already mirrored every isaacsim pair with a teleop one.

Note that after merging develop the ovphysx pairs were removed upstream, so the table is now teleop×ov, isaacsim×ov, isaacsim×importers, teleop×importers.

pytestmark = pytest.mark.integration
# conversion is served by the standalone importers when Isaac Sim is absent, so these run
# unchanged in the Kit-less container
pytestmark = [pytest.mark.integration, pytest.mark.kitless]

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.

🟡 Warning · Implementation — Kit-less run writes into read-only source mount

Adding kitless makes the grep-based runner in validate-kitless-image execute this module, but that job mounts source/ as :ro. Several tests here, including the new test_physics_variant_*, call os.makedirs(<test_dir>/output/...) and write the converted USD there, which fails with Read-only file system. Direct conversion output for kit-less-selected tests to tmp_path instead.

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 in 2f6bf12. All 29 write sites in the two converter test modules now go through a helper that falls back to a temporary directory when the directory beside the tests is not writable, so the read-only source/ mount is handled. Verified by simulating the read-only mount: output resolves to /tmp/isaaclab_converter_tests.


Tokens are not extras: ``ov[ovrtx]`` installs ``ovrtx``, not ``ov``.
"""
extras = set(optional_submodules)

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.

🔵 Suggestion · Implementation — Submodule tokens are not mapped to root extras

set(optional_submodules) stores the CLI token, but OPTIONAL_SUBMODULE_ROOT_EXTRAS maps mimic to the teleop and mimic extras. So -i mimic,ov[ovphysx] installs the Isaac-Sim-bearing teleop extra while the declared {teleop, ovphysx} conflict never matches, leaving one of the pairs this function claims to enforce unenforced. Expand submodule tokens through OPTIONAL_SUBMODULE_ROOT_EXTRAS first.

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 in 2f6bf12: optional submodule tokens are expanded through OPTIONAL_SUBMODULE_ROOT_EXTRAS before the conflict check, so -i mimic contributes both mimic and teleop.

Verified at the time: mimic + ov[ovphysx] was rejected. After merging develop the ovphysx conflict pairs no longer exist upstream, so that specific pair is legal again — the check reads [tool.uv].conflicts rather than hardcoding, so it tracked the change.

hujc7 added 5 commits August 7, 2026 17:21
- Register the pytest marker as `kitless`; a rename had left it as
  `importers` while every test uses `kitless`, so the marker was
  unregistered and the registered one selected nothing.
- Declare `teleop` conflicting with `importers`. teleop installs
  isaacsim itself, so it inherits the same incompatibility.
- Expand optional submodule tokens through OPTIONAL_SUBMODULE_ROOT_EXTRAS
  before checking conflicts, so `-i mimic,ov[ovphysx]` is rejected --
  mimic pulls the teleop extra, which carries Isaac Sim.
- Write converted USD to a temporary directory when the tests cannot
  write beside themselves. The kit-less image mounts source/ read-only,
  and the kitless marker now selects these tests there.
- Drop the documentation paragraph describing a fallback order for a
  shared environment; the two cannot share one.
The conflict check sees one invocation, so installing the two sides in
separate passes -- or into a checkout carrying a local _isaac_sim --
still reached the state the extra exists to prevent. Check the target
environment for the other side before installing either.

Also carry newton[importers]'s trimesh>=4.6.8 lower bound into the base
dependency, which the hand-expanded replacement had dropped, and give
both Changed entries the migration guidance AGENTS.md requires.
…hange-provider

# Conflicts:
#	pyproject.toml
#	uv.lock
Develop isaac-sim#6938 re-imposed the platform split by overriding usd-exchange
to aarch64, so x86_64 would keep usd-core. This branch removes usd-core
entirely, and the merge kept that override -- so the kit-less image
installed no pxr at all and every converter test failed with
"No module named 'pxr'". The install CLI applies these overrides too,
not just uv sync, so the effect reached both paths.
The CLI constant tests pin the exact feature sets, so registering
`importers` has to be reflected there. Also drop the aarch64-only
usd-exchange override from the two published override files, which must
match the root pyproject and still carried the entry removed from it.
…hange-provider

# Conflicts:
#	docker/Dockerfile.kitless
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 infrastructure isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant