示例#1
0
    def test_NewUsdLayer(self):
        def _TestNewLayer(layer, expectedFileFormat):
            """Check that the new layer was created successfully and its file
            format is what we expect."""
            self.assertTrue(layer)
            self.assertEqual(layer.GetFileFormat(), Sdf.FileFormat.FindById('usd'))

            # Write something to the layer to ensure it's functional.
            primSpec = Sdf.PrimSpec(layer, 'Scope', Sdf.SpecifierDef, 'Scope')
            self.assertTrue(primSpec)

            # Ensure the layer is saved to disk, then check that its
            # underlying file format matches what we expect.
            self.assertTrue(layer.Save())
            self.assertEqual(GetUnderlyingUsdFileFormat(layer), expectedFileFormat)

        usdFileFormat = Sdf.FileFormat.FindById('usd')

        # Newly-created .usd layers default to the USD_DEFAULT_FILE_FORMAT format.
        _TestNewLayer(Sdf.Layer.CreateNew('testNewUsdLayer.usd'),
                      Tf.GetEnvSetting('USD_DEFAULT_FILE_FORMAT'))
        _TestNewLayer(Sdf.Layer.New(usdFileFormat, 'testNewUsdLayer_2.usd'),
                      Tf.GetEnvSetting('USD_DEFAULT_FILE_FORMAT'))

        # Verify that file format arguments can be used to control the
        # underlying file format for new .usd layers.
        _TestNewLayer(Sdf.Layer.CreateNew('testNewUsdLayer_text.usd',
                                         args={'format':'usda'}), 'usda')
        _TestNewLayer(Sdf.Layer.New(usdFileFormat, 'testNewUsdLayer_text_2.usd',
                                   args={'format':'usda'}), 'usda')

        _TestNewLayer(Sdf.Layer.CreateNew('testNewUsdLayer_crate.usd',
                                         args={'format':'usdc'}), 'usdc')
        _TestNewLayer(Sdf.Layer.New(usdFileFormat, 'testNewUsdLayer_crate_2.usd',
                                   args={'format':'usdc'}), 'usdc')
    def testError(self):
        """Simulate error in non-Python-invoked code by using
        Tf.RepostErrors."""
        self._StartRecording()
        try:
            Tf.RaiseCodingError("blah")
        except Tf.ErrorException as e:
            Tf.RepostErrors(e)
        log = self._StopRecording()
        self.assertEqual(len(log), 1)
        logText, logCode = log[0]

        # When this test is executed as a result of the unittest.main() call at
        # the bottom of this file (e.g. when this script is executed directly
        # via the shebang, when the script file is passed to a Python
        # interpreter on the command-line, or when the script file's contents
        # is read and executed through compile() and exec(), the module will be
        # reported as "__main__". Otherwise, when this file is imported as a
        # module and then executed using unittest.main(module=<module name>),
        # the module name will match the file name and be reported as
        # "testDiagnosticDelegate". We make the regex here recognize both
        # cases.
        if (Tf.GetEnvSetting('MAYAUSD_SHOW_FULL_DIAGNOSTICS')):
            self.assertRegex(
                logText, "^Python coding error: blah -- Coding Error in "
                "(__main__|testDiagnosticDelegate)\.testError at line [0-9]+ of "
            )
        else:
            self.assertEqual(logText, "Python coding error: blah")

        self.assertEqual(logCode, OM.MCommandMessage.kError)
示例#3
0
    def test_StageMaskDependencyExpansion(self):
        """
        Tests dependency based (rels, attr connections) population expansion.
        """
        if not (Tf.GetEnvSetting("GUSD_STAGEMASK_ENABLE")
                and Tf.GetEnvSetting("GUSD_STAGEMASK_EXPANDRELS")):
            return

        path = "test.usda"
        cache = Gusd.StageCache()

        prim, stage = GetPrim(cache, path, "/Root/Component/B")

        # External prim should have been detected as a dependency and
        # included in the mask.
        assert Sdf.Path("/Root/ExternalDependency") in \
            stage.GetPopulationMask().GetPaths()

        # Make sure the mask composed prims as expected.
        assert stage.GetPrimAtPath("/Root/ExternalDependency")
        assert not stage.GetPrimAtPath("/Root/NonReferencedPrim")
        assert not stage.GetPrimAtPath("/Root2")
示例#4
0
    def test_StageMaskComponentExpansion(self):
        """
        Tests kind-based population mask expansion.
        """
        if not Tf.GetEnvSetting("GUSD_STAGEMASK_ENABLE"):
            return

        path = "test.usda"
        cache = Gusd.StageCache()

        prim, stage = GetPrim(cache, path, "/Root/Component/A")

        # Mask should have been expanded to include full /Root/Component.
        assert Sdf.Path("/Root/Component") in \
            stage.GetPopulationMask().GetPaths()

        # Make sure the mask composed prims as expected.
        assert stage.GetPrimAtPath("/Root/Component/B")
        assert not stage.GetPrimAtPath("/Root/NonReferencedPrim")
        assert not stage.GetPrimAtPath("/Root2")

        if not Tf.GetEnvSetting("GUSD_STAGEMASK_EXPANDRELS"):
            assert not stage.GetPrimAtPath("/Root/ExternalDependency")
示例#5
0
 def test_ValidClipMetadata(self):
     clipPrim = self.rootLayer.GetPrimAtPath(self.clipPath)
     self.assertTrue(clipPrim)
     if Tf.GetEnvSetting('USD_AUTHOR_LEGACY_CLIPS'):
         self.assertEqual(set(clipPrim.ListInfoKeys()), set(['clipTimes',
             'clipAssetPaths', 'clipPrimPath', 'clipManifestAssetPath',
             'clipActive', 'specifier']))
     else:
         self.assertEqual(set(clipPrim.ListInfoKeys()), 
                          set(['clips', 'specifier']))
         self.assertEqual(set(clipPrim.GetInfo('clips').keys()),
                          set(['default']))
         self.assertEqual(set(clipPrim.GetInfo('clips')['default'].keys()),
                          set(['times', 'assetPaths', 'primPath', 
                               'manifestAssetPath', 'active']))
示例#6
0
    def testProxyShapeBoundingBox(self):
        mayaFile = os.path.abspath('ProxyShape.ma')
        cmds.file(mayaFile, open=True, force=True)

        # Verify that the proxy shape read something from the USD file.
        bboxSize = cmds.getAttr('Cube_usd.boundingBoxSize')[0]
        self.assertEqual(bboxSize, (1.0, 1.0, 1.0))

        # The VP2 render delegate doesn't use additional proxy shape
        if not Tf.GetEnvSetting('VP2_RENDER_DELEGATE_PROXY'):
            # The proxy shape is imaged by the pxrHdImagingShape, which should be
            # created by the proxy shape's postConstructor() method. Make sure the
            # pxrHdImagingShape (and its parent transform) exist.
            hdImagingTransformPath = '|HdImaging'
            hdImagingShapePath = '%s|HdImagingShape' % hdImagingTransformPath

            self.assertTrue(cmds.objExists(hdImagingTransformPath))
            self.assertEqual(cmds.nodeType(hdImagingTransformPath),
                             'transform')

            self.assertTrue(cmds.objExists(hdImagingShapePath))
            self.assertEqual(cmds.nodeType(hdImagingShapePath),
                             'pxrHdImagingShape')

            self.assertNotEqual(cmds.ls(hdImagingTransformPath, uuid=True),
                                cmds.ls(hdImagingShapePath, uuid=True))

        # The pxrHdImagingShape and its parent transform are set so that they
        # do not write to the Maya scene file and are not exported by
        # usdExport, so do a test export and make sure that's the case.
        usdFilePath = os.path.abspath('ProxyShapeExportTest.usda')
        cmds.usdExport(file=usdFilePath)

        usdStage = Usd.Stage.Open(usdFilePath)
        prim = usdStage.GetPrimAtPath('/HdImaging')
        self.assertFalse(prim)
        prim = usdStage.GetPrimAtPath('/HdImaging/HdImagingShape')
        self.assertFalse(prim)

        # Make sure that we can reorder root nodes in the scene with the
        # pxrHdImagingShape present.
        cmds.polyCube(n="testNode1")
        cmds.polyCube(n="testNode2")
        cmds.reorder("testNode1", back=True)
        cmds.reorder("testNode2", front=True)
    def _ValidateSelection(self, expectedSelectionSet):
        if not Tf.GetEnvSetting('MAYAUSD_DISABLE_VP2_RENDER_DELEGATE'):
            # When the Viewport 2.0 render delegate is being used, we will have
            # selected USD prims rather than proxy shape nodes or their
            # transform nodes, so we query UFE for the selection and manipulate
            # the paths of the selected scene items to yield the Maya-side
            # selection.
            ufeSelection = ufe.GlobalSelection.get()
            self.assertEqual(len(ufeSelection), len(expectedSelectionSet))

            # Pop the USD root prim name, and then the proxy shape name off of
            # the UFE path to leave the name of the proxy shape's transform
            # node at the end of the path.
            ufePaths = [ufeItem.path().pop().pop() for ufeItem in ufeSelection]
            actualSelectionSet = {str(ufePath.back()) for ufePath in ufePaths}
        else:
            actualSelectionSet = set(cmds.ls(selection=True) or [])

        self.assertEqual(actualSelectionSet, expectedSelectionSet)
