# Perform namespace edit inside a variant set edit target

**URL:** <https://forum.aousd.org/t/perform-namespace-edit-inside-a-variant-set-edit-target/1006>\
**Category:** USD\
**Tags:** python\
**Created:** [December 1, 2023, 12:36pm UTC](https://forum.aousd.org/t/perform-namespace-edit-inside-a-variant-set-edit-target/1006 "2023-12-01T12:36:03Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![BigRoyNL](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.aousd.org/bigroynl/32/413_2.png) [@BigRoyNL](https://forum.aousd.org/u/BigRoyNL)\
**Post date:** [December 1, 2023, 12:36pm UTC](https://forum.aousd.org/t/perform-namespace-edit-inside-a-variant-set-edit-target/1006/1 "2023-12-01T12:36:03Z")

</div>

I’d like to be able to apply an `Sdf.NamespaceEdit` inside a variant edit target, but it **keeps crashing** on me.

```python
from pxr import Usd, Sdf

# Create a stage with a root xform
stage = Usd.Stage.CreateInMemory()
prim = stage.DefinePrim("/root", "Xform")

# Add variant set
variant_sets = prim.GetVariantSets()
variant_set = variant_sets.AddVariantSet("model")

# Add some variants
variant_set.AddVariant("main")
variant_set.AddVariant("damaged")
variant_set.AddVariant("ice")

# Set the variant selection
variant_set.SetVariantSelection("main")

edit_target = variant_set.GetVariantEditTarget()
stage.SetEditTarget(edit_target)

child = stage.DefinePrim("/root/child", "Xform")
spec = next(iter(child.GetPrimStack())) # there is only one prim spec in this case, it's in the variant set
assert spec.path == '/root{model=main}child'

# Rename, keep parent
edit = Sdf.NamespaceEdit.Rename(
    spec.path,
    "new_name"
)

layer = spec.layer
batch_edit = Sdf.BatchNamespaceEdit()
batch_edit.Add(edit)
layer.Apply(batch_edit)

child = stage.GetPrimAtPath("/root/new_name")
assert child, "Renamed child must exist"
assert not stage.GetPrimAtPath("/root/child"), "Old prim name must not exist"

# However, now accessing the prim stack for the renamed prim crashes
prim_stack = child.GetPrimStack() # CRASH

```

Am I missing something obvious? 🙂

Running it in Maya provides me this crash log:

```auto
//=====================================================
Maya Crash Report
//=====================================================

Exception code: C0000005: ACCESS_VIOLATION - illegal read at address 0x00000000
Fault address: D502A5FF in C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\usd_pcp.dll
0001:001895FF Logical offset (see .map file for location)

Call stack:
	Module: C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\usd_usd.dll (-exported-)
	Location: usd_usd.dllpxrInternal_v0_22 __pxrReserved__ ::UsdAttributeQuery::_Get<pxrInternal_v0_22 __pxrReserved__ ::VtArray<pxrInternal_v0_22 __pxrReserved__ ::GfVec4d> > + 79B164 bytes
	Decl: private: bool __cdecl pxrInternal_v0_22__ pxrReserved __::UsdAttributeQuery::_Get<class pxrInternal_v0_22__ pxrReserved __::VtArray<class pxrInternal_v0_22__ pxrReserved__::GfVec4d> >(class pxrInternal_v0_22__pxrReserved __::VtArray<class pxrInternal_v0_22__ px
	Module: C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\usd_usd.dll (-exported-)
	Location: usd_usd.dllpxrInternal_v0_22 __pxrReserved__ ::UsdAttributeQuery::_Get<pxrInternal_v0_22 __pxrReserved__ ::VtArray<pxrInternal_v0_22 __pxrReserved__ ::GfVec4d> > + 488E40 bytes
	Decl: private: bool __cdecl pxrInternal_v0_22__ pxrReserved __::UsdAttributeQuery::_Get<class pxrInternal_v0_22__ pxrReserved __::VtArray<class pxrInternal_v0_22__ pxrReserved__::GfVec4d> >(class pxrInternal_v0_22__pxrReserved __::VtArray<class pxrInternal_v0_22__ px
	Module: C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\python\pxr\Usd\_usd.pyd (-exported-)
	Location: _usd.pydPyInit_libusd + 1910DA bytes
	Module: C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\boost_python310-vc142-mt-x64-1_76.dll (-exported-)
	Location: boost_python310-vc142-mt-x64-1_76.dllboost::python::objects::function::call + 2D3 bytes
	Decl: public: struct _object * __ptr64__ cdecl boost::python::objects::function::call(struct _object * __ptr64,struct _object *__ ptr64)const __ptr64
	Module: C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\boost_python310-vc142-mt-x64-1_76.dll (-exported-)
	Location: boost_python310-vc142-mt-x64-1_76.dllboost::python::objects::static_data + 2AA bytes
	Decl: struct _object * __ptr64__ cdecl boost::python::objects::static_data(void)
	Module: C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\boost_python310-vc142-mt-x64-1_76.dll (-exported-)
	Location: boost_python310-vc142-mt-x64-1_76.dllboost::python::detail::exception_handler::operator() + 3B bytes
	Decl: public: bool __cdecl boost::python::detail::exception_handler::operator()(class boost::function0<void> const &__ptr64)const __ptr64
	Module: C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\python\pxr\Tf\_tf.pyd (-exported-)
	Location: _tf.pydpxrInternal_v0_22 __pxrReserved__ ::tfTestStaticTokens_StaticTokenType::tfTestStaticTokens_StaticTokenType + 619F0 bytes
	Decl: public: __cdecl pxrInternal_v0_22__ pxrReserved__::tfTestStaticTokens_StaticTokenType::tfTestStaticTokens_StaticTokenType(void)__ptr64
	Module: C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\boost_python310-vc142-mt-x64-1_76.dll (-exported-)
	Location: boost_python310-vc142-mt-x64-1_76.dllboost::python::handle_exception_impl + 47 bytes
	Decl: bool __cdecl boost::python::handle_exception_impl(class boost::function0<void>)
	Module: C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\boost_python310-vc142-mt-x64-1_76.dll (-exported-)
	Location: boost_python310-vc142-mt-x64-1_76.dllboost::python::objects::static_data + 35A bytes
	Decl: struct _object * __ptr64__ cdecl boost::python::objects::static_data(void)
	Module: C:\Program Files\Autodesk\Maya2024\bin\python310.dll (-exported-)
	Location: python310.dll_PyObject_Call + 96 bytes
	Module: C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\usd_tf.dll (-exported-)
	Location: usd_tf.dllpxrInternal_v0_22 __pxrReserved__ ::TfPyEnsureGILUnlockedObj::TfPyEnsureGILUnlockedObj + 13415F bytes
	Decl: public: __cdecl pxrInternal_v0_22__ pxrReserved__::TfPyEnsureGILUnlockedObj::TfPyEnsureGILUnlockedObj(void)__ptr64
	Module: C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\boost_python310-vc142-mt-x64-1_76.dll (-exported-)
	Location: boost_python310-vc142-mt-x64-1_76.dllboost::python::objects::function::call + 2D3 bytes
	Decl: public: struct _object * __ptr64__ cdecl boost::python::objects::function::call(struct _object * __ptr64,struct _object *__ ptr64)const __ptr64
	Module: C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\boost_python310-vc142-mt-x64-1_76.dll (-exported-)
	Location: boost_python310-vc142-mt-x64-1_76.dllboost::python::objects::static_data + 2AA bytes
	Decl: struct _object * __ptr64__ cdecl boost::python::objects::static_data(void)
	Module: C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\boost_python310-vc142-mt-x64-1_76.dll (-exported-)
	Location: boost_python310-vc142-mt-x64-1_76.dllboost::python::detail::exception_handler::operator() + 3B bytes
	Decl: public: bool __cdecl boost::python::detail::exception_handler::operator()(class boost::function0<void> const &__ptr64)const __ptr64
	Module: C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\python\pxr\Tf\_tf.pyd (-exported-)
	Location: _tf.pydpxrInternal_v0_22 __pxrReserved__ ::tfTestStaticTokens_StaticTokenType::tfTestStaticTokens_StaticTokenType + 619F0 bytes
	Decl: public: __cdecl pxrInternal_v0_22__ pxrReserved__::tfTestStaticTokens_StaticTokenType::tfTestStaticTokens_StaticTokenType(void)__ptr64
	Module: C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\boost_python310-vc142-mt-x64-1_76.dll (-exported-)
	Location: boost_python310-vc142-mt-x64-1_76.dllboost::python::handle_exception_impl + 47 bytes
	Decl: bool __cdecl boost::python::handle_exception_impl(class boost::function0<void>)
	Module: C:\Program Files\Autodesk\MayaUSD\Maya2024\0.26.0_202311130904-e634cda\mayausd\USD\lib\boost_python310-vc142-mt-x64-1_76.dll (-exported-)
	Location: boost_python310-vc142-mt-x64-1_76.dllboost::python::objects::static_data + 35A bytes
	Decl: struct _object * __ptr64__ cdecl boost::python::objects::static_data(void)

```

It also crashes outside of Maya in Python with `usd-core` but I’m not sure how to get such a crash dump there.

---

<div class="post-metadata">

**Author:** ![BigRoyNL](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.aousd.org/bigroynl/32/413_2.png) [@BigRoyNL](https://forum.aousd.org/u/BigRoyNL)\
**Post date:** [December 1, 2023, 12:51pm UTC](https://forum.aousd.org/t/perform-namespace-edit-inside-a-variant-set-edit-target/1006/2 "2023-12-01T12:51:37Z")

</div>

It seems fine to access the PrimSpec through the `Sdf.Layer` instead of going through the `Usd.Prim.GetPrimStack()`

```python
def debug(path):
    print("{:<30} {}".format(path.pathString, layer.GetPrimAtPath(path)))

layer.Traverse("/", debug)

```

Which prints:

```auto
/root{model=main}new_name Sdf.Find('anon:000001E0BA91E820:tmp.usda', '/root{model=main}new_name')
/root{model=main} Sdf.Find('anon:000001E0BA91E820:tmp.usda', '/root{model=main}')
/root{model=damaged} Sdf.Find('anon:000001E0BA91E820:tmp.usda', '/root{model=damaged}')
/root{model=ice} Sdf.Find('anon:000001E0BA91E820:tmp.usda', '/root{model=ice}')
/root{model=} None
/root Sdf.Find('anon:000001E0BA91E820:tmp.usda', '/root')
/ Sdf.Find('anon:000001E0BA91E820:tmp.usda', '/')

```

Still - any app is likely to crash as soon as it starts touching the prim stacks, etc.

---

<div class="post-metadata">

**Author:** ![BigRoyNL](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.aousd.org/bigroynl/32/413_2.png) [@BigRoyNL](https://forum.aousd.org/u/BigRoyNL)\
**Post date:** [December 1, 2023, 1:41pm UTC](https://forum.aousd.org/t/perform-namespace-edit-inside-a-variant-set-edit-target/1006/3 "2023-12-01T13:41:01Z")

</div>

I wonder if this hints to anything, for the crashing prim when using `prim.GetPrimStack()` ⚠ :

- the `Usd.Prim.GetPrimIndex()` returns `None`
- however it is considered valid `Usd.Prim.IsValid() == True`.
- this also crashes: `Usd.Prim.ComputeExpandedPrimIndex()` ⚠

---

<div class="post-metadata">

**Author:** ![spiff](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.aousd.org/spiff/32/22_2.png) [@spiff](https://forum.aousd.org/u/spiff)\
**Post date:** [December 4, 2023, 6:07am UTC](https://forum.aousd.org/t/perform-namespace-edit-inside-a-variant-set-edit-target/1006/4 "2023-12-04T06:07:50Z")

</div>

Would you mind filing this as an Issue on GitHub, @BigRoyNL ? This is timely as we are implementing namespace editing at the Usd stage/prim/property level, and it’ll be good to ensure test coverage of name-editing within a variant when that’s the selected EditTarget.

---

<div class="post-metadata">

**Author:** ![BigRoyNL](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.aousd.org/bigroynl/32/413_2.png) [@BigRoyNL](https://forum.aousd.org/u/BigRoyNL)\
**Post date:** [December 4, 2023, 9:07am UTC](https://forum.aousd.org/t/perform-namespace-edit-inside-a-variant-set-edit-target/1006/5 "2023-12-04T09:07:52Z")

</div>

Created the issue here: [Crash on namespace edit inside a variant edit target · Issue #2844 · PixarAnimationStudios/OpenUSD · GitHub](https://github.com/PixarAnimationStudios/OpenUSD/issues/2844)

Would love to know if there’s any workaround to maybe somehow invalidate the Prim’s Index (`PcpPrimIndex`).

---

<div class="post-metadata">

**Author:** ![spiff](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.aousd.org/spiff/32/22_2.png) [@spiff](https://forum.aousd.org/u/spiff)\
**Post date:** [December 4, 2023, 5:58pm UTC](https://forum.aousd.org/t/perform-namespace-edit-inside-a-variant-set-edit-target/1006/6 "2023-12-04T17:58:52Z")

</div>

We will prioritize looking into this… the only thing I can suggest _trying_ is, just before you do the Sdf-level name changing, **deactivate** `</root>` on the Stage - note it must be an ancestor of the prim you want to rename, and _not_ the prim itself. This will cause the stage to completely forget about the source prim. After performing the edit, re-activate `</root>`, and _hopefully_ the stage will re-index all of the child locations properly, and populate them on the stage. 🤞

---

<div class="post-metadata">

**Author:** ![BigRoyNL](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.aousd.org/bigroynl/32/413_2.png) [@BigRoyNL](https://forum.aousd.org/u/BigRoyNL)\
**Post date:** [December 4, 2023, 7:32pm UTC](https://forum.aousd.org/t/perform-namespace-edit-inside-a-variant-set-edit-target/1006/7 "2023-12-04T19:32:27Z")

</div>

Actually, that does work - even if you do it after the rename but before accessing the prim stack again.

Here are some examples that do **not** crash:

> **Deactivate/Reactivate parent after if \`GetPrimIndex\` is None (Click to expand)**
>
> ```python
> from pxr import Usd, Sdf
> 
> # Create a stage with a root xform
> stage = Usd.Stage.CreateInMemory()
> prim = stage.DefinePrim("/root", "Xform")
> 
> # Add variant set
> variant_sets = prim.GetVariantSets()
> variant_set = variant_sets.AddVariantSet("model")
> 
> # Add some variants
> variant_set.AddVariant("main")
> variant_set.AddVariant("damaged")
> variant_set.AddVariant("ice")
> 
> # Set the variant selection
> variant_set.SetVariantSelection("main")
> 
> edit_target = variant_set.GetVariantEditTarget()
> stage.SetEditTarget(edit_target)
> 
> child = stage.DefinePrim("/root/child", "Xform")
> spec = next(iter(child.GetPrimStack())) # there is only one prim spec in this case, it's in the variant set
> assert spec.path == '/root{model=main}child'
> 
> # Rename, keep parent
> edit = Sdf.NamespaceEdit.Rename(
> spec.path,
> "new_name"
> )
> 
> layer = spec.layer
> batch_edit = Sdf.BatchNamespaceEdit()
> batch_edit.Add(edit)
> layer.Apply(batch_edit)
> 
> # Avoid crash by deactivating + reactivating the parent
> # to hopefully re-index the child locations and populate
> # them on the stage
> child = stage.GetPrimAtPath("/root/new_name")
> if child.GetPrimIndex() is None:
> parent = child.GetParent()
> parent.SetActive(False)
> parent.SetActive(True)
> 
> child = stage.GetPrimAtPath("/root/new_name")
> assert child, "Renamed child must exist"
> assert not stage.GetPrimAtPath("/root/child"), "Old prim name must not exist"
> prim_stack = child.GetPrimStack()
> print(prim_stack)
> 
> ```

> **Deactivate parent in context manager during \`layer.Apply(batch\_edit)\` (Click to expand)**
>
> ```python
> import contextlib
> from pxr import Usd, Sdf
> 
> @contextlib.contextmanager
> def deactivated_parent(prim: Usd.Prim):
> """Deactivate parent during context if it's currently active"""
> parent = prim.GetParent()
> was_active = parent.IsActive()
> if was_active:
> parent.SetActive(False)
> try:
> yield
> finally:
> if was_active:
> parent.SetActive(was_active)
> 
> # Create a stage with a root xform
> stage = Usd.Stage.CreateInMemory()
> prim = stage.DefinePrim("/root", "Xform")
> 
> # Add variant set
> variant_sets = prim.GetVariantSets()
> variant_set = variant_sets.AddVariantSet("model")
> 
> # Add some variants
> variant_set.AddVariant("main")
> variant_set.AddVariant("damaged")
> variant_set.AddVariant("ice")
> 
> # Set the variant selection
> variant_set.SetVariantSelection("main")
> 
> edit_target = variant_set.GetVariantEditTarget()
> stage.SetEditTarget(edit_target)
> 
> child = stage.DefinePrim("/root/child", "Xform")
> spec = next(iter(child.GetPrimStack())) # there is only one prim spec in this case, it's in the variant set
> assert spec.path == '/root{model=main}child'
> 
> # Rename, keep parent
> edit = Sdf.NamespaceEdit.Rename(
> spec.path,
> "new_name"
> )
> 
> layer = spec.layer
> batch_edit = Sdf.BatchNamespaceEdit()
> batch_edit.Add(edit)
> 
> with deactivated_parent(child):
> layer.Apply(batch_edit)
> 
> child = stage.GetPrimAtPath("/root/new_name")
> assert child, "Renamed child must exist"
> assert not stage.GetPrimAtPath("/root/child"), "Old prim name must not exist"
> prim_stack = child.GetPrimStack()
> print(prim_stack)
> 
> ```

> **Set parent inactive/reactive for all new paths of batch edit edits\` (Click to expand)**
>
> ```python
> from pxr import Usd, Sdf
> 
> def fix_invalid_prim_indices_after_batch_edit(stage, batch_edit):
> for edit in batch_edit.edits:
> prim = stage.GetPrimAtPath(edit.newPath.StripAllVariantSelections())
> if prim and prim.GetPrimIndex() is None:
> parent = prim.GetParent()
> parent.SetActive(False)
> parent.SetActive(True)
> 
> # Create a stage with a root xform
> stage = Usd.Stage.CreateInMemory()
> prim = stage.DefinePrim("/root", "Xform")
> 
> # Add variant set
> variant_sets = prim.GetVariantSets()
> variant_set = variant_sets.AddVariantSet("model")
> 
> # Add some variants
> variant_set.AddVariant("main")
> variant_set.AddVariant("damaged")
> variant_set.AddVariant("ice")
> 
> # Set the variant selection
> variant_set.SetVariantSelection("main")
> 
> edit_target = variant_set.GetVariantEditTarget()
> stage.SetEditTarget(edit_target)
> 
> child = stage.DefinePrim("/root/child", "Xform")
> spec = next(iter(child.GetPrimStack())) # there is only one prim spec in this case, it's in the variant set
> assert spec.path == '/root{model=main}child'
> 
> # Rename, keep parent
> edit = Sdf.NamespaceEdit.Rename(
> spec.path,
> "new_name"
> )
> 
> layer = spec.layer
> batch_edit = Sdf.BatchNamespaceEdit()
> batch_edit.Add(edit)
> 
> layer.Apply(batch_edit)
> fix_invalid_prim_indices_after_batch_edit(stage, batch_edit)
> 
> child = stage.GetPrimAtPath("/root/new_name")
> assert child, "Renamed child must exist"
> assert not stage.GetPrimAtPath("/root/child"), "Old prim name must not exist"
> prim_stack = child.GetPrimStack()
> print(prim_stack)
> 
> ```

I’ve found the deactivate/reactivate afterwards directly to be more reliable somehow.
