Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed rigid object collection deletion handling to preserve legacy string-path callbacks and normalize event payloads before invalidation.
Original file line number Diff line number Diff line change
Expand Up @@ -1493,22 +1493,34 @@ def _invalidate_initialize_callback(self, event) -> None:
# set all existing views to None to invalidate them
self._root_view = None

def _on_prim_deletion(self, prim_path: str) -> None:
"""Invalidates and deletes the callbacks when the prim is deleted.
def _on_prim_deletion(self, event) -> None:
Comment thread
Xalzeroph marked this conversation as resolved.
"""Invalidates and deletes the callbacks when a prim is deleted.

Args:
prim_path: The path to the prim that is being deleted.
event: A legacy prim-path string, a deletion payload dictionary, or a deletion event
whose payload contains the deleted prim path.

.. note::
This function is called when the prim is deleted.
This function is called when a prim is deleted.
"""
if isinstance(event, str):
prim_path = event
else:
payload = getattr(event, "payload", event) if not isinstance(event, dict) else event
prim_path = payload.get("prim_path", "") if isinstance(payload, dict) else ""
if prim_path == "/":
self._clear_callbacks()
matches_collection = True
else:
matches_collection = any(
sim_utils.matches_path_expr_prefix(obj.prim_path, prim_path)
for obj in self.cfg.rigid_objects.values()
)
if not matches_collection:
return
for prim_path_expr in [obj.prim_path for obj in self.cfg.rigid_objects.values()]:
if sim_utils.matches_path_expr_prefix(prim_path_expr, prim_path):
self._clear_callbacks()
return
try:
self._invalidate_initialize_callback(event)
finally:
self._clear_callbacks()

"""
Deprecated properties and methods.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# 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

from types import SimpleNamespace
Comment thread
Xalzeroph marked this conversation as resolved.
from unittest.mock import Mock

import pytest

from isaaclab_physx.assets.rigid_object_collection.rigid_object_collection import RigidObjectCollection


def _make_collection_for_deletion_test() -> RigidObjectCollection:
collection = object.__new__(RigidObjectCollection)
collection.cfg = SimpleNamespace(
rigid_objects={"object": SimpleNamespace(prim_path="/World/Table_[^/]*/Object_0")}
)
collection._is_initialized = True
collection._root_view = object()
collection._debug_vis_handle = None
return collection


def test_prim_deletion_string_path_preserves_legacy_input() -> None:
collection = _make_collection_for_deletion_test()

collection._on_prim_deletion("/World/Table_0/Object_0")

assert collection.is_initialized is False
assert collection._root_view is None


def test_prim_deletion_event_invalidates_matching_collection() -> None:
collection = _make_collection_for_deletion_test()

collection._on_prim_deletion(SimpleNamespace(payload={"prim_path": "/World/Table_0/Object_0"}))

assert collection.is_initialized is False
assert collection._root_view is None


@pytest.mark.parametrize("event", [{"prim_path": "/"}, SimpleNamespace(payload={"prim_path": "/"})])
def test_prim_deletion_event_accepts_root_payload_forms(event) -> None:
collection = _make_collection_for_deletion_test()

collection._on_prim_deletion(event)

assert collection.is_initialized is False
assert collection._root_view is None


def test_nonmatching_prim_deletion_leaves_collection_initialized() -> None:
collection = _make_collection_for_deletion_test()

collection._on_prim_deletion(SimpleNamespace(payload={"prim_path": "/World/Other/Object_0"}))

assert collection.is_initialized is True
assert collection._root_view is not None


def test_prim_deletion_clears_callbacks_when_invalidation_fails() -> None:
collection = _make_collection_for_deletion_test()
collection._invalidate_initialize_callback = Mock(side_effect=RuntimeError("teardown failed"))
collection._clear_callbacks = Mock()

with pytest.raises(RuntimeError, match="teardown failed"):
collection._on_prim_deletion({"prim_path": "/"})

collection._clear_callbacks.assert_called_once_with()
Loading