1#!/pxrpythonsubst 2# 3# Copyright 2017 Pixar 4# 5# Licensed under the Apache License, Version 2.0 (the "Apache License") 6# with the following modification; you may not use this file except in 7# compliance with the Apache License and the following modification to it: 8# Section 6. Trademarks. is deleted and replaced with: 9# 10# 6. Trademarks. This License does not grant permission to use the trade 11# names, trademarks, service marks, or product names of the Licensor 12# and its affiliates, except as required to comply with Section 4(c) of 13# the License and to reproduce the content of the NOTICE file. 14# 15# You may obtain a copy of the Apache License at 16# 17# http://www.apache.org/licenses/LICENSE-2.0 18# 19# Unless required by applicable law or agreed to in writing, software 20# distributed under the Apache License with the above modification is 21# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 22# KIND, either express or implied. See the Apache License for the specific 23# language governing permissions and limitations under the Apache License. 24 25from pxr import Sdf, Pcp, Tf 26import unittest 27from contextlib import contextmanager 28 29class TestPcpChanges(unittest.TestCase): 30 def test_EmptySublayerChanges(self): 31 subLayer1 = Sdf.Layer.CreateAnonymous() 32 primSpec = Sdf.CreatePrimInLayer(subLayer1, '/Test') 33 34 rootLayer = Sdf.Layer.CreateAnonymous() 35 rootLayer.subLayerPaths.append(subLayer1.identifier) 36 37 layerStackId = Pcp.LayerStackIdentifier(rootLayer) 38 pcp = Pcp.Cache(layerStackId) 39 40 (pi, err) = pcp.ComputePrimIndex('/Test') 41 self.assertFalse(err) 42 self.assertEqual(pi.primStack, [primSpec]) 43 44 subLayer2 = Sdf.Layer.CreateAnonymous() 45 self.assertTrue(subLayer2.empty) 46 47 # Adding an empty sublayer should not require recomputing any prim 48 # indexes or change their prim stacks, but it should change the used 49 # layers revision count. 50 revCount = pcp.GetUsedLayersRevision() 51 with Pcp._TestChangeProcessor(pcp): 52 rootLayer.subLayerPaths.insert(0, subLayer2.identifier) 53 54 pi = pcp.FindPrimIndex('/Test') 55 self.assertTrue(pi) 56 self.assertEqual(pi.primStack, [primSpec]) 57 self.assertNotEqual(revCount, pcp.GetUsedLayersRevision()) 58 59 # Same with deleting an empty sublayer. 60 revCount = pcp.GetUsedLayersRevision() 61 with Pcp._TestChangeProcessor(pcp): 62 del rootLayer.subLayerPaths[0] 63 64 pi = pcp.FindPrimIndex('/Test') 65 self.assertTrue(pi) 66 self.assertEqual(pi.primStack, [primSpec]) 67 self.assertNotEqual(revCount, pcp.GetUsedLayersRevision()) 68 69 def test_InvalidSublayerAdd(self): 70 invalidSublayerId = "/tmp/testPcpChanges_invalidSublayer.sdf" 71 72 layer = Sdf.Layer.CreateAnonymous() 73 layerStackId = Pcp.LayerStackIdentifier(layer) 74 pcp = Pcp.Cache(layerStackId) 75 76 (layerStack, errs) = pcp.ComputeLayerStack(layerStackId) 77 self.assertEqual(len(errs), 0) 78 self.assertEqual(len(layerStack.localErrors), 0) 79 self.assertTrue(pcp.UsesLayerStack(layerStack)) 80 81 with Pcp._TestChangeProcessor(pcp): 82 layer.subLayerPaths.append(invalidSublayerId) 83 84 (layerStack, errs) = pcp.ComputeLayerStack(layerStackId) 85 # This is potentially surprising. Layer stacks are recomputed 86 # immediately during change processing, so any composition 87 # errors generated during that process won't be reported 88 # during the call to ComputeLayerStack. The errors will be 89 # stored in the layer stack's localErrors field, however. 90 self.assertEqual(len(errs), 0) 91 self.assertEqual(len(layerStack.localErrors), 1) 92 self.assertTrue(pcp.UsesLayerStack(layerStack)) 93 94 def test_InvalidSublayerRemoval(self): 95 invalidSublayerId = "/tmp/testPcpChanges_invalidSublayer.sdf" 96 97 layer = Sdf.Layer.CreateAnonymous() 98 layer.subLayerPaths.append(invalidSublayerId) 99 100 layerStackId = Pcp.LayerStackIdentifier(layer) 101 pcp = Pcp.Cache(layerStackId) 102 103 (layerStack, errs) = pcp.ComputeLayerStack(layerStackId) 104 self.assertEqual(len(errs), 1) 105 self.assertEqual(len(layerStack.localErrors), 1) 106 self.assertTrue(pcp.IsInvalidSublayerIdentifier(invalidSublayerId)) 107 108 with Pcp._TestChangeProcessor(pcp): 109 layer.subLayerPaths.remove(invalidSublayerId) 110 111 (layerStack, errs) = pcp.ComputeLayerStack(layerStackId) 112 self.assertEqual(len(errs), 0) 113 self.assertEqual(len(layerStack.localErrors), 0) 114 self.assertFalse(pcp.IsInvalidSublayerIdentifier(invalidSublayerId)) 115 self.assertTrue(pcp.UsesLayerStack(layerStack)) 116 117 def test_UnusedVariantChanges(self): 118 layer = Sdf.Layer.CreateAnonymous() 119 parent = Sdf.PrimSpec(layer, 'Root', Sdf.SpecifierDef, 'Scope') 120 vA = Sdf.CreateVariantInLayer(layer, parent.path, 'var', 'A') 121 vB = Sdf.CreateVariantInLayer(layer, parent.path, 'var', 'B') 122 parent.variantSelections['var'] = 'A' 123 124 layerStackId = Pcp.LayerStackIdentifier(layer) 125 pcp = Pcp.Cache(layerStackId) 126 127 (pi, err) = pcp.ComputePrimIndex('/Root') 128 self.assertTrue(pi) 129 self.assertEqual(len(err), 0) 130 131 # Add a new prim spec inside the unused variant and verify that this 132 # does not cause the cached prim index to be blown. 133 with Pcp._TestChangeProcessor(pcp): 134 newPrim = Sdf.PrimSpec(vB.primSpec, 'Child', Sdf.SpecifierDef, 'Scope') 135 136 self.assertTrue(pcp.FindPrimIndex('/Root')) 137 138 def test_SublayerOffsetChanges(self): 139 rootLayerPath = 'TestSublayerOffsetChanges/root.sdf' 140 rootSublayerPath = 'TestSublayerOffsetChanges/root-sublayer.sdf' 141 refLayerPath = 'TestSublayerOffsetChanges/ref.sdf' 142 refSublayerPath = 'TestSublayerOffsetChanges/ref-sublayer.sdf' 143 ref2LayerPath = 'TestSublayerOffsetChanges/ref2.sdf' 144 145 rootLayer = Sdf.Layer.FindOrOpen(rootLayerPath) 146 pcp = Pcp.Cache(Pcp.LayerStackIdentifier(rootLayer)) 147 148 (pi, err) = pcp.ComputePrimIndex('/A') 149 self.assertTrue(pi) 150 self.assertEqual(len(err), 0) 151 152 # Verify the expected structure of the test asset. It should simply be 153 # a chain of two references, with layer offsets of 100.0 and 50.0 154 # respectively. 155 refNode = pi.rootNode.children[0] 156 self.assertEqual(refNode.layerStack.layers, 157 [Sdf.Layer.Find(refLayerPath), Sdf.Layer.Find(refSublayerPath)]) 158 self.assertEqual(refNode.arcType, Pcp.ArcTypeReference) 159 self.assertEqual(refNode.mapToRoot.timeOffset, Sdf.LayerOffset(100.0)) 160 161 ref2Node = refNode.children[0] 162 self.assertEqual(ref2Node.layerStack.layers, [Sdf.Layer.Find(ref2LayerPath)]) 163 self.assertEqual(ref2Node.arcType, Pcp.ArcTypeReference) 164 self.assertEqual(ref2Node.mapToRoot.timeOffset, Sdf.LayerOffset(150.0)) 165 166 # Change the layer offset in the local layer stack and verify that 167 # invalidates the prim index and that the updated layer offset is 168 # taken into account after recomputing the index. 169 with Pcp._TestChangeProcessor(pcp): 170 rootLayer.subLayerOffsets[0] = Sdf.LayerOffset(200.0) 171 172 self.assertFalse(pcp.FindPrimIndex('/A')) 173 (pi, err) = pcp.ComputePrimIndex('/A') 174 refNode = pi.rootNode.children[0] 175 ref2Node = refNode.children[0] 176 177 self.assertEqual(refNode.mapToRoot.timeOffset, Sdf.LayerOffset(200.0)) 178 self.assertEqual(ref2Node.mapToRoot.timeOffset, Sdf.LayerOffset(250.0)) 179 180 # Change the layer offset in a referenced layer stack and again verify 181 # that the prim index is invalidated and the updated layer offset is 182 # taken into account. 183 refLayer = refNode.layerStack.layers[0] 184 with Pcp._TestChangeProcessor(pcp): 185 refLayer.subLayerOffsets[0] = Sdf.LayerOffset(200.0) 186 187 self.assertFalse(pcp.FindPrimIndex('/A')) 188 # Compute the prim index in the change processing block as the 189 # changed refLayer is only being held onto by the changes' lifeboat 190 # as its referencing prim index has been invalidated. 191 (pi, err) = pcp.ComputePrimIndex('/A') 192 refNode = pi.rootNode.children[0] 193 ref2Node = refNode.children[0] 194 195 self.assertEqual(refNode.mapToRoot.timeOffset, Sdf.LayerOffset(200.0)) 196 self.assertEqual(ref2Node.mapToRoot.timeOffset, Sdf.LayerOffset(400.0)) 197 198 def _RunTcpsChangesForLayer(self, pcpCache, layer, tcpsToExpecteOffsetsMap, 199 affectedPaths): 200 """ 201 Helper function for test_TcpsChanges to run a suite of various TCPS and 202 FPS metadata changes on a particular layer and verifying that the 203 correct change processing is run for every change. 204 """ 205 206 # Helper function for a making a TCPS and/or FPS change and verify the 207 # expected change processing, prim index invalidation, and new computed 208 # values. 209 def _ChangeAndVerify(newValDict, expectSignificantChange, expectedTcps): 210 211 # Just verify we have a tcps value and/or fps value to set 212 self.assertTrue('tcps' in newValDict or 'fps' in newValDict) 213 with Pcp._TestChangeProcessor(pcpCache) as cp: 214 # Change block for when we're setting both fps and tcps 215 with Sdf.ChangeBlock(): 216 # Set the tcps value if present (None -> Clear) 217 if 'tcps' in newValDict: 218 val = newValDict['tcps'] 219 if val is None: 220 layer.ClearTimeCodesPerSecond() 221 self.assertFalse(layer.HasTimeCodesPerSecond()) 222 else: 223 layer.timeCodesPerSecond = val 224 self.assertTrue(layer.HasTimeCodesPerSecond()) 225 226 # Set the fps value if present (None -> Clear) 227 if 'fps' in newValDict: 228 val = newValDict['fps'] 229 if val is None: 230 layer.ClearFramesPerSecond() 231 self.assertFalse(layer.HasFramesPerSecond()) 232 else: 233 layer.framesPerSecond = val 234 self.assertTrue(layer.HasFramesPerSecond()) 235 236 # Verify whether the change processor logged a significant 237 # change for the expected affected paths or not based on 238 # whether we expect a significant change. 239 if expectSignificantChange: 240 self.assertEqual(cp.GetSignificantChanges(), affectedPaths) 241 # A significant change will have invalidated our 242 # prim's prim index. 243 self.assertFalse(pcpCache.FindPrimIndex('/A')) 244 # Recompute the new prim index 245 (pi, err) = pcpCache.ComputePrimIndex('/A') 246 else: 247 # No significant should leave our prim's prim index 248 # valid. 249 self.assertEqual(cp.GetSignificantChanges(), []) 250 pi = pcpCache.FindPrimIndex('/A') 251 self.assertTrue(pi) 252 253 refNode = pi.rootNode.children[0] 254 ref2Node = refNode.children[0] 255 256 # Verify the layer has the expected computed TCPS 257 self.assertEqual(layer.timeCodesPerSecond, expectedTcps) 258 # Verify the ref node offesets match the expected offsets 259 # for the layer's expected computed TCPS. 260 expectedOffsets = tcpsToExpecteOffsetsMap[expectedTcps] 261 self.assertEqual(refNode.mapToRoot.timeOffset, 262 expectedOffsets[0]) 263 self.assertEqual(ref2Node.mapToRoot.timeOffset, 264 expectedOffsets[1]) 265 266 # Expect the layer to start with no authored TCPS of FPS. Verify 267 # various changes to authored timeCodesPerSecond 268 self.assertFalse(layer.HasTimeCodesPerSecond()) 269 self.assertFalse(layer.HasFramesPerSecond()) 270 _ChangeAndVerify({'tcps' : 24.0}, False, 24.0) 271 _ChangeAndVerify({'tcps' : None}, False, 24.0) 272 _ChangeAndVerify({'tcps' : 48.0}, True, 48.0) 273 _ChangeAndVerify({'tcps' : 12.0}, True, 12.0) 274 _ChangeAndVerify({'tcps' : None}, True, 24.0) 275 276 # Expect the layer to start with no authored TCPS of FPS again. 277 # Verify various changes to authored framesPerSecond 278 self.assertFalse(layer.HasTimeCodesPerSecond()) 279 self.assertFalse(layer.HasFramesPerSecond()) 280 _ChangeAndVerify({'fps' : 24.0}, False, 24.0) 281 _ChangeAndVerify({'fps' : None}, False, 24.0) 282 _ChangeAndVerify({'fps' : 48.0}, True, 48.0) 283 _ChangeAndVerify({'fps' : 12.0}, True, 12.0) 284 _ChangeAndVerify({'fps' : None}, True, 24.0) 285 286 # Change the layer to have an authored non-default framesPerSecond. 287 # Verify various changes to timeCodesPerSecond. 288 _ChangeAndVerify({'fps' : 48.0}, True, 48.0) 289 self.assertFalse(layer.HasTimeCodesPerSecond()) 290 self.assertTrue(layer.HasFramesPerSecond()) 291 self.assertEqual(layer.timeCodesPerSecond, 48.0) 292 _ChangeAndVerify({'tcps' : 48.0}, False, 48.0) 293 _ChangeAndVerify({'tcps' : None}, False, 48.0) 294 _ChangeAndVerify({'tcps' : 12.0}, True, 12.0) 295 _ChangeAndVerify({'tcps' : 24.0}, True, 24.0) 296 _ChangeAndVerify({'tcps' : None}, True, 48.0) 297 298 # Change the layer to have an authored timeCodesPerSecond. 299 # Verify that various changes to framesPerSecond have no effect. 300 _ChangeAndVerify({'tcps' : 24.0, 'fps' : None}, True, 24.0) 301 self.assertTrue(layer.HasTimeCodesPerSecond()) 302 self.assertFalse(layer.HasFramesPerSecond()) 303 self.assertEqual(layer.timeCodesPerSecond, 24.0) 304 _ChangeAndVerify({'fps' : 24.0}, False, 24.0) 305 _ChangeAndVerify({'fps' : None}, False, 24.0) 306 _ChangeAndVerify({'fps' : 48.0}, False, 24.0) 307 _ChangeAndVerify({'fps' : 12.0}, False, 24.0) 308 _ChangeAndVerify({'fps' : None}, False, 24.0) 309 310 # Change the layer to start with an unauthored timeCodesPerSecond 311 # and a non-default framesPerSecond 312 # Verify various changes to timeCodesPerSecond and framesPerSecond 313 # at the same time. 314 _ChangeAndVerify({'tcps' : None, 'fps' : 48.0}, True, 48.0) 315 self.assertFalse(layer.HasTimeCodesPerSecond()) 316 self.assertTrue(layer.HasFramesPerSecond()) 317 self.assertEqual(layer.timeCodesPerSecond, 48.0) 318 _ChangeAndVerify({'tcps' : 48.0, 'fps' : None}, False, 48.0) 319 _ChangeAndVerify({'tcps' : None, 'fps' : 48.0}, False, 48.0) 320 _ChangeAndVerify({'tcps' : 24.0, 'fps' : None}, True, 24.0) 321 _ChangeAndVerify({'tcps' : None, 'fps' : 48.0}, True, 48.0) 322 _ChangeAndVerify({'tcps' : 12.0, 'fps' : None}, True, 12.0) 323 _ChangeAndVerify({'tcps' : 48.0, 'fps' : 12.0}, True, 48.0) 324 _ChangeAndVerify({'tcps' : 12.0, 'fps' : 48.0}, True, 12.0) 325 _ChangeAndVerify({'tcps' : None, 'fps' : 12.0}, False, 12.0) 326 _ChangeAndVerify({'tcps' : 24.0, 'fps' : 24.0}, True, 24.0) 327 _ChangeAndVerify({'tcps' : None, 'fps' : None}, False, 24.0) 328 329 @unittest.skipIf( 330 Tf.GetEnvSetting('PCP_DISABLE_TIME_SCALING_BY_LAYER_TCPS'), 331 "Test requires layer TCPS time scaling enabled") 332 def test_TcpsChanges(self): 333 """ 334 Tests change processing for changes that affect the time codes per 335 second of all layers in the layer stacks of a PcpCache. 336 """ 337 338 # Use the same layers as the sublayer offset test case. 339 rootLayerPath = 'TestSublayerOffsetChanges/root.sdf' 340 rootSublayerPath = 'TestSublayerOffsetChanges/root-sublayer.sdf' 341 refLayerPath = 'TestSublayerOffsetChanges/ref.sdf' 342 refSublayerPath = 'TestSublayerOffsetChanges/ref-sublayer.sdf' 343 ref2LayerPath = 'TestSublayerOffsetChanges/ref2.sdf' 344 345 rootLayer = Sdf.Layer.FindOrOpen(rootLayerPath) 346 sessionLayer = Sdf.Layer.CreateAnonymous() 347 pcp = Pcp.Cache(Pcp.LayerStackIdentifier(rootLayer, sessionLayer)) 348 349 (pi, err) = pcp.ComputePrimIndex('/A') 350 self.assertTrue(pi) 351 self.assertEqual(len(err), 0) 352 353 rootSublayer = Sdf.Layer.Find(rootSublayerPath) 354 refLayer = Sdf.Layer.Find(refLayerPath) 355 refSublayer = Sdf.Layer.Find(refSublayerPath) 356 ref2Layer = Sdf.Layer.Find(ref2LayerPath) 357 358 # Verify the expected structure of the test asset. It should simply be 359 # a chain of two references, with layer offsets of 100.0 and 50.0 360 # respectively. 361 self.assertEqual(pi.rootNode.layerStack.layers, 362 [sessionLayer, rootLayer, rootSublayer]) 363 364 refNode = pi.rootNode.children[0] 365 self.assertEqual(refNode.layerStack.layers, [refLayer, refSublayer]) 366 self.assertEqual(refNode.arcType, Pcp.ArcTypeReference) 367 self.assertEqual(refNode.mapToRoot.timeOffset, Sdf.LayerOffset(100.0)) 368 for layer in refNode.layerStack.layers: 369 self.assertFalse(layer.HasTimeCodesPerSecond()) 370 self.assertEqual(layer.timeCodesPerSecond, 24.0) 371 372 ref2Node = refNode.children[0] 373 self.assertEqual(ref2Node.layerStack.layers, [ref2Layer]) 374 self.assertEqual(ref2Node.arcType, Pcp.ArcTypeReference) 375 self.assertEqual(ref2Node.mapToRoot.timeOffset, Sdf.LayerOffset(150.0)) 376 for layer in ref2Node.layerStack.layers: 377 self.assertFalse(layer.HasTimeCodesPerSecond()) 378 self.assertEqual(layer.timeCodesPerSecond, 24.0) 379 380 # Run the TCPS change suite on the root layer. 381 tcpsToOffsets = {12.0: (Sdf.LayerOffset(100.0, 0.5), 382 Sdf.LayerOffset(125.0, 0.5)), 383 24.0: (Sdf.LayerOffset(100.0), 384 Sdf.LayerOffset(150.0)), 385 48.0: (Sdf.LayerOffset(100.0, 2.0), 386 Sdf.LayerOffset(200.0, 2.0)) 387 } 388 self._RunTcpsChangesForLayer(pcp, rootLayer, tcpsToOffsets, ['/']) 389 390 # Run the TCPS change suite on the first reference layer. 391 tcpsToOffsets = {12.0: (Sdf.LayerOffset(100.0, 2.0), 392 Sdf.LayerOffset(200.0)), 393 24.0: (Sdf.LayerOffset(100.0), 394 Sdf.LayerOffset(150.0)), 395 48.0: (Sdf.LayerOffset(100.0, 0.5), 396 Sdf.LayerOffset(125.0)) 397 } 398 self._RunTcpsChangesForLayer(pcp, refLayer, tcpsToOffsets, ['/A']) 399 400 # Run the TCPS change suite on the second reference layer. 401 tcpsToOffsets = {12.0: (Sdf.LayerOffset(100.0), 402 Sdf.LayerOffset(150.0, 2.0)), 403 24.0: (Sdf.LayerOffset(100.0), 404 Sdf.LayerOffset(150.0)), 405 48.0: (Sdf.LayerOffset(100.0), 406 Sdf.LayerOffset(150.0, 0.5)) 407 } 408 self._RunTcpsChangesForLayer(pcp, ref2Layer, tcpsToOffsets, ['/A']) 409 410 # Run the TCPS change suite on the sublayers of the root and reference 411 # layers. In the particular setup of these layer, TCPS of either 412 # sublayer doesn't change the layer offsets applied to the reference 413 # nodes, but will still cause change management to report significant 414 # changes to prim indexes. 415 tcpsToOffsets = {12.0: (Sdf.LayerOffset(100.0), 416 Sdf.LayerOffset(150.0)), 417 24.0: (Sdf.LayerOffset(100.0), 418 Sdf.LayerOffset(150.0)), 419 48.0: (Sdf.LayerOffset(100.0), 420 Sdf.LayerOffset(150.0)) 421 } 422 self._RunTcpsChangesForLayer(pcp, rootSublayer, tcpsToOffsets, ['/']) 423 self._RunTcpsChangesForLayer(pcp, refSublayer, tcpsToOffsets, ['/A']) 424 425 # Run the TCPS change suite on the session layer. 426 tcpsToOffsets = {12.0: (Sdf.LayerOffset(50.0, 0.5), 427 Sdf.LayerOffset(75.0, 0.5)), 428 24.0: (Sdf.LayerOffset(100.0), 429 Sdf.LayerOffset(150.0)), 430 48.0: (Sdf.LayerOffset(200.0, 2.0), 431 Sdf.LayerOffset(300.0, 2.0)) 432 } 433 self._RunTcpsChangesForLayer(pcp, sessionLayer, tcpsToOffsets, ['/']) 434 435 # Special cases for the session layer when root layer has a tcps value 436 rootLayer.timeCodesPerSecond = 24.0 437 self.assertTrue(rootLayer.HasTimeCodesPerSecond()) 438 self.assertFalse(sessionLayer.HasTimeCodesPerSecond()) 439 with Pcp._TestChangeProcessor(pcp) as cp: 440 # Set the session layer's FPS. This will change the session layer's 441 # computed TCPS and is a significant change even though the overall 442 # TCPS of the root layer stack is 24 as it is authored on the root 443 # layer. 444 sessionLayer.framesPerSecond = 48.0 445 self.assertEqual(sessionLayer.timeCodesPerSecond, 48.0) 446 self.assertEqual(cp.GetSignificantChanges(), ['/']) 447 self.assertFalse(pcp.FindPrimIndex('/A')) 448 # Recompute the new prim index 449 (pi, err) = pcp.ComputePrimIndex('/A') 450 refNode = pi.rootNode.children[0] 451 ref2Node = refNode.children[0] 452 # The reference layer offsets are still the same as authored as 453 # the root layer TCPS still matches its layer stack's overall TCPS 454 self.assertEqual(refNode.mapToRoot.timeOffset, 455 Sdf.LayerOffset(100.0)) 456 self.assertEqual(ref2Node.mapToRoot.timeOffset, 457 Sdf.LayerOffset(150.0)) 458 459 # Continuing from the previous case, root layer has TCPS set to 24 and 460 # session layer has FPS set to 48. Now we set the session TCPS to 48. 461 # While this does not cause a TCPS change to session layer taken by 462 # itself, this does mean that the session now overrides the overall 463 # TCPS of the layer stack which used to come the root. We verify here 464 # that this is a significant change and that it scales the layer offsets 465 # to the references. 466 self.assertFalse(sessionLayer.HasTimeCodesPerSecond()) 467 with Pcp._TestChangeProcessor(pcp) as cp: 468 sessionLayer.timeCodesPerSecond = 48.0 469 self.assertEqual(sessionLayer.timeCodesPerSecond, 48.0) 470 self.assertEqual(cp.GetSignificantChanges(), ['/']) 471 self.assertFalse(pcp.FindPrimIndex('/A')) 472 # Recompute the new prim index 473 (pi, err) = pcp.ComputePrimIndex('/A') 474 refNode = pi.rootNode.children[0] 475 ref2Node = refNode.children[0] 476 self.assertEqual(refNode.mapToRoot.timeOffset, 477 Sdf.LayerOffset(200.0, 2.0)) 478 self.assertEqual(ref2Node.mapToRoot.timeOffset, 479 Sdf.LayerOffset(300.0, 2.0)) 480 481 # And as a parallel to the previous case, we now clear the session TCPS 482 # again. This is still no effective change to the session layer TCPS 483 # itself, but root layer's TCPS is once again the overall layer stack 484 # TCPS. This is significant changes and the layer offsets return to 485 # their original values. 486 with Pcp._TestChangeProcessor(pcp) as cp: 487 sessionLayer.ClearTimeCodesPerSecond() 488 self.assertEqual(sessionLayer.timeCodesPerSecond, 48.0) 489 self.assertEqual(cp.GetSignificantChanges(), ['/']) 490 self.assertFalse(pcp.FindPrimIndex('/A')) 491 # Recompute the new prim index 492 (pi, err) = pcp.ComputePrimIndex('/A') 493 refNode = pi.rootNode.children[0] 494 ref2Node = refNode.children[0] 495 # The reference layer offsets are still the same as authored as 496 # the root layer TCPS still matches its layer stack's overall TCPS 497 self.assertEqual(refNode.mapToRoot.timeOffset, 498 Sdf.LayerOffset(100.0)) 499 self.assertEqual(ref2Node.mapToRoot.timeOffset, 500 Sdf.LayerOffset(150.0)) 501 502 # One more special case. Neither session or root layers have TCPS set. 503 # Root layer has FPS set to 48, session layer has FPS set to 24. Overall 504 # computed TCPS of the layer stack will be 24, matching session FPS. 505 # We then author a TCPS value of 48 to the root layer, matching its FPS 506 # value. There is no effective change to the root layer's TCPS itself 507 # but we do end up with a significant change as the overall layer stack 508 # TCPS will now compute to 48. 509 sessionLayer.ClearTimeCodesPerSecond() 510 rootLayer.ClearTimeCodesPerSecond() 511 sessionLayer.framesPerSecond = 24.0 512 rootLayer.framesPerSecond = 48.0 513 with Pcp._TestChangeProcessor(pcp) as cp: 514 rootLayer.timeCodesPerSecond = 48.0 515 self.assertEqual(rootLayer.timeCodesPerSecond, 48.0) 516 self.assertEqual(cp.GetSignificantChanges(), ['/']) 517 self.assertFalse(pcp.FindPrimIndex('/A')) 518 # Recompute the new prim index 519 (pi, err) = pcp.ComputePrimIndex('/A') 520 refNode = pi.rootNode.children[0] 521 ref2Node = refNode.children[0] 522 self.assertEqual(refNode.mapToRoot.timeOffset, 523 Sdf.LayerOffset(100.0, 2.0)) 524 self.assertEqual(ref2Node.mapToRoot.timeOffset, 525 Sdf.LayerOffset(200.0, 2.0)) 526 527 528 def test_DefaultReferenceTargetChanges(self): 529 # create a layer, set DefaultPrim, then reference it. 530 targLyr = Sdf.Layer.CreateAnonymous() 531 532 def makePrim(name): 533 primSpec = Sdf.CreatePrimInLayer(targLyr, name) 534 primSpec.specifier = Sdf.SpecifierDef 535 536 makePrim('target1') 537 makePrim('target2') 538 539 targLyr.defaultPrim = 'target1' 540 541 def _Test(referencingLayer): 542 # Make a PcpCache. 543 pcp = Pcp.Cache(Pcp.LayerStackIdentifier(referencingLayer)) 544 545 (pi, err) = pcp.ComputePrimIndex('/source') 546 547 # First child node should be the referenced target1. 548 self.assertEqual(pi.rootNode.children[0].path, '/target1') 549 550 # Now clear defaultPrim. This should issue an error and 551 # fail to pick up the referenced prim. 552 with Pcp._TestChangeProcessor(pcp): 553 targLyr.ClearDefaultPrim() 554 555 (pi, err) = pcp.ComputePrimIndex('/source') 556 self.assertTrue(isinstance(err[0], Pcp.ErrorUnresolvedPrimPath)) 557 # If the reference to the defaultPrim is an external reference, 558 # the one child node should be the pseudoroot dependency placeholder. 559 # If the reference is an internal reference, that dependency 560 # placeholder is unneeded. 561 if referencingLayer != targLyr: 562 self.assertEqual(len(pi.rootNode.children), 1) 563 self.assertEqual(pi.rootNode.children[0].path, '/') 564 565 # Change defaultPrim to other target. This should pick 566 # up the reference again, but to the new prim target2. 567 with Pcp._TestChangeProcessor(pcp): 568 targLyr.defaultPrim = 'target2' 569 570 (pi, err) = pcp.ComputePrimIndex('/source') 571 self.assertEqual(len(err), 0) 572 self.assertEqual(pi.rootNode.children[0].path, '/target2') 573 574 # Reset defaultPrim to original target 575 targLyr.defaultPrim = 'target1' 576 577 # Test external reference case where some other layer references 578 # a layer with defaultPrim specified. 579 srcLyr = Sdf.Layer.CreateAnonymous() 580 srcPrimSpec = Sdf.CreatePrimInLayer(srcLyr, '/source') 581 srcPrimSpec.referenceList.Add(Sdf.Reference(targLyr.identifier)) 582 _Test(srcLyr) 583 584 # Test internal reference case where a prim in the layer with defaultPrim 585 # specified references the same layer. 586 srcPrimSpec = Sdf.CreatePrimInLayer(targLyr, '/source') 587 srcPrimSpec.referenceList.Add(Sdf.Reference()) 588 _Test(targLyr) 589 590 def test_InternalReferenceChanges(self): 591 rootLayer = Sdf.Layer.CreateAnonymous() 592 593 Sdf.PrimSpec(rootLayer, 'target1', Sdf.SpecifierDef) 594 Sdf.PrimSpec(rootLayer, 'target2', Sdf.SpecifierDef) 595 596 srcPrimSpec = Sdf.PrimSpec(rootLayer, 'source', Sdf.SpecifierDef) 597 srcPrimSpec.referenceList.Add(Sdf.Reference(primPath = '/target1')) 598 599 # Initially, the prim index for /source should contain a single 600 # reference node to /target1 in rootLayer. 601 pcp = Pcp.Cache(Pcp.LayerStackIdentifier(rootLayer)) 602 (pi, err) = pcp.ComputePrimIndex('/source') 603 604 self.assertEqual(len(err), 0) 605 self.assertEqual(pi.rootNode.children[0].layerStack.identifier.rootLayer, 606 rootLayer) 607 self.assertEqual(pi.rootNode.children[0].path, '/target1') 608 609 # Modify the internal reference to point to /target2 and verify the 610 # reference node is updated. 611 with Pcp._TestChangeProcessor(pcp): 612 srcPrimSpec.referenceList.addedItems[0] = \ 613 Sdf.Reference(primPath = '/target2') 614 615 (pi, err) = pcp.ComputePrimIndex('/source') 616 617 self.assertEqual(len(err), 0) 618 self.assertEqual(pi.rootNode.children[0].layerStack.identifier.rootLayer, 619 rootLayer) 620 self.assertEqual(pi.rootNode.children[0].path, '/target2') 621 622 # Clear out all references and verify that the prim index contains no 623 # reference nodes. 624 with Pcp._TestChangeProcessor(pcp): 625 srcPrimSpec.referenceList.ClearEdits() 626 627 (pi, err) = pcp.ComputePrimIndex('/source') 628 629 self.assertEqual(len(err), 0) 630 self.assertEqual(len(pi.rootNode.children), 0) 631 632 def test_VariantChanges(self): 633 rootLayer = Sdf.Layer.CreateAnonymous() 634 modelSpec = Sdf.PrimSpec(rootLayer, 'Variant', Sdf.SpecifierDef) 635 636 pcp = Pcp.Cache(Pcp.LayerStackIdentifier(rootLayer), usd=True) 637 638 # Test changes that are emitted as a variant set and variant 639 # are created. 640 641 pcp.ComputePrimIndex('/Variant') 642 with Pcp._TestChangeProcessor(pcp) as cp: 643 varSetSpec = Sdf.VariantSetSpec(modelSpec, 'test') 644 self.assertEqual(cp.GetSignificantChanges(), ['/Variant']) 645 self.assertEqual(cp.GetSpecChanges(), []) 646 self.assertEqual(cp.GetPrimChanges(), []) 647 648 pcp.ComputePrimIndex('/Variant') 649 with Pcp._TestChangeProcessor(pcp) as cp: 650 modelSpec.variantSelections['test'] = 'A' 651 self.assertEqual(cp.GetSignificantChanges(), ['/Variant']) 652 self.assertEqual(cp.GetSpecChanges(), []) 653 self.assertEqual(cp.GetPrimChanges(), []) 654 655 pcp.ComputePrimIndex('/Variant') 656 with Pcp._TestChangeProcessor(pcp) as cp: 657 modelSpec.variantSetNameList.Add('test') 658 self.assertEqual(cp.GetSignificantChanges(), ['/Variant']) 659 self.assertEqual(cp.GetSpecChanges(), []) 660 self.assertEqual(cp.GetPrimChanges(), []) 661 662 pcp.ComputePrimIndex('/Variant') 663 with Pcp._TestChangeProcessor(pcp) as cp: 664 varSpec = Sdf.VariantSpec(varSetSpec, 'A') 665 self.assertEqual(cp.GetSignificantChanges(), []) 666 self.assertEqual(cp.GetSpecChanges(), ['/Variant']) 667 # Creating the variant spec adds an inert spec to /Variant's prim 668 # stack but does not require rebuilding /Variant's prim index to 669 # account for the new variant node. 670 self.assertEqual(cp.GetPrimChanges(), []) 671 672 pcp.ComputePrimIndex('/Variant') 673 with Pcp._TestChangeProcessor(pcp) as cp: 674 varSpec.primSpec.referenceList.Add( 675 Sdf.Reference('./dummy.sdf', '/Dummy')) 676 self.assertEqual(cp.GetSignificantChanges(), ['/Variant']) 677 self.assertEqual(cp.GetSpecChanges(), []) 678 self.assertEqual(cp.GetPrimChanges(), []) 679 680 def test_InstancingChanges(self): 681 refLayer = Sdf.Layer.CreateAnonymous() 682 refParentSpec = Sdf.PrimSpec(refLayer, 'Parent', Sdf.SpecifierDef) 683 refChildSpec = Sdf.PrimSpec(refParentSpec, 'RefChild', Sdf.SpecifierDef) 684 685 rootLayer = Sdf.Layer.CreateAnonymous() 686 parentSpec = Sdf.PrimSpec(rootLayer, 'Parent', Sdf.SpecifierOver) 687 parentSpec.referenceList.Add( 688 Sdf.Reference(refLayer.identifier, '/Parent')) 689 childSpec = Sdf.PrimSpec(parentSpec, 'DirectChild', Sdf.SpecifierDef) 690 691 # Instancing is only enabled in Usd mode. 692 pcp = Pcp.Cache(Pcp.LayerStackIdentifier(rootLayer), usd=True) 693 694 # /Parent is initially not tagged as an instance, so we should 695 # see both RefChild and DirectChild name children. 696 (pi, err) = pcp.ComputePrimIndex('/Parent') 697 self.assertEqual(len(err), 0) 698 self.assertFalse(pi.IsInstanceable()) 699 self.assertEqual(pi.ComputePrimChildNames(), (['RefChild', 'DirectChild'], [])) 700 701 with Pcp._TestChangeProcessor(pcp) as cp: 702 parentSpec.instanceable = True 703 self.assertEqual(cp.GetSignificantChanges(), ['/Parent']) 704 self.assertEqual(cp.GetSpecChanges(), []) 705 self.assertEqual(cp.GetPrimChanges(), []) 706 707 # After being made an instance, DirectChild should no longer 708 # be reported as a name child since instances may not introduce 709 # new prims locally. 710 (pi, err) = pcp.ComputePrimIndex('/Parent') 711 self.assertEqual(len(err), 0) 712 self.assertTrue(pi.IsInstanceable()) 713 self.assertEqual(pi.ComputePrimChildNames(), (['RefChild'], [])) 714 715 with Pcp._TestChangeProcessor(pcp) as cp: 716 parentSpec.instanceable = False 717 self.assertEqual(cp.GetSignificantChanges(), ['/Parent']) 718 self.assertEqual(cp.GetSpecChanges(), []) 719 self.assertEqual(cp.GetPrimChanges(), []) 720 721 # Flipping the instance flag back should restore us to the 722 # original state. 723 (pi, err) = pcp.ComputePrimIndex('/Parent') 724 self.assertEqual(len(err), 0) 725 self.assertFalse(pi.IsInstanceable()) 726 self.assertEqual(pi.ComputePrimChildNames(), (['RefChild', 'DirectChild'], [])) 727 728 def test_InstancingChangesForSubrootArcs(self): 729 # First layer: Build up the first reference structure 730 refLayer = Sdf.Layer.CreateAnonymous() 731 # Base spec name space hierarchy: /Base/Child/BaseLeaf. 732 baseSpec = Sdf.PrimSpec(refLayer, 'Base', Sdf.SpecifierDef) 733 baseChildSpec = Sdf.PrimSpec(baseSpec, 'Child', Sdf.SpecifierDef) 734 baseLeafSpec = Sdf.PrimSpec(baseChildSpec, 'BaseLeaf', Sdf.SpecifierDef) 735 736 # /A references /Base 737 refASpec = Sdf.PrimSpec(refLayer, 'A', Sdf.SpecifierDef) 738 refASpec.referenceList.Add(Sdf.Reference('', '/Base')) 739 740 # /B references /A 741 refBSpec = Sdf.PrimSpec(refLayer, 'B', Sdf.SpecifierDef) 742 refBSpec.referenceList.Add(Sdf.Reference('', '/A')) 743 744 # Second layer: Same structure as layer with incmented names for clarity 745 # when both layers have prims referenced 746 refLayer2 = Sdf.Layer.CreateAnonymous() 747 base2Spec = Sdf.PrimSpec(refLayer2, 'Base2', Sdf.SpecifierDef) 748 base2ChildSpec = Sdf.PrimSpec(base2Spec, 'Child', Sdf.SpecifierDef) 749 base2LeafSpec = Sdf.PrimSpec(base2ChildSpec, 'Base2Leaf', 750 Sdf.SpecifierDef) 751 752 # /A2 references /Base2 753 refA2Spec = Sdf.PrimSpec(refLayer2, 'A2', Sdf.SpecifierDef) 754 refA2Spec.referenceList.Add(Sdf.Reference('', '/Base2')) 755 756 # /B2 references /A2 757 refB2Spec = Sdf.PrimSpec(refLayer2, 'B2', Sdf.SpecifierDef) 758 refB2Spec.referenceList.Add(Sdf.Reference('', '/A2')) 759 760 # Root layer: 761 # Instance spec namespace hierarchy: /Instance/Child/InstanceLeaf 762 # /Instance references /B2. 763 # /Instance/Child subroot references /B/Child 764 # 765 # What this gives us is the following prim index graph for 766 # /Instance/Child: 767 # 768 # /Instance/Child --> /B/Child -a-> /A/Child -a-> /Base/Child 769 # | 770 # +-a-> /B2/Child -a-> /A2/Child -a-> /Base2/Child 771 # 772 # All reference arcs are "ancestral" except the direct reference from 773 # /Instance/Child to /B/Child. Ancestral arcs under a direct arc are 774 # treated differently for instancing than normal ancestral arcs. 775 layer = Sdf.Layer.CreateAnonymous() 776 instanceSpec = Sdf.PrimSpec(layer, 'Instance', Sdf.SpecifierDef) 777 instanceSpec.referenceList.Add( 778 Sdf.Reference(refLayer2.identifier, '/B2')) 779 instanceChildSpec = Sdf.PrimSpec(instanceSpec, 'Child', 780 Sdf.SpecifierDef) 781 instanceChildSpec.referenceList.Add( 782 Sdf.Reference(refLayer.identifier, '/B/Child')) 783 instanceLeafSpec = Sdf.PrimSpec(instanceChildSpec, 'InstanceLeaf', 784 Sdf.SpecifierDef) 785 786 # Instancing is only enabled in Usd mode. 787 pcp = Pcp.Cache(Pcp.LayerStackIdentifier(layer), usd=True) 788 789 # Compute our initial prim index. It is not yet instanceable and 790 # all leaf nodes appear when computing prim child names. 791 (pi, err) = pcp.ComputePrimIndex('/Instance/Child') 792 self.assertEqual(len(err), 0) 793 self.assertFalse(pi.IsInstanceable()) 794 self.assertEqual(pi.ComputePrimChildNames(), 795 (['Base2Leaf', 'BaseLeaf', 'InstanceLeaf'], [])) 796 797 # Helper context for verifying the change processing of the changes 798 # affecting /Instance/Child 799 @contextmanager 800 def _VerifyChanges(significant=False, spec=False, prim=False): 801 primIndexPath = '/Instance/Child' 802 # Verify that we have a computed prim index for /Instance/Child 803 # before making the change . 804 self.assertTrue(pcp.FindPrimIndex(primIndexPath)) 805 with Pcp._TestChangeProcessor(pcp) as cp: 806 try: 807 yield cp 808 finally: 809 self.assertEqual(cp.GetSignificantChanges(), 810 [primIndexPath] if significant else []) 811 self.assertEqual(cp.GetSpecChanges(), 812 [primIndexPath] if spec else []) 813 self.assertEqual(cp.GetPrimChanges(), 814 [primIndexPath] if prim else []) 815 # Significant and prim changes do invalidate the prim index. 816 if significant or prim: 817 self.assertFalse(pcp.FindPrimIndex(primIndexPath)) 818 else: 819 self.assertTrue(pcp.FindPrimIndex(primIndexPath)) 820 821 # Add Child spec to /A. This is just a spec change to /Instance/Child 822 # as /Instance/Child is not instanceable yet. 823 with _VerifyChanges(spec=True): 824 Sdf.PrimSpec(refASpec, 'Child', Sdf.SpecifierOver) 825 826 # Add Child spec to /A2. This is just a spec change to /Instance/Child. 827 with _VerifyChanges(spec=True): 828 Sdf.PrimSpec(refA2Spec, 'Child', Sdf.SpecifierOver) 829 830 # Delete both Child specs we just added. 831 with _VerifyChanges(spec=True): 832 del refASpec.nameChildren['Child'] 833 with _VerifyChanges(spec=True): 834 del refA2Spec.nameChildren['Child'] 835 836 # Now set /Base/Child to instanceable which is always a significant 837 # change. 838 with _VerifyChanges(significant=True): 839 baseChildSpec.instanceable = True 840 841 # /Instance/Child is now instanceable. BaseLeaf is still returned by 842 # ComputePrimChildren because the ancestral node that provides it comes 843 # from a subtree composed for a direct subroot reference arc so it is 844 # part of the instance. Base2Leaf comes from an actual ancestral arc so 845 # it gets skipped when computing children as does the local child 846 # opinion for InstanceLeaf. 847 (pi, err) = pcp.ComputePrimIndex('/Instance/Child') 848 self.assertEqual(len(err), 0) 849 self.assertTrue(pi.IsInstanceable()) 850 self.assertEqual(pi.ComputePrimChildNames(), (['BaseLeaf'], [])) 851 852 # Add Child spec to /A2 again now that /Instance/Child is instanceable. 853 # This is still just a spec change to /Instance/Child as true ancestral 854 # nodes are ignored by the instance key. 855 with _VerifyChanges(spec=True): 856 Sdf.PrimSpec(refA2Spec, 'Child', Sdf.SpecifierOver) 857 858 # Add Child spec to /A again. This is a significant change as /A/Child 859 # is an ancestral node that's part of a direct arc's subtree and is 860 # part of the instance key. 861 with _VerifyChanges(significant=True): 862 Sdf.PrimSpec(refASpec, 'Child', Sdf.SpecifierOver) 863 864 (pi, err) = pcp.ComputePrimIndex('/Instance/Child') 865 self.assertEqual(len(err), 0) 866 self.assertTrue(pi.IsInstanceable()) 867 self.assertEqual(pi.ComputePrimChildNames(), (['BaseLeaf'], [])) 868 869 def test_InertPrimChanges(self): 870 refLayer = Sdf.Layer.CreateAnonymous() 871 refParentSpec = Sdf.PrimSpec(refLayer, 'Parent', Sdf.SpecifierDef) 872 refChildSpec = Sdf.PrimSpec(refParentSpec, 'Child', Sdf.SpecifierDef) 873 874 rootLayer = Sdf.Layer.CreateAnonymous() 875 parentSpec = Sdf.PrimSpec(rootLayer, 'Parent', Sdf.SpecifierOver) 876 parentSpec.referenceList.Add( 877 Sdf.Reference(refLayer.identifier, '/Parent')) 878 879 pcp = Pcp.Cache(Pcp.LayerStackIdentifier(rootLayer)) 880 881 # Adding an empty over to a prim that already exists (has specs) 882 # is an insignificant change. 883 (pi, err) = pcp.ComputePrimIndex('/Parent/Child') 884 self.assertEqual(err, []) 885 with Pcp._TestChangeProcessor(pcp) as cp: 886 Sdf.CreatePrimInLayer(rootLayer, '/Parent/Child') 887 self.assertEqual(cp.GetSignificantChanges(), []) 888 self.assertEqual(cp.GetSpecChanges(), ['/Parent/Child']) 889 self.assertEqual(cp.GetPrimChanges(), []) 890 891 # Adding an empty over as the first spec for a prim is a 892 # a significant change, even if we haven't computed a prim index 893 # for that path yet. 894 with Pcp._TestChangeProcessor(pcp) as cp: 895 Sdf.CreatePrimInLayer(rootLayer, '/Parent/NewChild') 896 self.assertEqual(cp.GetSignificantChanges(), ['/Parent/NewChild']) 897 self.assertEqual(cp.GetSpecChanges(), []) 898 self.assertEqual(cp.GetPrimChanges(), []) 899 900 (pi, err) = pcp.ComputePrimIndex('/Parent/NewChild2') 901 self.assertEqual(err, []) 902 with Pcp._TestChangeProcessor(pcp) as cp: 903 Sdf.CreatePrimInLayer(rootLayer, '/Parent/NewChild2') 904 self.assertEqual(cp.GetSignificantChanges(), ['/Parent/NewChild2']) 905 self.assertEqual(cp.GetSpecChanges(), []) 906 self.assertEqual(cp.GetPrimChanges(), []) 907 908 def test_InertPrimRemovalChanges(self): 909 subLayer = Sdf.Layer.CreateAnonymous() 910 subParentSpec = Sdf.PrimSpec(subLayer, 'Parent', Sdf.SpecifierDef) 911 subChildSpec = Sdf.PrimSpec(subParentSpec, 'Child', Sdf.SpecifierDef) 912 subAttrSpec = Sdf.AttributeSpec(subChildSpec, 'attr', Sdf.ValueTypeNames.Double) 913 subAttrSpec.default = 1.0 914 915 rootLayer = Sdf.Layer.CreateAnonymous() 916 rootParentSpec = Sdf.PrimSpec(rootLayer, 'Parent', Sdf.SpecifierOver) 917 rootChildSpec = Sdf.PrimSpec(rootParentSpec, 'Child', Sdf.SpecifierOver) 918 rootAttrSpec = Sdf.AttributeSpec(rootChildSpec, 'attr', Sdf.ValueTypeNames.Double) 919 rootLayer.subLayerPaths.append(subLayer.identifier) 920 921 pcp = Pcp.Cache(Pcp.LayerStackIdentifier(rootLayer)) 922 923 (pi, err) = pcp.ComputePrimIndex('/Parent') 924 self.assertEqual(err, []) 925 self.assertEqual(pi.primStack, [rootParentSpec, subParentSpec]) 926 927 (pi, err) = pcp.ComputePrimIndex('/Parent/Child') 928 self.assertEqual(err, []) 929 self.assertEqual(pi.primStack, [rootChildSpec, subChildSpec]) 930 931 (pi, err) = pcp.ComputePropertyIndex('/Parent/Child.attr') 932 self.assertEqual(err, []) 933 self.assertEqual(pi.propertyStack, [rootAttrSpec, subAttrSpec]) 934 935 revCount = pcp.GetUsedLayersRevision() 936 with Pcp._TestChangeProcessor(pcp) as cp: 937 del rootLayer.pseudoRoot.nameChildren['Parent'] 938 self.assertFalse(rootParentSpec) 939 self.assertFalse(rootChildSpec) 940 self.assertFalse(rootAttrSpec) 941 942 self.assertEqual(cp.GetSignificantChanges(), []) 943 self.assertEqual(cp.GetSpecChanges(), 944 ['/Parent', '/Parent/Child', '/Parent/Child.attr']) 945 self.assertEqual(cp.GetPrimChanges(), []) 946 947 self.assertEqual(revCount, pcp.GetUsedLayersRevision()) 948 949 (pi, err) = pcp.ComputePrimIndex('/Parent') 950 self.assertEqual(err, []) 951 self.assertEqual(pi.primStack, [subParentSpec]) 952 953 (pi, err) = pcp.ComputePrimIndex('/Parent/Child') 954 self.assertEqual(err, []) 955 self.assertEqual(pi.primStack, [subChildSpec]) 956 957 (pi, err) = pcp.ComputePropertyIndex('/Parent/Child.attr') 958 self.assertEqual(err, []) 959 self.assertEqual(pi.propertyStack, [subAttrSpec]) 960 961if __name__ == "__main__": 962 unittest.main() 963