示例#8
0
    def test_StageMaskPreemption(self):
        """
        Test that the presence of a full stage on the cache preempts
        the use of masked stage queries.
        """
        if not Tf.GetEnvSetting("GUSD_STAGEMASK_ENABLE"):
            return

        path = "test.usda"
        cache = Gusd.StageCache()

        # Pre-populate a complete stage on the cache.
        stage = FindOrOpen(cache, path)

        # Individual prim queries should now return the same stage.
        assert GetPrim(cache, path, "/Root/Component")[1] == stage
        assert GetPrim(cache, path, "/Root/NonReferencedPrim")[1] == stage
        assert GetPrim(cache, path, "/Root/ExternalDependency")[1] == stage
        assert GetPrim(cache, path, "/Root/ModelWithVariants")[1] == stage
示例#9
0
    def test_StageMaskRootExpansion(self):
        """
        Test the fallback behavior of expanding to the root in
        componentless hierarchcies.
        """
        if not Tf.GetEnvSetting("GUSD_STAGEMASK_ENABLE"):
            return

        path = "test.usda"
        cache = Gusd.StageCache()

        prim, stage = GetPrim(cache, path, "/Root/ComponentlessHierarchy")

        # Since there's no component as an ancestor or descendant
        # of this prim, we should have expanded out to the full stage.
        assert stage.GetPopulationMask().GetPaths() == \
            [Sdf.Path.absoluteRootPath]

        # Make sure the mask composed prims as expected.
        assert stage.GetPrimAtPath("/Root")
        assert stage.GetPrimAtPath("/Root2")
示例#10
0
    def test_StageMaskDescendantComponentExpansion(self):
        """
        Tests kind-based population mask expansion when expanding
        a primitve that contains a descendant that is a component.
        """
        if not Tf.GetEnvSetting("GUSD_STAGEMASK_ENABLE"):
            return

        path = "test.usda"
        cache = Gusd.StageCache()

        prim, stage = GetPrim(cache, path, "/Root")

        # Since /Root contains a component prim, expansion should
        # have gone no further than /Root.

        assert stage.GetPopulationMask().GetPaths() == [Sdf.Path("/Root")]

        # Make sure the mask composed prims as expected.
        assert stage.GetPrimAtPath("/Root")
        assert not stage.GetPrimAtPath("/Root2")
示例#11
0
    def test_Export(self):
        # Verify that exporting to a .usd file produces the default usd file format.
        composed = Usd.Stage.Open("root.usd")
        assert composed.Export('TestExport.usd')

        newFileName = 'TestExport.' + Tf.GetEnvSetting(
            'USD_DEFAULT_FILE_FORMAT')
        shutil.copyfile('TestExport.usd', newFileName)
        assert Sdf.Layer.FindOrOpen(newFileName)

        # Verify that exporting to a .usd file but specifying ASCII
        # via file format arguments produces an ASCII file.
        assert composed.Export('TestExport_ascii.usd', args={'format': 'usda'})

        shutil.copyfile('TestExport_ascii.usd', 'TestExport_ascii.usda')
        assert Sdf.Layer.FindOrOpen('TestExport_ascii.usda')

        # Verify that exporting to a .usd file but specifying crate
        # via file format arguments produces a usd crate file.
        assert composed.Export('TestExport_crate.usd', args={'format': 'usdc'})

        shutil.copyfile('TestExport_crate.usd', 'TestExport_crate.usdc')
        assert Sdf.Layer.FindOrOpen('TestExport_crate.usdc')
示例#12
0
    def test_Clear(self):
        """
        Tests cache clearing.
        """
        path = "test.usda"
        cache = Gusd.StageCache()

        stage = FindOrOpen(cache, path)
        assert stage

        stage2 = cache.Find(path)

        cache.Clear(["test.usda"])
        # should not longer find the stage on the cache.
        assert not cache.Find("test.usda")
        assert not cache.FindStages(["test.usda"])
        # but our stage variable should still be valid.
        assert stage

        if Tf.GetEnvSetting("GUSD_STAGEMASK_ENABLE"):
            # Make sure this clearing behavior extends to masked stages.

            prim, primStage = GetPrim(cache, path, "/Root/Component")

            cache.Clear(["test.usda"])

            assert not cache.Find("test.usda")
            assert not cache.FindStages(["test.usda"])

            assert prim
            assert primStage

            # the above primStage should be the only stage reference;
            # release it, and our prim should expire.
            primStage = None
            assert not prim
