Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f003ec7
Bump usd-core dependency to 26.05 to fix USD physics crash
mataylor-nvidia Jul 14, 2026
b9883d4
Fix benchmark test fixture expecting stale usd-core 25.11 version
mataylor-nvidia Jul 14, 2026
b639c8a
patch usd-core ext path
mataylor-nvidia Jul 14, 2026
45d5da8
bat usd-core patch
mataylor-nvidia Jul 14, 2026
1279e7e
update
mataylor-nvidia Jul 14, 2026
052b52f
Fix pxr conflict with omni.usd.schema.usd_particle_field in OV enviro…
mataylor-nvidia Jul 14, 2026
1e280e3
revert
mataylor-nvidia Jul 14, 2026
c8e1595
fix
mataylor-nvidia Jul 14, 2026
3c0deaa
update
mataylor-nvidia Jul 15, 2026
bb65e2e
cleanup
mataylor-nvidia Jul 15, 2026
c7757b6
use small python script
mataylor-nvidia Jul 16, 2026
e850085
cleanup
mataylor-nvidia Jul 16, 2026
b755878
fix format
mataylor-nvidia Jul 16, 2026
328fb7f
fix
mataylor-nvidia Jul 16, 2026
29a0fb5
fix
mataylor-nvidia Jul 16, 2026
2c3a052
fix
mataylor-nvidia Jul 16, 2026
8d6a542
fix
mataylor-nvidia Jul 16, 2026
812c51b
fix
mataylor-nvidia Jul 16, 2026
9975b67
Surface read-only pxr promotion failure with a warning
mataylor-nvidia Jul 16, 2026
8d97c56
fix
mataylor-nvidia Jul 16, 2026
2e1efd3
fix
mataylor-nvidia Jul 16, 2026
6dc7638
fix
mataylor-nvidia Jul 16, 2026
437190a
_find_extscache
mataylor-nvidia Jul 20, 2026
9391637
update
mataylor-nvidia Jul 21, 2026
cc3c00f
fix
mataylor-nvidia Jul 21, 2026
7949221
Merge branch 'develop' into mataylor/bump-usd-26.05
mataylor-nvidia Jul 21, 2026
ea91a4c
revert
mataylor-nvidia Jul 21, 2026
579f763
Merge branch 'mataylor/bump-usd-26.05' of github.com:mataylor-nvidia/…
mataylor-nvidia Jul 21, 2026
cf0df85
update
mataylor-nvidia Jul 21, 2026
368476c
update
mataylor-nvidia Jul 21, 2026
f6a6c99
undo
mataylor-nvidia Jul 21, 2026
3c5d45b
update
mataylor-nvidia Jul 21, 2026
294ccf1
update
mataylor-nvidia Jul 21, 2026
b38daf5
fix
mataylor-nvidia Jul 22, 2026
ecd7233
fix
mataylor-nvidia Jul 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions isaaclab.bat
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ if exist "%ISAACLAB_PATH%\_isaac_sim\" (
)
)

rem Prefer omni.usd.libs over usd-core for pxr imports to avoid TfType::AddAlias
rem conflicts with ovrtx/ovphysx (see tools/setup_usd_libs.py for details).
for /f "delims=" %%d in ('"%python_exe%" "%ISAACLAB_PATH%\tools\setup_usd_libs.py"') do (
set "PYTHONPATH=%%d;!PYTHONPATH!"
set "PATH=%%d\bin;!PATH!"
)

rem Execute CLI.
"%python_exe%" -c "from isaaclab.cli import cli; cli()" %*

Expand Down
11 changes: 11 additions & 0 deletions isaaclab.sh
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,16 @@ if [ -d "$ISAACLAB_PATH/_isaac_sim" ]; then
fi
fi

# Prefer omni.usd.libs over usd-core for pxr imports to avoid TfType::AddAlias
# conflicts with ovrtx/ovphysx. omni.usd.libs/pxr/ is a namespace package, so
# Python ignores PYTHONPATH order and picks usd-core's regular pxr instead; writing
# a minimal __init__.py promotes it to a regular package so path order takes effect.
_ov_usd_libs_dir=$("$python_exe" "$ISAACLAB_PATH/tools/setup_usd_libs.py")
if [ -n "$_ov_usd_libs_dir" ]; then
export PYTHONPATH="$_ov_usd_libs_dir:$PYTHONPATH"
export LD_LIBRARY_PATH="$_ov_usd_libs_dir/bin:$LD_LIBRARY_PATH"
fi
Comment thread
mataylor-nvidia marked this conversation as resolved.
unset _ov_usd_libs_dir

