I’m trying to use the Sdf.CopySpec
function to copy some specs around but “merge them into existing” prims instead of completely obliterating child prims or properties that already exist but are not in the copied data.
As far as I understand I should be able to do so by providing it the should copy value and should copy children functions so I can return what it should do.
However, I’m not sure in the should_copy_children_fn
how to get the children_field
from the Sdf.PrimSpec
. It seems I can only access that metadata on a composed Usd.Prim
?
Here’s a quick reproducable:
from pxr import Usd, Sdf
import pprint
import logging
stage = Usd.Stage.CreateInMemory()
prim = stage.DefinePrim("/A", "Xform")
prim = stage.DefinePrim("/A/A", "Xform")
prim = stage.DefinePrim("/B", "Xform")
prim = stage.DefinePrim("/B/B", "Xform")
layer = stage.GetRootLayer()
def report_errors(fn):
"""Decorator that logs any errors raised by the function.
This can be useful for functions that are connected to e.g. USD's
callbacks that do not output the full error if any occurs.
"""
def wrap(*args, **kwargs):
try:
return fn(*args, **kwargs)
except Exception as exc:
logging.error(exc, exc_info=sys.exc_info())
raise RuntimeError(f"Error from {fn}") from exc
return wrap
@report_errors
def should_copy_value_fn(
spec_type: Sdf.SpecType,
field: str,
src_layer: Sdf.Layer,
src_path: Sdf.Path,
field_in_src: bool,
dest_layer: Sdf.Layer,
dest_path: Sdf.Path,
field_in_dest: bool
):
print("\nshould_copy_value_fn()")
pprint.pprint(locals())
return True
@report_errors
def should_copy_children_fn(
children_field: str,
src_layer: Sdf.Layer,
src_path: Sdf.Path,
field_in_src: bool,
dest_layer: Sdf.Layer,
dest_path: Sdf.Path,
field_in_dest: bool):
print("\should_copy_children_fn()")
pprint.pprint(locals())
if field_in_dest and not field_in_src:
# Keep dest
return False
if field_in_dest and field_in_src:
# Merge values, append copied after source values
# QUESTION: How do I do this without a `Usd.Stage. but using only the `Sdf.PrimSpec`?
src_stage = Usd.Stage.Open(src_layer)
prim = src_stage.GetPrimAtPath(src_path)
src_children = prim.GetMetadata(children_field)
dest_stage = Usd.Stage.Open(dest_layer)
prim = dest_stage.GetPrimAtPath(dest_path)
dest_children = prim.GetMetadata(children_field)
return True, src_children, src_children + dest_children
return True
Sdf.CopySpec(layer, Sdf.Path("/A"), layer, Sdf.Path("/B"), should_copy_value_fn, should_copy_children_fn)
# These should all exist
# B/A should be newly created -> copied over
print(stage.GetPrimAtPath("/A"))
print(stage.GetPrimAtPath("/A/A"))
print(stage.GetPrimAtPath("/B/A"))
print(stage.GetPrimAtPath("/B/B"))
Note that it has quite a few prints to for debugging purposes for the behavior of these calls.