示例#13
0
class TestPcpChanges(unittest.TestCase):
    def test_EmptySublayerChanges(self):
        subLayer1 = Sdf.Layer.CreateAnonymous()
        primSpec = Sdf.CreatePrimInLayer(subLayer1, '/Test')

        rootLayer = Sdf.Layer.CreateAnonymous()
        rootLayer.subLayerPaths.append(subLayer1.identifier)

        layerStackId = Pcp.LayerStackIdentifier(rootLayer)
        pcp = Pcp.Cache(layerStackId)

        (pi, err) = pcp.ComputePrimIndex('/Test')
        self.assertFalse(err)
        self.assertEqual(pi.primStack, [primSpec])

        subLayer2 = Sdf.Layer.CreateAnonymous()
        self.assertTrue(subLayer2.empty)

        # Adding an empty sublayer should not require recomputing any
        # prim indexes or change their prim stacks.
        with Pcp._TestChangeProcessor(pcp):
            rootLayer.subLayerPaths.insert(0, subLayer2.identifier)

        pi = pcp.FindPrimIndex('/Test')
        self.assertTrue(pi)
        self.assertEqual(pi.primStack, [primSpec])

        # Same with deleting an empty sublayer.
        with Pcp._TestChangeProcessor(pcp):
            del rootLayer.subLayerPaths[0]

        pi = pcp.FindPrimIndex('/Test')
        self.assertTrue(pi)
        self.assertEqual(pi.primStack, [primSpec])

    def test_InvalidSublayerAdd(self):
        invalidSublayerId = "/tmp/testPcpChanges_invalidSublayer.sdf"

        layer = Sdf.Layer.CreateAnonymous()
        layerStackId = Pcp.LayerStackIdentifier(layer)
        pcp = Pcp.Cache(layerStackId)

        (layerStack, errs) = pcp.ComputeLayerStack(layerStackId)
        self.assertEqual(len(errs), 0)
        self.assertEqual(len(layerStack.localErrors), 0)

        with Pcp._TestChangeProcessor(pcp):
            layer.subLayerPaths.append(invalidSublayerId)

        (layerStack, errs) = pcp.ComputeLayerStack(layerStackId)
        # This is potentially surprising. Layer stacks are recomputed
        # immediately during change processing, so any composition
        # errors generated during that process won't be reported
        # during the call to ComputeLayerStack. The errors will be
        # stored in the layer stack's localErrors field, however.
        self.assertEqual(len(errs), 0)
        self.assertEqual(len(layerStack.localErrors), 1)

    def test_InvalidSublayerRemoval(self):
        invalidSublayerId = "/tmp/testPcpChanges_invalidSublayer.sdf"

        layer = Sdf.Layer.CreateAnonymous()
        layer.subLayerPaths.append(invalidSublayerId)

        layerStackId = Pcp.LayerStackIdentifier(layer)
        pcp = Pcp.Cache(layerStackId)

        (layerStack, errs) = pcp.ComputeLayerStack(layerStackId)
        self.assertEqual(len(errs), 1)
        self.assertEqual(len(layerStack.localErrors), 1)
        self.assertTrue(pcp.IsInvalidSublayerIdentifier(invalidSublayerId))

        with Pcp._TestChangeProcessor(pcp):
            layer.subLayerPaths.remove(invalidSublayerId)

        (layerStack, errs) = pcp.ComputeLayerStack(layerStackId)
        self.assertEqual(len(errs), 0)
        self.assertEqual(len(layerStack.localErrors), 0)
        self.assertFalse(pcp.IsInvalidSublayerIdentifier(invalidSublayerId))

    def test_UnusedVariantChanges(self):
        layer = Sdf.Layer.CreateAnonymous()
        parent = Sdf.PrimSpec(layer, 'Root', Sdf.SpecifierDef, 'Scope')
        vA = Sdf.CreateVariantInLayer(layer, parent.path, 'var', 'A')
        vB = Sdf.CreateVariantInLayer(layer, parent.path, 'var', 'B')
        parent.variantSelections['var'] = 'A'

        layerStackId = Pcp.LayerStackIdentifier(layer)
        pcp = Pcp.Cache(layerStackId)

        (pi, err) = pcp.ComputePrimIndex('/Root')
        self.assertTrue(pi)
        self.assertEqual(len(err), 0)

        # Add a new prim spec inside the unused variant and verify that this
        # does not cause the cached prim index to be blown.
        with Pcp._TestChangeProcessor(pcp):
            newPrim = Sdf.PrimSpec(vB.primSpec, 'Child', Sdf.SpecifierDef,
                                   'Scope')

        self.assertTrue(pcp.FindPrimIndex('/Root'))

    def test_SublayerOffsetChanges(self):
        rootLayerPath = 'TestSublayerOffsetChanges/root.sdf'
        rootSublayerPath = 'TestSublayerOffsetChanges/root-sublayer.sdf'
        refLayerPath = 'TestSublayerOffsetChanges/ref.sdf'
        refSublayerPath = 'TestSublayerOffsetChanges/ref-sublayer.sdf'
        ref2LayerPath = 'TestSublayerOffsetChanges/ref2.sdf'

        rootLayer = Sdf.Layer.FindOrOpen(rootLayerPath)
        pcp = Pcp.Cache(Pcp.LayerStackIdentifier(rootLayer))

        (pi, err) = pcp.ComputePrimIndex('/A')
        self.assertTrue(pi)
        self.assertEqual(len(err), 0)

        # Verify the expected structure of the test asset. It should simply be
        # a chain of two references, with layer offsets of 100.0 and 50.0
        # respectively.
        refNode = pi.rootNode.children[0]
        self.assertEqual(
            refNode.layerStack.layers,
            [Sdf.Layer.Find(refLayerPath),
             Sdf.Layer.Find(refSublayerPath)])
        self.assertEqual(refNode.arcType, Pcp.ArcTypeReference)
        self.assertEqual(refNode.mapToRoot.timeOffset, Sdf.LayerOffset(100.0))

        ref2Node = refNode.children[0]
        self.assertEqual(ref2Node.layerStack.layers,
                         [Sdf.Layer.Find(ref2LayerPath)])
        self.assertEqual(ref2Node.arcType, Pcp.ArcTypeReference)
        self.assertEqual(ref2Node.mapToRoot.timeOffset, Sdf.LayerOffset(150.0))

        # Change the layer offset in the local layer stack and verify that
        # invalidates the prim index and that the updated layer offset is
        # taken into account after recomputing the index.
        with Pcp._TestChangeProcessor(pcp):
            rootLayer.subLayerOffsets[0] = Sdf.LayerOffset(200.0)

        self.assertFalse(pcp.FindPrimIndex('/A'))
        (pi, err) = pcp.ComputePrimIndex('/A')
        refNode = pi.rootNode.children[0]
        ref2Node = refNode.children[0]

        self.assertEqual(refNode.mapToRoot.timeOffset, Sdf.LayerOffset(200.0))
        self.assertEqual(ref2Node.mapToRoot.timeOffset, Sdf.LayerOffset(250.0))

        # Change the layer offset in a referenced layer stack and again verify
        # that the prim index is invalidated and the updated layer offset is
        # taken into account.
        refLayer = refNode.layerStack.layers[0]
        with Pcp._TestChangeProcessor(pcp):
            refLayer.subLayerOffsets[0] = Sdf.LayerOffset(200.0)

            self.assertFalse(pcp.FindPrimIndex('/A'))
            # Compute the prim index in the change processing block as the
            # changed refLayer is only being held onto by the changes' lifeboat
            # as its referencing prim index has been invalidated.
            (pi, err) = pcp.ComputePrimIndex('/A')
            refNode = pi.rootNode.children[0]
            ref2Node = refNode.children[0]

            self.assertEqual(refNode.mapToRoot.timeOffset,
                             Sdf.LayerOffset(200.0))
            self.assertEqual(ref2Node.mapToRoot.timeOffset,
                             Sdf.LayerOffset(400.0))

    def _RunTcpsChangesForLayer(self, pcpCache, layer, tcpsToExpecteOffsetsMap,
                                affectedPaths):
        """ 
        Helper function for test_TcpsChanges to run a suite of various TCPS and
        FPS metadata changes on a particular layer and verifying that the 
        correct change processing is run for every change.
        """

        # Helper function for a making a TCPS and/or FPS change and verify the
        # expected change processing, prim index invalidation, and new computed
        # values.
        def _ChangeAndVerify(newValDict, expectSignificantChange,
                             expectedTcps):

            # Just verify we have a tcps value and/or fps value to set
            self.assertTrue('tcps' in newValDict or 'fps' in newValDict)
            with Pcp._TestChangeProcessor(pcpCache) as cp:
                # Change block for when we're setting both fps and tcps
                with Sdf.ChangeBlock():
                    # Set the tcps value if present (None -> Clear)
                    if 'tcps' in newValDict:
                        val = newValDict['tcps']
                        if val is None:
                            layer.ClearTimeCodesPerSecond()
                            self.assertFalse(layer.HasTimeCodesPerSecond())
                        else:
                            layer.timeCodesPerSecond = val
                            self.assertTrue(layer.HasTimeCodesPerSecond())

                    # Set the fps value if present (None -> Clear)
                    if 'fps' in newValDict:
                        val = newValDict['fps']
                        if val is None:
                            layer.ClearFramesPerSecond()
                            self.assertFalse(layer.HasFramesPerSecond())
                        else:
                            layer.framesPerSecond = val
                            self.assertTrue(layer.HasFramesPerSecond())

                # Verify whether the change processor logged a significant
                # change for the expected affected paths or not based on
                # whether we expect a significant change.
                if expectSignificantChange:
                    self.assertEqual(cp.GetSignificantChanges(), affectedPaths)
                    # A significant change will have invalidated our
                    # prim's prim index.
                    self.assertFalse(pcpCache.FindPrimIndex('/A'))
                    # Recompute the new prim index
                    (pi, err) = pcpCache.ComputePrimIndex('/A')
                else:
                    # No significant should leave our prim's prim index
                    # valid.
                    self.assertEqual(cp.GetSignificantChanges(), [])
                    pi = pcpCache.FindPrimIndex('/A')
                    self.assertTrue(pi)

                refNode = pi.rootNode.children[0]
                ref2Node = refNode.children[0]

                # Verify the layer has the expected computed TCPS
                self.assertEqual(layer.timeCodesPerSecond, expectedTcps)
                # Verify the ref node offesets match the expected offsets
                # for the layer's expected computed TCPS.
                expectedOffsets = tcpsToExpecteOffsetsMap[expectedTcps]
                self.assertEqual(refNode.mapToRoot.timeOffset,
                                 expectedOffsets[0])
                self.assertEqual(ref2Node.mapToRoot.timeOffset,
                                 expectedOffsets[1])

        # Expect the layer to start with no authored TCPS of FPS. Verify
        # various changes to authored timeCodesPerSecond
        self.assertFalse(layer.HasTimeCodesPerSecond())
        self.assertFalse(layer.HasFramesPerSecond())
        _ChangeAndVerify({'tcps': 24.0}, False, 24.0)
        _ChangeAndVerify({'tcps': None}, False, 24.0)
        _ChangeAndVerify({'tcps': 48.0}, True, 48.0)
        _ChangeAndVerify({'tcps': 12.0}, True, 12.0)
        _ChangeAndVerify({'tcps': None}, True, 24.0)

        # Expect the layer to start with no authored TCPS of FPS again.
        # Verify various changes to authored framesPerSecond
        self.assertFalse(layer.HasTimeCodesPerSecond())
        self.assertFalse(layer.HasFramesPerSecond())
        _ChangeAndVerify({'fps': 24.0}, False, 24.0)
        _ChangeAndVerify({'fps': None}, False, 24.0)
        _ChangeAndVerify({'fps': 48.0}, True, 48.0)
        _ChangeAndVerify({'fps': 12.0}, True, 12.0)
        _ChangeAndVerify({'fps': None}, True, 24.0)

        # Change the layer to have an authored non-default framesPerSecond.
        # Verify various changes to timeCodesPerSecond.
        _ChangeAndVerify({'fps': 48.0}, True, 48.0)
        self.assertFalse(layer.HasTimeCodesPerSecond())
        self.assertTrue(layer.HasFramesPerSecond())
        self.assertEqual(layer.timeCodesPerSecond, 48.0)
        _ChangeAndVerify({'tcps': 48.0}, False, 48.0)
        _ChangeAndVerify({'tcps': None}, False, 48.0)
        _ChangeAndVerify({'tcps': 12.0}, True, 12.0)
        _ChangeAndVerify({'tcps': 24.0}, True, 24.0)
        _ChangeAndVerify({'tcps': None}, True, 48.0)

        # Change the layer to have an authored timeCodesPerSecond.
        # Verify that various changes to framesPerSecond have no effect.
        _ChangeAndVerify({'tcps': 24.0, 'fps': None}, True, 24.0)
        self.assertTrue(layer.HasTimeCodesPerSecond())
        self.assertFalse(layer.HasFramesPerSecond())
        self.assertEqual(layer.timeCodesPerSecond, 24.0)
        _ChangeAndVerify({'fps': 24.0}, False, 24.0)
        _ChangeAndVerify({'fps': None}, False, 24.0)
        _ChangeAndVerify({'fps': 48.0}, False, 24.0)
        _ChangeAndVerify({'fps': 12.0}, False, 24.0)
        _ChangeAndVerify({'fps': None}, False, 24.0)

        # Change the layer to start with an unauthored timeCodesPerSecond
        # and a non-default framesPerSecond
        # Verify various changes to timeCodesPerSecond and framesPerSecond
        # at the same time.
        _ChangeAndVerify({'tcps': None, 'fps': 48.0}, True, 48.0)
        self.assertFalse(layer.HasTimeCodesPerSecond())
        self.assertTrue(layer.HasFramesPerSecond())
        self.assertEqual(layer.timeCodesPerSecond, 48.0)
        _ChangeAndVerify({'tcps': 48.0, 'fps': None}, False, 48.0)
        _ChangeAndVerify({'tcps': None, 'fps': 48.0}, False, 48.0)
        _ChangeAndVerify({'tcps': 24.0, 'fps': None}, True, 24.0)
        _ChangeAndVerify({'tcps': None, 'fps': 48.0}, True, 48.0)
        _ChangeAndVerify({'tcps': 12.0, 'fps': None}, True, 12.0)
        _ChangeAndVerify({'tcps': 48.0, 'fps': 12.0}, True, 48.0)
        _ChangeAndVerify({'tcps': 12.0, 'fps': 48.0}, True, 12.0)
        _ChangeAndVerify({'tcps': None, 'fps': 12.0}, False, 12.0)
        _ChangeAndVerify({'tcps': 24.0, 'fps': 24.0}, True, 24.0)
        _ChangeAndVerify({'tcps': None, 'fps': None}, False, 24.0)

    @unittest.skipIf(
        Tf.GetEnvSetting('PCP_DISABLE_TIME_SCALING_BY_LAYER_TCPS'),
        "Test requires layer TCPS time scaling enabled")
    def test_TcpsChanges(self):
        """
        Tests change processing for changes that affect the time codes per
        second of all layers in the layer stacks of a PcpCache.
        """

        # Use the same layers as the sublayer offset test case.
        rootLayerPath = 'TestSublayerOffsetChanges/root.sdf'
        rootSublayerPath = 'TestSublayerOffsetChanges/root-sublayer.sdf'
        refLayerPath = 'TestSublayerOffsetChanges/ref.sdf'
        refSublayerPath = 'TestSublayerOffsetChanges/ref-sublayer.sdf'
        ref2LayerPath = 'TestSublayerOffsetChanges/ref2.sdf'

        rootLayer = Sdf.Layer.FindOrOpen(rootLayerPath)
        sessionLayer = Sdf.Layer.CreateAnonymous()
        pcp = Pcp.Cache(Pcp.LayerStackIdentifier(rootLayer, sessionLayer))

        (pi, err) = pcp.ComputePrimIndex('/A')
        self.assertTrue(pi)
        self.assertEqual(len(err), 0)

        rootSublayer = Sdf.Layer.Find(rootSublayerPath)
        refLayer = Sdf.Layer.Find(refLayerPath)
        refSublayer = Sdf.Layer.Find(refSublayerPath)
        ref2Layer = Sdf.Layer.Find(ref2LayerPath)

        # Verify the expected structure of the test asset. It should simply be
        # a chain of two references, with layer offsets of 100.0 and 50.0
        # respectively.
        self.assertEqual(pi.rootNode.layerStack.layers,
                         [sessionLayer, rootLayer, rootSublayer])

        refNode = pi.rootNode.children[0]
        self.assertEqual(refNode.layerStack.layers, [refLayer, refSublayer])
        self.assertEqual(refNode.arcType, Pcp.ArcTypeReference)
        self.assertEqual(refNode.mapToRoot.timeOffset, Sdf.LayerOffset(100.0))
        for layer in refNode.layerStack.layers:
            self.assertFalse(layer.HasTimeCodesPerSecond())
            self.assertEqual(layer.timeCodesPerSecond, 24.0)

        ref2Node = refNode.children[0]
        self.assertEqual(ref2Node.layerStack.layers, [ref2Layer])
        self.assertEqual(ref2Node.arcType, Pcp.ArcTypeReference)
        self.assertEqual(ref2Node.mapToRoot.timeOffset, Sdf.LayerOffset(150.0))
        for layer in ref2Node.layerStack.layers:
            self.assertFalse(layer.HasTimeCodesPerSecond())
            self.assertEqual(layer.timeCodesPerSecond, 24.0)

        # Run the TCPS change suite on the root layer.
        tcpsToOffsets = {
            12.0: (Sdf.LayerOffset(100.0, 0.5), Sdf.LayerOffset(125.0, 0.5)),
            24.0: (Sdf.LayerOffset(100.0), Sdf.LayerOffset(150.0)),
            48.0: (Sdf.LayerOffset(100.0, 2.0), Sdf.LayerOffset(200.0, 2.0))
        }
        self._RunTcpsChangesForLayer(pcp, rootLayer, tcpsToOffsets, ['/'])

        # Run the TCPS change suite on the first reference layer.
        tcpsToOffsets = {
            12.0: (Sdf.LayerOffset(100.0, 2.0), Sdf.LayerOffset(200.0)),
            24.0: (Sdf.LayerOffset(100.0), Sdf.LayerOffset(150.0)),
            48.0: (Sdf.LayerOffset(100.0, 0.5), Sdf.LayerOffset(125.0))
        }
        self._RunTcpsChangesForLayer(pcp, refLayer, tcpsToOffsets, ['/A'])

        # Run the TCPS change suite on the second reference layer.
        tcpsToOffsets = {
            12.0: (Sdf.LayerOffset(100.0), Sdf.LayerOffset(150.0, 2.0)),
            24.0: (Sdf.LayerOffset(100.0), Sdf.LayerOffset(150.0)),
            48.0: (Sdf.LayerOffset(100.0), Sdf.LayerOffset(150.0, 0.5))
        }
        self._RunTcpsChangesForLayer(pcp, ref2Layer, tcpsToOffsets, ['/A'])

        # Run the TCPS change suite on the sublayers of the root and reference
        # layers. In the particular setup of these layer, TCPS of either
        # sublayer doesn't change the layer offsets applied to the reference
        # nodes, but will still cause change management to report significant
        # changes to prim indexes.
        tcpsToOffsets = {
            12.0: (Sdf.LayerOffset(100.0), Sdf.LayerOffset(150.0)),
            24.0: (Sdf.LayerOffset(100.0), Sdf.LayerOffset(150.0)),
            48.0: (Sdf.LayerOffset(100.0), Sdf.LayerOffset(150.0))
        }
        self._RunTcpsChangesForLayer(pcp, rootSublayer, tcpsToOffsets, ['/'])
        self._RunTcpsChangesForLayer(pcp, refSublayer, tcpsToOffsets, ['/A'])

        # Run the TCPS change suite on the session layer.
        tcpsToOffsets = {
            12.0: (Sdf.LayerOffset(50.0, 0.5), Sdf.LayerOffset(75.0, 0.5)),
            24.0: (Sdf.LayerOffset(100.0), Sdf.LayerOffset(150.0)),
            48.0: (Sdf.LayerOffset(200.0, 2.0), Sdf.LayerOffset(300.0, 2.0))
        }
        self._RunTcpsChangesForLayer(pcp, sessionLayer, tcpsToOffsets, ['/'])

        # Special cases for the session layer when root layer has a tcps value
        rootLayer.timeCodesPerSecond = 24.0
        self.assertTrue(rootLayer.HasTimeCodesPerSecond())
        self.assertFalse(sessionLayer.HasTimeCodesPerSecond())
        with Pcp._TestChangeProcessor(pcp) as cp:
            # Set the session layer's FPS. This will change the session layer's
            # computed TCPS and is a significant change even though the overall
            # TCPS of the root layer stack is 24 as it is authored on the root
            # layer.
            sessionLayer.framesPerSecond = 48.0
            self.assertEqual(sessionLayer.timeCodesPerSecond, 48.0)
            self.assertEqual(cp.GetSignificantChanges(), ['/'])
            self.assertFalse(pcp.FindPrimIndex('/A'))
            # Recompute the new prim index
            (pi, err) = pcp.ComputePrimIndex('/A')
            refNode = pi.rootNode.children[0]
            ref2Node = refNode.children[0]
            # The reference layer offsets are still the same as authored as
            # the root layer TCPS still matches its layer stack's overall TCPS
            self.assertEqual(refNode.mapToRoot.timeOffset,
                             Sdf.LayerOffset(100.0))
            self.assertEqual(ref2Node.mapToRoot.timeOffset,
                             Sdf.LayerOffset(150.0))

        # Continuing from the previous case, root layer has TCPS set to 24 and
        # session layer has FPS set to 48. Now we set the session TCPS to 48.
        # While this does not cause a TCPS change to session layer taken by
        # itself, this does mean that the session now overrides the overall
        # TCPS of the layer stack which used to come the root. We verify here
        # that this is a significant change and that it scales the layer offsets
        # to the references.
        self.assertFalse(sessionLayer.HasTimeCodesPerSecond())
        with Pcp._TestChangeProcessor(pcp) as cp:
            sessionLayer.timeCodesPerSecond = 48.0
            self.assertEqual(sessionLayer.timeCodesPerSecond, 48.0)
            self.assertEqual(cp.GetSignificantChanges(), ['/'])
            self.assertFalse(pcp.FindPrimIndex('/A'))
            # Recompute the new prim index
            (pi, err) = pcp.ComputePrimIndex('/A')
            refNode = pi.rootNode.children[0]
            ref2Node = refNode.children[0]
            self.assertEqual(refNode.mapToRoot.timeOffset,
                             Sdf.LayerOffset(200.0, 2.0))
            self.assertEqual(ref2Node.mapToRoot.timeOffset,
                             Sdf.LayerOffset(300.0, 2.0))

        # And as a parallel to the previous case, we now clear the session TCPS
        # again. This is still no effective change to the session layer TCPS
        # itself, but root layer's TCPS is once again the overall layer stack
        # TCPS. This is significant changes and the layer offsets return to
        # their original values.
        with Pcp._TestChangeProcessor(pcp) as cp:
            sessionLayer.ClearTimeCodesPerSecond()
            self.assertEqual(sessionLayer.timeCodesPerSecond, 48.0)
            self.assertEqual(cp.GetSignificantChanges(), ['/'])
            self.assertFalse(pcp.FindPrimIndex('/A'))
            # Recompute the new prim index
            (pi, err) = pcp.ComputePrimIndex('/A')
            refNode = pi.rootNode.children[0]
            ref2Node = refNode.children[0]
            # The reference layer offsets are still the same as authored as
            # the root layer TCPS still matches its layer stack's overall TCPS
            self.assertEqual(refNode.mapToRoot.timeOffset,
                             Sdf.LayerOffset(100.0))
            self.assertEqual(ref2Node.mapToRoot.timeOffset,
                             Sdf.LayerOffset(150.0))

        # One more special case. Neither session or root layers have TCPS set.
        # Root layer has FPS set to 48, session layer has FPS set to 24. Overall
        # computed TCPS of the layer stack will be 24, matching session FPS.
        # We then author a TCPS value of 48 to the root layer, matching its FPS
        # value. There is no effective change to the root layer's TCPS itself
        # but we do end up with a significant change as the overall layer stack
        # TCPS will now compute to 48.
        sessionLayer.ClearTimeCodesPerSecond()
        rootLayer.ClearTimeCodesPerSecond()
        sessionLayer.framesPerSecond = 24.0
        rootLayer.framesPerSecond = 48.0
        with Pcp._TestChangeProcessor(pcp) as cp:
            rootLayer.timeCodesPerSecond = 48.0
            self.assertEqual(rootLayer.timeCodesPerSecond, 48.0)
            self.assertEqual(cp.GetSignificantChanges(), ['/'])
            self.assertFalse(pcp.FindPrimIndex('/A'))
            # Recompute the new prim index
            (pi, err) = pcp.ComputePrimIndex('/A')
            refNode = pi.rootNode.children[0]
            ref2Node = refNode.children[0]
            self.assertEqual(refNode.mapToRoot.timeOffset,
                             Sdf.LayerOffset(100.0, 2.0))
            self.assertEqual(ref2Node.mapToRoot.timeOffset,
                             Sdf.LayerOffset(200.0, 2.0))

    def test_DefaultReferenceTargetChanges(self):
        # create a layer, set DefaultPrim, then reference it.
        targLyr = Sdf.Layer.CreateAnonymous()

        def makePrim(name):
            primSpec = Sdf.CreatePrimInLayer(targLyr, name)
            primSpec.specifier = Sdf.SpecifierDef

        makePrim('target1')
        makePrim('target2')

        targLyr.defaultPrim = 'target1'

        def _Test(referencingLayer):
            # Make a PcpCache.
            pcp = Pcp.Cache(Pcp.LayerStackIdentifier(referencingLayer))

            (pi, err) = pcp.ComputePrimIndex('/source')

            # First child node should be the referenced target1.
            self.assertEqual(pi.rootNode.children[0].path, '/target1')

            # Now clear defaultPrim.  This should issue an error and
            # fail to pick up the referenced prim.
            with Pcp._TestChangeProcessor(pcp):
                targLyr.ClearDefaultPrim()

            (pi, err) = pcp.ComputePrimIndex('/source')
            self.assertTrue(isinstance(err[0], Pcp.ErrorUnresolvedPrimPath))
            # If the reference to the defaultPrim is an external reference,
            # the one child node should be the pseudoroot dependency placeholder.
            # If the reference is an internal reference, that dependency
            # placeholder is unneeded.
            if referencingLayer != targLyr:
                self.assertEqual(len(pi.rootNode.children), 1)
                self.assertEqual(pi.rootNode.children[0].path, '/')

            # Change defaultPrim to other target.  This should pick
            # up the reference again, but to the new prim target2.
            with Pcp._TestChangeProcessor(pcp):
                targLyr.defaultPrim = 'target2'

            (pi, err) = pcp.ComputePrimIndex('/source')
            self.assertEqual(len(err), 0)
            self.assertEqual(pi.rootNode.children[0].path, '/target2')

            # Reset defaultPrim to original target
            targLyr.defaultPrim = 'target1'

        # Test external reference case where some other layer references
        # a layer with defaultPrim specified.
        srcLyr = Sdf.Layer.CreateAnonymous()
        srcPrimSpec = Sdf.CreatePrimInLayer(srcLyr, '/source')
        srcPrimSpec.referenceList.Add(Sdf.Reference(targLyr.identifier))
        _Test(srcLyr)

        # Test internal reference case where a prim in the layer with defaultPrim
        # specified references the same layer.
        srcPrimSpec = Sdf.CreatePrimInLayer(targLyr, '/source')
        srcPrimSpec.referenceList.Add(Sdf.Reference())
        _Test(targLyr)

    def test_InternalReferenceChanges(self):
        rootLayer = Sdf.Layer.CreateAnonymous()

        Sdf.PrimSpec(rootLayer, 'target1', Sdf.SpecifierDef)
        Sdf.PrimSpec(rootLayer, 'target2', Sdf.SpecifierDef)

        srcPrimSpec = Sdf.PrimSpec(rootLayer, 'source', Sdf.SpecifierDef)
        srcPrimSpec.referenceList.Add(Sdf.Reference(primPath='/target1'))

        # Initially, the prim index for /source should contain a single
        # reference node to /target1 in rootLayer.
        pcp = Pcp.Cache(Pcp.LayerStackIdentifier(rootLayer))
        (pi, err) = pcp.ComputePrimIndex('/source')

        self.assertEqual(len(err), 0)
        self.assertEqual(
            pi.rootNode.children[0].layerStack.identifier.rootLayer, rootLayer)
        self.assertEqual(pi.rootNode.children[0].path, '/target1')

        # Modify the internal reference to point to /target2 and verify the
        # reference node is updated.
        with Pcp._TestChangeProcessor(pcp):
            srcPrimSpec.referenceList.addedItems[0] = \
                Sdf.Reference(primPath = '/target2')

        (pi, err) = pcp.ComputePrimIndex('/source')

        self.assertEqual(len(err), 0)
        self.assertEqual(
            pi.rootNode.children[0].layerStack.identifier.rootLayer, rootLayer)
        self.assertEqual(pi.rootNode.children[0].path, '/target2')

        # Clear out all references and verify that the prim index contains no
        # reference nodes.
        with Pcp._TestChangeProcessor(pcp):
            srcPrimSpec.referenceList.ClearEdits()

        (pi, err) = pcp.ComputePrimIndex('/source')

        self.assertEqual(len(err), 0)
        self.assertEqual(len(pi.rootNode.children), 0)

    def test_VariantChanges(self):
        rootLayer = Sdf.Layer.CreateAnonymous()
        modelSpec = Sdf.PrimSpec(rootLayer, 'Variant', Sdf.SpecifierDef)

        pcp = Pcp.Cache(Pcp.LayerStackIdentifier(rootLayer), usd=True)

        # Test changes that are emitted as a variant set and variant
        # are created.

        pcp.ComputePrimIndex('/Variant')
        with Pcp._TestChangeProcessor(pcp) as cp:
            varSetSpec = Sdf.VariantSetSpec(modelSpec, 'test')
            self.assertEqual(cp.GetSignificantChanges(), ['/Variant'])
            self.assertEqual(cp.GetSpecChanges(), [])
            self.assertEqual(cp.GetPrimChanges(), [])

        pcp.ComputePrimIndex('/Variant')
        with Pcp._TestChangeProcessor(pcp) as cp:
            modelSpec.variantSelections['test'] = 'A'
            self.assertEqual(cp.GetSignificantChanges(), ['/Variant'])
            self.assertEqual(cp.GetSpecChanges(), [])
            self.assertEqual(cp.GetPrimChanges(), [])

        pcp.ComputePrimIndex('/Variant')
        with Pcp._TestChangeProcessor(pcp) as cp:
            modelSpec.variantSetNameList.Add('test')
            self.assertEqual(cp.GetSignificantChanges(), ['/Variant'])
            self.assertEqual(cp.GetSpecChanges(), [])
            self.assertEqual(cp.GetPrimChanges(), [])

        pcp.ComputePrimIndex('/Variant')
        with Pcp._TestChangeProcessor(pcp) as cp:
            varSpec = Sdf.VariantSpec(varSetSpec, 'A')
            self.assertEqual(cp.GetSignificantChanges(), [])
            self.assertEqual(cp.GetSpecChanges(), ['/Variant'])
            # Creating the variant spec adds an inert spec to /Variant's prim
            # stack but does not require rebuilding /Variant's prim index to
            # account for the new variant node.
            self.assertEqual(cp.GetPrimChanges(), [])

        pcp.ComputePrimIndex('/Variant')
        with Pcp._TestChangeProcessor(pcp) as cp:
            varSpec.primSpec.referenceList.Add(
                Sdf.Reference('./dummy.sdf', '/Dummy'))
            self.assertEqual(cp.GetSignificantChanges(), ['/Variant'])
            self.assertEqual(cp.GetSpecChanges(), [])
            self.assertEqual(cp.GetPrimChanges(), [])

    # Instancing is disabled in Usd mode, so we don't test there.
    # TestInstancingChanges(usd = False)
    def test_InstancingChanges(self):
        refLayer = Sdf.Layer.CreateAnonymous()
        refParentSpec = Sdf.PrimSpec(refLayer, 'Parent', Sdf.SpecifierDef)
        refChildSpec = Sdf.PrimSpec(refParentSpec, 'RefChild',
                                    Sdf.SpecifierDef)

        rootLayer = Sdf.Layer.CreateAnonymous()
        parentSpec = Sdf.PrimSpec(rootLayer, 'Parent', Sdf.SpecifierOver)
        parentSpec.referenceList.Add(
            Sdf.Reference(refLayer.identifier, '/Parent'))
        childSpec = Sdf.PrimSpec(parentSpec, 'DirectChild', Sdf.SpecifierDef)

        pcp = Pcp.Cache(Pcp.LayerStackIdentifier(rootLayer), usd=True)

        # /Parent is initially not tagged as an instance, so we should
        # see both RefChild and DirectChild name children.
        (pi, err) = pcp.ComputePrimIndex('/Parent')
        self.assertEqual(len(err), 0)
        self.assertFalse(pi.IsInstanceable())
        self.assertEqual(pi.ComputePrimChildNames(),
                         (['RefChild', 'DirectChild'], []))

        with Pcp._TestChangeProcessor(pcp) as cp:
            parentSpec.instanceable = True
            self.assertEqual(cp.GetSignificantChanges(), ['/Parent'])
            self.assertEqual(cp.GetSpecChanges(), [])
            self.assertEqual(cp.GetPrimChanges(), [])

        # After being made an instance, DirectChild should no longer
        # be reported as a name child since instances may not introduce
        # new prims locally.
        (pi, err) = pcp.ComputePrimIndex('/Parent')
        self.assertEqual(len(err), 0)
        self.assertTrue(pi.IsInstanceable())
        self.assertEqual(pi.ComputePrimChildNames(), (['RefChild'], []))

        with Pcp._TestChangeProcessor(pcp) as cp:
            parentSpec.instanceable = False
            self.assertEqual(cp.GetSignificantChanges(), ['/Parent'])
            self.assertEqual(cp.GetSpecChanges(), [])
            self.assertEqual(cp.GetPrimChanges(), [])

        # Flipping the instance flag back should restore us to the
        # original state.
        (pi, err) = pcp.ComputePrimIndex('/Parent')
        self.assertEqual(len(err), 0)
        self.assertFalse(pi.IsInstanceable())
        self.assertEqual(pi.ComputePrimChildNames(),
                         (['RefChild', 'DirectChild'], []))

    def test_InertPrimChanges(self):
        refLayer = Sdf.Layer.CreateAnonymous()
        refParentSpec = Sdf.PrimSpec(refLayer, 'Parent', Sdf.SpecifierDef)
        refChildSpec = Sdf.PrimSpec(refParentSpec, 'Child', Sdf.SpecifierDef)

        rootLayer = Sdf.Layer.CreateAnonymous()
        parentSpec = Sdf.PrimSpec(rootLayer, 'Parent', Sdf.SpecifierOver)
        parentSpec.referenceList.Add(
            Sdf.Reference(refLayer.identifier, '/Parent'))

        pcp = Pcp.Cache(Pcp.LayerStackIdentifier(rootLayer))

        # Adding an empty over to a prim that already exists (has specs)
        # is an insignificant change.
        (pi, err) = pcp.ComputePrimIndex('/Parent/Child')
        self.assertEqual(err, [])
        with Pcp._TestChangeProcessor(pcp) as cp:
            Sdf.CreatePrimInLayer(rootLayer, '/Parent/Child')
            self.assertEqual(cp.GetSignificantChanges(), [])
            self.assertEqual(cp.GetSpecChanges(), ['/Parent/Child'])
            self.assertEqual(cp.GetPrimChanges(), [])

        # Adding an empty over as the first spec for a prim is a
        # a significant change, even if we haven't computed a prim index
        # for that path yet.
        with Pcp._TestChangeProcessor(pcp) as cp:
            Sdf.CreatePrimInLayer(rootLayer, '/Parent/NewChild')
            self.assertEqual(cp.GetSignificantChanges(), ['/Parent/NewChild'])
            self.assertEqual(cp.GetSpecChanges(), [])
            self.assertEqual(cp.GetPrimChanges(), [])

        (pi, err) = pcp.ComputePrimIndex('/Parent/NewChild2')
        self.assertEqual(err, [])
        with Pcp._TestChangeProcessor(pcp) as cp:
            Sdf.CreatePrimInLayer(rootLayer, '/Parent/NewChild2')
            self.assertEqual(cp.GetSignificantChanges(), ['/Parent/NewChild2'])
            self.assertEqual(cp.GetSpecChanges(), [])
            self.assertEqual(cp.GetPrimChanges(), [])

    def test_InertPrimRemovalChanges(self):
        subLayer = Sdf.Layer.CreateAnonymous()
        subParentSpec = Sdf.PrimSpec(subLayer, 'Parent', Sdf.SpecifierDef)
        subChildSpec = Sdf.PrimSpec(subParentSpec, 'Child', Sdf.SpecifierDef)
        subAttrSpec = Sdf.AttributeSpec(subChildSpec, 'attr',
                                        Sdf.ValueTypeNames.Double)
        subAttrSpec.default = 1.0

        rootLayer = Sdf.Layer.CreateAnonymous()
        rootParentSpec = Sdf.PrimSpec(rootLayer, 'Parent', Sdf.SpecifierOver)
        rootChildSpec = Sdf.PrimSpec(rootParentSpec, 'Child',
                                     Sdf.SpecifierOver)
        rootAttrSpec = Sdf.AttributeSpec(rootChildSpec, 'attr',
                                         Sdf.ValueTypeNames.Double)
        rootLayer.subLayerPaths.append(subLayer.identifier)

        pcp = Pcp.Cache(Pcp.LayerStackIdentifier(rootLayer))

        (pi, err) = pcp.ComputePrimIndex('/Parent')
        self.assertEqual(err, [])
        self.assertEqual(pi.primStack, [rootParentSpec, subParentSpec])

        (pi, err) = pcp.ComputePrimIndex('/Parent/Child')
        self.assertEqual(err, [])
        self.assertEqual(pi.primStack, [rootChildSpec, subChildSpec])

        (pi, err) = pcp.ComputePropertyIndex('/Parent/Child.attr')
        self.assertEqual(err, [])
        self.assertEqual(pi.propertyStack, [rootAttrSpec, subAttrSpec])

        with Pcp._TestChangeProcessor(pcp) as cp:
            del rootLayer.pseudoRoot.nameChildren['Parent']
            self.assertFalse(rootParentSpec)
            self.assertFalse(rootChildSpec)
            self.assertFalse(rootAttrSpec)

            self.assertEqual(cp.GetSignificantChanges(), [])
            self.assertEqual(
                cp.GetSpecChanges(),
                ['/Parent', '/Parent/Child', '/Parent/Child.attr'])
            self.assertEqual(cp.GetPrimChanges(), [])

        (pi, err) = pcp.ComputePrimIndex('/Parent')
        self.assertEqual(err, [])
        self.assertEqual(pi.primStack, [subParentSpec])

        (pi, err) = pcp.ComputePrimIndex('/Parent/Child')
        self.assertEqual(err, [])
        self.assertEqual(pi.primStack, [subChildSpec])

        (pi, err) = pcp.ComputePropertyIndex('/Parent/Child.attr')
        self.assertEqual(err, [])
        self.assertEqual(pi.propertyStack, [subAttrSpec])