# Execute CLI.
exec "$python_exe" -c "from isaaclab.cli import cli; cli()" "$@"
8 changes: 6 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ dependencies = [
# OpenUSD (kit-less mode). Both packages vendor a complete ``pxr`` runtime, so
# they must never co-install: usd-core supplies pxr where it has wheels (x86_64),
# usd-exchange supplies it on aarch64 (where usd-core has no wheel).
"usd-core>=25.11,<26.0 ; platform_machine in 'x86_64 AMD64'",
"usd-core>=26.05,<27.0 ; platform_machine in 'x86_64 AMD64'",
Comment thread
mataylor-nvidia marked this conversation as resolved.
Comment thread
mataylor-nvidia marked this conversation as resolved.
"usd-exchange>=2.2 ; platform_machine in 'aarch64 arm64'",
# avoid broken hf-xet pre-release cached on NVIDIA Artifactory
"hf-xet>=1.4.1,<2.0.0 ; platform_machine in 'x86_64 AMD64 aarch64 arm64'",
Expand All @@ -86,7 +86,7 @@ dependencies = [
# exact git commit is forced via [tool.uv].override-dependencies (uv sync only).
# The importers extra carries the mesh-processing deps (coacd, fast-simplification,
# ...) that honoring USD-authored ``physics:approximation`` requires.
"newton[sim,importers]>=1.2.0",
"newton[sim]>=1.2.0",
# Loose bound co-resolves with isaacsim's ==0.2.0; the override below forces >=0.4.0.
"newton-usd-schemas>=0.2.0",
"PyOpenGL-accelerate>=3.1.0",
Expand Down Expand Up @@ -340,6 +340,10 @@ override-dependencies = [
"newton[sim,importers] @ git+https://github.com/newton-physics/newton.git@81cdcfc2dd89f8b7285e32b5e3853092a97fa6f9",
# Force the Newton-matched schemas over isaacsim's ==0.2.0 pin.
"newton-usd-schemas>=0.4.0",
# newton[importers] pins usd-core<26.5 in every published release and the current
# dev build; override it so uv accepts our usd-core>=26.05 requirement.
# Remove once newton publishes a release that drops the upper bound.
"usd-core>=26.05,<27.0 ; platform_machine in 'x86_64 AMD64'",
"torch==2.11.0",
"torchvision==0.26.0",
"torchaudio==2.11.0",
Expand Down
5 changes: 5 additions & 0 deletions source/isaaclab/changelog.d/mataylor-golden-sim-usd.minor.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Changed
^^^^^^^

* Bumped ``usd-core`` dependency from ``>=25.11,<26.0`` to ``>=26.05,<27.0`` on x86_64 to resolve
a crash in ``libusd_ms`` triggered by USD physics loading (``LoadUsdPhysicsFromRange``) for kitless runs.
4 changes: 2 additions & 2 deletions source/isaaclab/test/benchmark/test_capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def test_capture_versions_preserves_runtime_packages():
StringMetadata(name="ovphysx_version", data="3.0.5"),
StringMetadata(name="mujoco_version", data="3.8.1"),
StringMetadata(name="cuda_bindings_version", data="12.9.4"),
StringMetadata(name="usd_core_version", data="25.11"),
StringMetadata(name="usd_core_version", data="26.05"),
StringMetadata(name="isaaclab_release_version", data="3.0.0"),
]
bm = _Bm({"VersionInfo": _Rec(MeasurementData(measurements=[], metadata=md, artefacts=[]))})
Expand All @@ -89,7 +89,7 @@ def test_capture_versions_preserves_runtime_packages():
assert versions.ovphysx == "3.0.5"
assert versions.mujoco == "3.8.1"
assert versions.cuda_bindings == "12.9.4"
assert versions.usd_core == "25.11"
assert versions.usd_core == "26.05"
assert versions.isaaclab_release == "3.0.0"


Expand Down
186 changes: 186 additions & 0 deletions source/isaaclab/test/cli/test_setup_usd_libs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

"""Tests for tools/setup_usd_libs.py.
Covers two Isaac Sim install layouts:
* **Symlink / binary install** — ``ISAACLAB_PATH/_isaac_sim/extscache/omni.usd.libs-<ver>/``
* **Wheel / pip install** — ``isaacsim`` package on ``sys.path``; ``extscache`` lives next
to the package ``__init__.py``.
Each test runs the script as a subprocess so the module-level code executes in a
clean interpreter.
"""

from __future__ import annotations

import os
import sys
from pathlib import Path

import pytest

pytestmark = pytest.mark.unit


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------


def _script_path() -> Path:
for parent in Path(__file__).resolve().parents:
candidate = parent / "tools" / "setup_usd_libs.py"
if candidate.is_file():
return candidate
raise RuntimeError("Could not find tools/setup_usd_libs.py")


def _run(env_overrides: dict[str, str], tmp_path: Path) -> tuple[int, str, str]:
"""Run setup_usd_libs.py as a subprocess and return (returncode, stdout, stderr)."""
import subprocess

env = {**os.environ, **env_overrides}
result = subprocess.run(
[sys.executable, str(_script_path())],
capture_output=True,
text=True,
env=env,
)
return result.returncode, result.stdout, result.stderr


def _make_usd_libs(base: Path, version: str = "26.05.0") -> Path:
"""Create a minimal omni.usd.libs extension directory under *base*/extscache."""
usd_libs = base / "extscache" / f"omni.usd.libs-{version}"
(usd_libs / "pxr").mkdir(parents=True)
return usd_libs


# ---------------------------------------------------------------------------
# Symlink / binary install
# ---------------------------------------------------------------------------


class TestSymlinkInstall:
"""ISAACLAB_PATH/_isaac_sim/extscache layout (binary / developer install)."""

def _isaaclab_env(self, tmp_path: Path) -> dict[str, str]:
return {"ISAACLAB_PATH": str(tmp_path), "PYTHONPATH": ""}

def test_prints_usd_libs_dir(self, tmp_path: Path) -> None:
"""Script prints the usd_libs_dir path when omni.usd.libs exists."""
usd_libs = _make_usd_libs(tmp_path / "_isaac_sim")

rc, stdout, _ = _run(self._isaaclab_env(tmp_path), tmp_path)

assert rc == 0
assert stdout == str(usd_libs)

def test_creates_pxr_init_when_missing(self, tmp_path: Path) -> None:
"""Script creates pxr/__init__.py so the directory becomes an importable package."""
usd_libs = _make_usd_libs(tmp_path / "_isaac_sim")

_run(self._isaaclab_env(tmp_path), tmp_path)

assert (usd_libs / "pxr" / "__init__.py").is_file()

def test_leaves_existing_pxr_init_intact(self, tmp_path: Path) -> None:
"""Script does not overwrite an existing pxr/__init__.py."""
usd_libs = _make_usd_libs(tmp_path / "_isaac_sim")
init_py = usd_libs / "pxr" / "__init__.py"
init_py.write_text("# sentinel")

_run(self._isaaclab_env(tmp_path), tmp_path)

assert init_py.read_text() == "# sentinel"

def test_picks_latest_version(self, tmp_path: Path) -> None:
"""Script selects the lexicographically last omni.usd.libs version."""
_make_usd_libs(tmp_path / "_isaac_sim", "25.11.0")
newer = _make_usd_libs(tmp_path / "_isaac_sim", "26.05.0")

_, stdout, _ = _run(self._isaaclab_env(tmp_path), tmp_path)

assert stdout == str(newer)

def test_no_usd_libs_produces_no_output(self, tmp_path: Path) -> None:
"""Script exits 0 with no stdout when extscache has no omni.usd.libs dirs."""
(tmp_path / "_isaac_sim" / "extscache").mkdir(parents=True)

rc, stdout, _ = _run(self._isaaclab_env(tmp_path), tmp_path)

assert rc == 0
assert stdout == ""

@pytest.mark.skipif(sys.platform == "win32", reason="chmod semantics differ on Windows")
def test_readonly_pxr_dir_warns_and_exits_cleanly(self, tmp_path: Path) -> None:
"""Script emits [WARNING] to stderr and exits 0 when pxr/ is not writable."""
usd_libs = _make_usd_libs(tmp_path / "_isaac_sim")
pxr_dir = usd_libs / "pxr"
pxr_dir.chmod(0o555)

try:
rc, _, stderr = _run(self._isaaclab_env(tmp_path), tmp_path)
finally:
pxr_dir.chmod(0o755)

assert rc == 0
assert "[WARNING]" in stderr


# ---------------------------------------------------------------------------
# Wheel / pip install
# ---------------------------------------------------------------------------


class TestWheelInstall:
"""Wheel install layout: isaacsim on sys.path, extscache next to __init__.py."""

def _wheel_env(self, isaacsim_site: Path) -> dict[str, str]:
"""Environment that hides the symlink path and exposes a fake isaacsim package."""
existing = os.environ.get("PYTHONPATH", "")
pythonpath = str(isaacsim_site) + (os.pathsep + existing if existing else "")
return {
"ISAACLAB_PATH": "", # no _isaac_sim symlink
"PYTHONPATH": pythonpath,
}

def _make_fake_isaacsim(self, base: Path, version: str = "26.05.0") -> Path:
"""Create a minimal fake isaacsim package with an extscache directory."""
pkg = base / "isaacsim"
pkg.mkdir(parents=True, exist_ok=True)
(pkg / "__init__.py").write_text("")
return _make_usd_libs(pkg, version)

def test_prints_usd_libs_dir(self, tmp_path: Path) -> None:
"""Script finds omni.usd.libs via importlib.util.find_spec when no symlink exists."""
usd_libs = self._make_fake_isaacsim(tmp_path)

rc, stdout, _ = _run(self._wheel_env(tmp_path), tmp_path)

assert rc == 0
assert stdout == str(usd_libs)

def test_creates_pxr_init_when_missing(self, tmp_path: Path) -> None:
"""Script promotes pxr/ to a package in the wheel-install layout too."""
usd_libs = self._make_fake_isaacsim(tmp_path)

_run(self._wheel_env(tmp_path), tmp_path)

assert (usd_libs / "pxr" / "__init__.py").is_file()

def test_picks_latest_version(self, tmp_path: Path) -> None:
"""Script selects the latest omni.usd.libs in the wheel extscache."""
pkg = tmp_path / "isaacsim"
pkg.mkdir(parents=True)
(pkg / "__init__.py").write_text("")
_make_usd_libs(pkg, "25.11.0")
newer = _make_usd_libs(pkg, "26.05.0")

_, stdout, _ = _run(self._wheel_env(tmp_path), tmp_path)

assert stdout == str(newer)
12 changes: 0 additions & 12 deletions source/isaaclab/test/cli/test_source_package_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,6 @@ def _repo_root() -> Path:
raise RuntimeError("Could not find Isaac Lab repository root.")


def test_isaaclab_usd_core_pin_stays_on_isaacsim_compatible_usd25_abi():
"""The kit-less USD package must stay on the Isaac Sim compatible USD 25 ABI."""
with (_repo_root() / "pyproject.toml").open("rb") as f:
pyproject = tomllib.load(f)

usd_core_dependencies = [
dependency for dependency in pyproject["project"]["dependencies"] if dependency.startswith("usd-core")
]

assert usd_core_dependencies == ["usd-core>=25.11,<26.0 ; platform_machine in 'x86_64 AMD64'"]


def test_isaaclab_standalone_usd_providers_are_platform_disjoint():
"""Standalone USD packages must not overlap on platforms where both ship ``pxr``."""
with (_repo_root() / "pyproject.toml").open("rb") as f:
Expand Down
2 changes: 1 addition & 1 deletion source/isaaclab/test/cli/test_uv_run_pyproject.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def test_uv_run_base_dependencies_cover_newton_rsl_rl_training():
# Newton is the default physics engine and RSL-RL the default training library,
# so both ship as core third-party requirements (not opt-in extras). The importers
# extra carries the mesh-processing deps that authored collision approximations need.
assert any(dep.startswith("newton[sim,importers]") for dep in dependencies)
assert any(dep.startswith("newton[sim]") for dep in dependencies)
assert any(dep.startswith("rsl-rl-lib") for dep in dependencies)


Expand Down
52 changes: 52 additions & 0 deletions tools/setup_usd_libs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

"""Locate omni.usd.libs and promote its pxr package to a regular package.

Prints the extension directory to stdout on success, nothing on failure.
Called by isaaclab.sh / isaaclab.bat to populate PYTHONPATH / LD_LIBRARY_PATH.
"""

import glob
import importlib.util
import os
import sys


def _find_extscache() -> str:
# Binary / symlink install: ISAACLAB_PATH/_isaac_sim/extscache.
# Only probe when ISAACLAB_PATH is set; an empty value would produce a
# relative path that resolves against CWD and may accidentally match a
# _isaac_sim symlink in an unrelated working directory.
isaaclab_path = os.environ.get("ISAACLAB_PATH", "")
if isaaclab_path:
symlink_path = os.path.join(isaaclab_path, "_isaac_sim", "extscache")
if os.path.isdir(symlink_path):
return symlink_path

# Wheel / pip install: locate the isaacsim package without importing it so
# that this script can run before PYTHONPATH is fully configured.
spec = importlib.util.find_spec("isaacsim")
if spec is not None and spec.origin:
return os.path.join(os.path.dirname(spec.origin), "extscache")

return ""


extscache = _find_extscache()
candidates = sorted(glob.glob(os.path.join(extscache, "omni.usd.libs-*"))) if extscache else []
if candidates:
usd_libs_dir = candidates[-1]
init_py = os.path.join(usd_libs_dir, "pxr", "__init__.py")
if os.path.exists(os.path.join(usd_libs_dir, "pxr")) and not os.path.isfile(init_py):
try:
open(init_py, "w").close()
except OSError as exc:
print(
f"[WARNING] Cannot promote omni.usd.libs/pxr to a regular package; skipping USD path setup: {exc}",
file=sys.stderr,
)
sys.exit(0)
print(usd_libs_dir, end="")
Loading
Loading