示例#14
0
    def test_Basic(self):
        l = Sdf.Layer.CreateAnonymous()
        stage = Usd.Stage.Open(l.identifier)

        world = stage.DefinePrim("/World", "Xform")
        assert world
        world.SetMetadata('kind', 'group')
        assert world.IsModel()
        assert world.IsGroup()

        group = stage.DefinePrim("/World/Group", "Xform")
        assert group
        group.SetMetadata('kind', 'group')
        assert group.IsModel()
        assert group.IsGroup()

        model = stage.DefinePrim("/World/Group/Model", "Xform")
        assert model
        model.SetMetadata('kind', 'component')
        assert model.IsModel()

        p = stage.DefinePrim("/World/Group/Model/Mesh", "Scope")
        assert p

        print("Test Material")
        material = UsdShade.Material.Define(stage,
                                            "/World/Group/Model/Material")
        assert material
        assert material.GetPrim()
        UsdShade.MaterialBindingAPI(p).Bind(material)

        print("Test shader")
        shader = UsdRi.RslShader.Define(stage, '/World/Group/Model/Shader')
        assert shader
        assert shader.GetPrim()
        assert not UsdRi.StatementsAPI.IsRiAttribute(shader.GetSloPathAttr())
        shader.GetSloPathAttr().Set('foo')

        print("Test RiMaterialAPI")
        riMaterial = UsdRi.MaterialAPI.Apply(material.GetPrim())
        assert riMaterial
        assert riMaterial.GetPrim()

        # Test surface output
        self._TestOutput(riMaterial, UsdRi.MaterialAPI.GetSurfaceOutput,
                         UsdRi.MaterialAPI.SetSurfaceSource,
                         UsdRi.MaterialAPI.GetSurface, shader.GetPath())

        # Test displacement output
        self._TestOutput(riMaterial, UsdRi.MaterialAPI.GetDisplacementOutput,
                         UsdRi.MaterialAPI.SetDisplacementSource,
                         UsdRi.MaterialAPI.GetDisplacement, shader.GetPath())

        # Test volume output
        self._TestOutput(riMaterial, UsdRi.MaterialAPI.GetVolumeOutput,
                         UsdRi.MaterialAPI.SetVolumeSource,
                         UsdRi.MaterialAPI.GetVolume, shader.GetPath())

        print("Test pattern")
        pattern = UsdRi.RisPattern.Define(stage, '/World/Group/Model/Pattern')
        assert pattern
        assert pattern.GetPrim()
        pattern.GetFilePathAttr().Set('foo')
        self.assertEqual(pattern.GetFilePathAttr().Get(), 'foo')
        pattern.GetArgsPathAttr().Set('argspath')
        self.assertEqual(pattern.GetArgsPathAttr().Get(), 'argspath')

        print("Test oslPattern")
        oslPattern = UsdRi.RisOslPattern.Define(
            stage, '/World/Group/Model/OslPattern')
        assert oslPattern
        assert oslPattern.GetPrim()
        self.assertEqual(oslPattern.GetFilePathAttr().Get(), 'PxrOSL')

        print("Test bxdf")
        bxdf = UsdRi.RisBxdf.Define(stage, '/World/Group/Model/Bxdf')
        assert bxdf
        assert bxdf.GetPrim()
        bxdf.GetFilePathAttr().Set('foo')
        bxdf.GetArgsPathAttr().Set('argspath')

        print("Test RIS Material")
        risMaterial = UsdRi.MaterialAPI(material.GetPrim())
        assert risMaterial
        assert risMaterial.GetPrim()

        print("Test riStatements")
        riStatements = UsdRi.StatementsAPI.Apply(shader.GetPrim())
        assert riStatements
        assert riStatements.GetPrim()
        attr = riStatements.CreateRiAttribute("ModelName", "string").\
            Set('someModelName')
        assert attr
        props = riStatements.GetRiAttributes()
        assert props
        # this is so convoluted
        attr = riStatements.GetPrim().GetAttribute(props[0].GetName())
        assert attr
        prefix = ('primvars:' if
                  Tf.GetEnvSetting('USDRI_STATEMENTS_WRITE_NEW_ATTR_ENCODING')
                  else '')
        self.assertEqual(attr.GetName(),
                         prefix + 'ri:attributes:user:ModelName')
        self.assertEqual(attr.Get(), 'someModelName')
        self.assertEqual(UsdRi.StatementsAPI.GetRiAttributeName(attr),
                         'ModelName')
        self.assertEqual(UsdRi.StatementsAPI.GetRiAttributeNameSpace(attr),
                         'user')
        assert UsdRi.StatementsAPI.IsRiAttribute(attr)

        self.assertEqual(
            UsdRi.StatementsAPI.MakeRiAttributePropertyName('myattr'),
            prefix + 'ri:attributes:user:myattr')
        self.assertEqual(
            UsdRi.StatementsAPI.MakeRiAttributePropertyName('dice:myattr'),
            prefix + 'ri:attributes:dice:myattr')
        self.assertEqual(
            UsdRi.StatementsAPI.MakeRiAttributePropertyName('dice.myattr'),
            prefix + 'ri:attributes:dice:myattr')
        self.assertEqual(
            UsdRi.StatementsAPI.MakeRiAttributePropertyName('dice_myattr'),
            prefix + 'ri:attributes:dice:myattr')
        # period is stronger separator than underscore, when both are present
        self.assertEqual(
            UsdRi.StatementsAPI.MakeRiAttributePropertyName('dice_my.attr'),
            prefix + 'ri:attributes:dice_my:attr')
        # multiple tokens concatted with underscores
        self.assertEqual(
            UsdRi.StatementsAPI.MakeRiAttributePropertyName(
                'dice:my1:long:attr'),
            prefix + 'ri:attributes:dice:my1_long_attr')
        self.assertEqual(
            UsdRi.StatementsAPI.MakeRiAttributePropertyName(
                'dice.my2.long.attr'),
            prefix + 'ri:attributes:dice:my2_long_attr')
        self.assertEqual(
            UsdRi.StatementsAPI.MakeRiAttributePropertyName(
                'dice_my3_long_attr'),
            prefix + 'ri:attributes:dice:my3_long_attr')

        self.assertEqual(riStatements.GetCoordinateSystem(), '')
        self.assertEqual(
            UsdRi.StatementsAPI(model).GetModelCoordinateSystems(), [])
        self.assertEqual(
            UsdRi.StatementsAPI(model).GetModelScopedCoordinateSystems(), [])
        riStatements.SetCoordinateSystem('LEyeSpace')
        self.assertEqual(riStatements.GetCoordinateSystem(), 'LEyeSpace')
        self.assertEqual(
            UsdRi.StatementsAPI(model).GetModelCoordinateSystems(),
            [Sdf.Path('/World/Group/Model/Shader')])
        riStatements.SetScopedCoordinateSystem('ScopedLEyeSpace')
        self.assertEqual(riStatements.GetScopedCoordinateSystem(),
                         'ScopedLEyeSpace')
        self.assertEqual(
            UsdRi.StatementsAPI(model).GetModelScopedCoordinateSystems(),
            [Sdf.Path('/World/Group/Model/Shader')])
        self.assertEqual(
            UsdRi.StatementsAPI(group).GetModelCoordinateSystems(), [])
        self.assertEqual(
            UsdRi.StatementsAPI(group).GetModelScopedCoordinateSystems(), [])
        self.assertEqual(
            UsdRi.StatementsAPI(world).GetModelCoordinateSystems(), [])
        self.assertEqual(
            UsdRi.StatementsAPI(world).GetModelScopedCoordinateSystems(), [])

        # Test mixed old & new style encodings
        if (Tf.GetEnvSetting('USDRI_STATEMENTS_WRITE_NEW_ATTR_ENCODING') and
                Tf.GetEnvSetting('USDRI_STATEMENTS_READ_OLD_ATTR_ENCODING')):
            prim = stage.DefinePrim("/prim")
            riStatements = UsdRi.StatementsAPI.Apply(prim)
            self.assertEqual(len(riStatements.GetRiAttributes()), 0)
            # Add new-style
            newStyleAttr = riStatements.CreateRiAttribute('newStyle', 'string')
            newStyleAttr.Set('new')
            self.assertEqual(len(riStatements.GetRiAttributes()), 1)
            # Add old-style (note that we can't use UsdRi API for this,
            # since it doesn't let the caller choose the encoding)
            oldStyleAttr = prim.CreateAttribute('ri:attributes:user:oldStyle',
                                                Sdf.ValueTypeNames.String)
            oldStyleAttr.Set('old')
            self.assertEqual(len(riStatements.GetRiAttributes()), 2)
            # Exercise the case of an Ri attribute encoded in both
            # old and new styles.
            ignoredAttr = prim.CreateAttribute('ri:attributes:user:newStyle',
                                               Sdf.ValueTypeNames.String)
            self.assertEqual(len(riStatements.GetRiAttributes()), 2)
            self.assertFalse(ignoredAttr in riStatements.GetRiAttributes())
# registered.
from mayaUsd import lib as mayaUsdLib

from pxr import Tf
from pxr import Usd

from maya import cmds
from maya import standalone

import fixturesUtils

import os
import unittest


@unittest.skipIf(not Tf.GetEnvSetting('MAYAUSD_DISABLE_VP2_RENDER_DELEGATE'),
                 'Not applicable when using the Viewport 2.0 render deleggate')
class testHdImagingShape(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        inputPath = fixturesUtils.setUpClass(__file__)

        mayaSceneFilePath = os.path.join(inputPath, 'HdImagingShapeTest',
                                         'HdImagingShapeTest.ma')

        cmds.file(mayaSceneFilePath, open=True, force=True)

    @classmethod
    def tearDownClass(cls):
        standalone.uninitialize()