def testGlobals(self): a = GafferScene.CustomOptions() a["options"].addChild(Gaffer.NameValuePlug("test1", 1)) a["options"].addChild(Gaffer.NameValuePlug("test2", 2)) b = GafferScene.CustomOptions() b["options"].addChild(Gaffer.NameValuePlug("test2", 4)) b["options"].addChild(Gaffer.NameValuePlug("test3", 3)) merge = GafferScene.MergeScenes() merge["in"][0].setInput(a["out"]) merge["in"][1].setInput(b["out"]) # `Keep` self.assertEqual(merge["globalsMode"].getValue(), merge.Mode.Keep) self.assertEqual(merge["out"].globals(), a["out"].globals()) self.assertEqual(merge["out"].globalsHash(), a["out"].globalsHash()) # `Replace` merge["globalsMode"].setValue(merge.Mode.Replace) self.assertEqual(merge["out"].globals(), b["out"].globals()) self.assertEqual(merge["out"].globalsHash(), b["out"].globalsHash()) # `Merge` merge["globalsMode"].setValue(merge.Mode.Merge) mergedGlobals = a["out"].globals() mergedGlobals.update(b["out"].globals()) self.assertEqual(merge["out"].globals(), mergedGlobals)
def testSerialisation(self): s = Gaffer.ScriptNode() s["optionsNode"] = GafferScene.CustomOptions() s["optionsNode"]["options"].addChild( Gaffer.NameValuePlug("test", IECore.IntData(10), flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)) s["optionsNode"]["options"].addChild( Gaffer.NameValuePlug("test2", IECore.StringData("10"), flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)) ss = s.serialise() s2 = Gaffer.ScriptNode() s2.execute(ss) g = s2["optionsNode"]["out"]["globals"].getValue() self.assertEqual(len(g), 2) self.assertEqual(g["option:test"], IECore.IntData(10)) self.assertEqual(g["option:test2"], IECore.StringData("10")) self.assertTrue("options1" not in s2["optionsNode"])
def test( self ) : p = GafferScene.Plane() options = GafferScene.CustomOptions() options["in"].setInput( p["out"] ) # check that the scene hierarchy is passed through self.assertEqual( options["out"].object( "/" ), IECore.NullObject() ) self.assertEqual( options["out"].transform( "/" ), imath.M44f() ) self.assertEqual( options["out"].bound( "/" ), imath.Box3f( imath.V3f( -0.5, -0.5, 0 ), imath.V3f( 0.5, 0.5, 0 ) ) ) self.assertEqual( options["out"].childNames( "/" ), IECore.InternedStringVectorData( [ "plane" ] ) ) self.assertEqual( options["out"].object( "/plane" ), IECoreScene.MeshPrimitive.createPlane( imath.Box2f( imath.V2f( -0.5 ), imath.V2f( 0.5 ) ) ) ) self.assertEqual( options["out"].transform( "/plane" ), imath.M44f() ) self.assertEqual( options["out"].bound( "/plane" ), imath.Box3f( imath.V3f( -0.5, -0.5, 0 ), imath.V3f( 0.5, 0.5, 0 ) ) ) self.assertEqual( options["out"].childNames( "/plane" ), IECore.InternedStringVectorData() ) # check that we can make options options["options"].addChild( Gaffer.NameValuePlug( "test", IECore.IntData( 10 ) ) ) options["options"].addChild( Gaffer.NameValuePlug( "test2", IECore.StringData( "10" ) ) ) g = options["out"]["globals"].getValue() self.assertEqual( len( g ), 2 ) self.assertEqual( g["option:test"], IECore.IntData( 10 ) ) self.assertEqual( g["option:test2"], IECore.StringData( "10" ) )
def testEnabledFromGlobals(self): script = Gaffer.ScriptNode() script["options"] = GafferScene.CustomOptions() script["options"]["options"]["enabled"] = Gaffer.NameValuePlug( "enabled", True) script["plane"] = GafferScene.Plane() script["sphere"] = GafferScene.Sphere() script["switch"] = Gaffer.NameSwitch() script["switch"].setup(GafferScene.ScenePlug()) script["switch"]["selector"].setValue("sphere") script["switch"]["in"][0]["name"].setValue("plane") script["switch"]["in"][0]["value"].setInput(script["plane"]["out"]) script["switch"]["in"][1]["name"].setValue("sphere") script["switch"]["in"][1]["value"].setInput(script["sphere"]["out"]) script["expression"] = Gaffer.Expression() script["expression"].setExpression( inspect.cleandoc(""" g = parent["options"]["out"]["globals"] parent["switch"]["enabled"] = g["option:enabled"] """)) # As well as asserting that the scene is as expected here, we're also # indirectly testing that `scene:path` isn't leaked into the context # used to evaluate the globals (because SceneTestCase installs a # ContextSanitiser for the duration of the test). self.assertEqual(script["switch"]["out"]["value"].object("/sphere"), script["sphere"]["out"].object("/sphere"))
def testDirtyPropagation( self ) : p = GafferScene.Plane() o = GafferScene.CustomOptions() o["in"].setInput( p["out"] ) cs = GafferTest.CapturingSlot( o.plugDirtiedSignal() ) p["dimensions"]["x"].setValue( 100.1 ) dirtiedPlugs = { x[0] for x in cs if not x[0].getName().startswith( "__" ) } self.assertEqual( dirtiedPlugs, { o["in"]["bound"], o["in"]["childBounds"], o["in"]["object"], o["in"], o["out"]["bound"], o["out"]["childBounds"], o["out"]["object"], o["out"], } )
def test(self): plane = GafferScene.Plane() options = GafferScene.CustomOptions() options["in"].setInput(plane["out"]) deleteOptions = GafferScene.DeleteOptions() deleteOptions["in"].setInput(options["out"]) # test that by default the scene is passed through self.assertScenesEqual(plane["out"], deleteOptions["out"]) self.assertSceneHashesEqual(plane["out"], deleteOptions["out"]) # test that we can delete options options["options"].addMember("test1", 1) options["options"].addMember("test2", 2) options["options"].addMember("test3", 3) g = deleteOptions["out"]["globals"].getValue() self.assertEqual(g["option:test1"], IECore.IntData(1)) self.assertEqual(g["option:test2"], IECore.IntData(2)) self.assertEqual(g["option:test3"], IECore.IntData(3)) deleteOptions["names"].setValue("test1 test2") g = deleteOptions["out"]["globals"].getValue() self.assertEqual(g["option:test3"], IECore.IntData(3)) self.assertFalse("option:test1" in g) self.assertFalse("option:test2" in g) deleteOptions["names"].setValue("test*") g = deleteOptions["out"]["globals"].getValue() self.assertFalse("option:test1" in g) self.assertFalse("option:test2" in g) self.assertFalse("option:test3" in g) # test dirty propagation cs = GafferTest.CapturingSlot(deleteOptions.plugDirtiedSignal()) deleteOptions["names"].setValue("") self.assertTrue(deleteOptions["out"]["globals"] in set(e[0] for e in cs)) del cs[:] deleteOptions["invertNames"].setValue(True) self.assertTrue(deleteOptions["out"]["globals"] in set(e[0] for e in cs))
def testPrefix(self): options = GafferScene.CustomOptions() options["options"].addMember("test", IECore.IntData(10)) options["prefix"].setValue("myCategory:") g = options["out"]["globals"].getValue() self.assertEqual(g["option:myCategory:test"], IECore.IntData(10))
def testGlobals( self ) : options = GafferScene.CustomOptions() options["options"].addMember( "user:test", "${collect:rootName}" ) self.assertTrue( "option:user:test" in options["out"]["globals"].getValue() ) collect = GafferScene.CollectScenes() collect["in"].setInput( options["out"] ) collect["rootNames"].setValue( IECore.StringVectorData( [ "a", "b" ] ) ) self.assertEqual( collect["out"]["globals"].getValue()["option:user:test"], IECore.StringData( "a" ) )
def testHashPassThrough( self ) : # The hash of everything except the globals should be # identical to the input, so that they share cache entries. p = GafferScene.Plane() options = GafferScene.CustomOptions() options["in"].setInput( p["out"] ) options["options"].addChild( Gaffer.NameValuePlug( "test", IECore.IntData( 10 ) ) ) self.assertSceneHashesEqual( p["out"], options["out"], checks = self.allSceneChecks - { "globals" } )
def testDirtyPropagationOnMemberAdditionAndRemoval(self): o = GafferScene.CustomOptions() cs = GafferTest.CapturingSlot(o.plugDirtiedSignal()) p = o["options"].addMember("test", IECore.IntData(10)) self.assertTrue(o["out"]["globals"] in [c[0] for c in cs]) del cs[:] o["options"].removeChild(p) self.assertTrue(o["out"]["globals"] in [c[0] for c in cs])
def testHashPassThrough( self ) : # the hash of the per-object part of the output should be # identical to the input, so that they share cache entries. p = GafferScene.Plane() options = GafferScene.CustomOptions() options["in"].setInput( p["out"] ) options["options"].addMember( "test", IECore.IntData( 10 ) ) self.assertSceneHashesEqual( p["out"], options["out"], childPlugNames = ( "transform", "bound", "attributes", "object", "childNames" ) )
def testDirtyPropagationOnMemberAdditionAndRemoval( self ) : o = GafferScene.CustomOptions() cs = GafferTest.CapturingSlot( o.plugDirtiedSignal() ) p = Gaffer.NameValuePlug( "test", IECore.IntData( 10 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) o["options"].addChild( p ) self.assertTrue( o["out"]["globals"] in [ c[0] for c in cs ] ) del cs[:] o["options"].removeChild( p ) self.assertTrue( o["out"]["globals"] in [ c[0] for c in cs ] )
def testMergeGlobals(self): script = Gaffer.ScriptNode() script["options"] = GafferScene.CustomOptions() script["options"]["options"]["test1"] = Gaffer.NameValuePlug( "user:test1", "${collect:rootName}", True) script["options"]["options"]["test2"] = Gaffer.NameValuePlug( "user:test2", "${collect:rootName}", True) script["options"]["options"]["test3"] = Gaffer.NameValuePlug( "user:test3", "${collect:rootName}", True) script["spreadsheet"] = Gaffer.Spreadsheet() script["spreadsheet"]["selector"].setValue("${collect:rootName}") for option in script["options"]["options"].children(): script["spreadsheet"]["rows"].addColumn(option["enabled"], option.getName()) option["enabled"].setInput( script["spreadsheet"]["out"][option.getName()]) for rowName in ("a", "b"): row = script["spreadsheet"]["rows"].addRow() row["name"].setValue(rowName) row["cells"]["test1"]["value"].setValue(rowName == "a") row["cells"]["test2"]["value"].setValue(True) row["cells"]["test3"]["value"].setValue(rowName == "b") script["collect"] = GafferScene.CollectScenes() script["collect"]["in"].setInput(script["options"]["out"]) script["collect"]["rootNames"].setInput( script["spreadsheet"]["activeRowNames"]) # Merging off self.assertEqual( script["collect"]["out"].globals(), IECore.CompoundObject({ "option:user:test1": IECore.StringData("a"), "option:user:test2": IECore.StringData("a"), })) # Merging on script["collect"]["mergeGlobals"].setValue(True) self.assertEqual( script["collect"]["out"].globals(), IECore.CompoundObject({ "option:user:test1": IECore.StringData("a"), "option:user:test2": IECore.StringData("b"), "option:user:test3": IECore.StringData("b"), }))
def testSetsPassThrough( self ) : p = GafferScene.Plane() p["sets"].setValue( "a b" ) o = GafferScene.CustomOptions() o["in"].setInput( p["out"] ) self.assertEqual( p["out"]["setNames"].hash(), o["out"]["setNames"].hash() ) self.assertTrue( p["out"]["setNames"].getValue( _copy = False ).isSame( o["out"]["setNames"].getValue( _copy = False ) ) ) self.assertEqual( p["out"].setHash( "a" ), o["out"].setHash( "b" ) ) self.assertTrue( p["out"].set( "a", _copy = False ).isSame( o["out"].set( "b", _copy = False ) ) )
def testSubstitution( self ) : o = GafferScene.CustomOptions() o["options"].addChild( Gaffer.NameValuePlug( "test", "${foo}" ) ) self.assertEqual( o["out"]["globals"].getValue()["option:test"], IECore.StringData( "" ) ) h = o["out"]["globals"].hash() c = Gaffer.Context() c["foo"] = "foo" with c : self.assertNotEqual( o["out"]["globals"].hash(), h ) self.assertEqual( o["out"]["globals"].getValue()["option:test"], IECore.StringData( "foo" ) )
def testDisabled( self ) : p = GafferScene.Plane() options = GafferScene.CustomOptions() options["in"].setInput( p["out"] ) options["options"].addChild( Gaffer.NameValuePlug( "test", IECore.IntData( 10 ) ) ) self.assertSceneHashesEqual( p["out"], options["out"], checks = self.allSceneChecks - { "globals" } ) self.assertNotEqual( options["out"]["globals"].hash(), p["out"]["globals"].hash() ) options["enabled"].setValue( False ) self.assertSceneHashesEqual( p["out"], options["out"] ) self.assertScenesEqual( p["out"], options["out"] )
def testDisabled( self ) : p = GafferScene.Plane() options = GafferScene.CustomOptions() options["in"].setInput( p["out"] ) options["options"].addMember( "test", IECore.IntData( 10 ) ) self.assertSceneHashesEqual( p["out"], options["out"], childPlugNames = ( "transform", "bound", "attributes", "object", "childNames" ) ) self.assertNotEqual( options["out"]["globals"].hash(), p["out"]["globals"].hash() ) options["enabled"].setValue( False ) self.assertSceneHashesEqual( p["out"], options["out"] ) self.assertScenesEqual( p["out"], options["out"] )
def testDuplicateRoots(self): sphere = GafferScene.Sphere() sphere["sets"].setValue("${collect:rootName}") sphereFilter = GafferScene.PathFilter() sphereFilter["paths"].setValue(IECore.StringVectorData(["/sphere"])) attributes = GafferScene.CustomAttributes() attributes["in"].setInput(sphere["out"]) attributes["filter"].setInput(sphereFilter["out"]) attributes["attributes"]["test"] = Gaffer.NameValuePlug( "test", "${collect:rootName}") options = GafferScene.CustomOptions() options["in"].setInput(attributes["out"]) options["options"]["test"] = Gaffer.NameValuePlug( "test", "${collect:rootName}") collect = GafferScene.CollectScenes() collect["in"].setInput(options["out"]) # The user might enter the exact same value multiple times by accident. # And because the values represent paths, they may even enter _different_ # values that map to the same path. collect["rootNames"].setValue( IECore.StringVectorData([ "A/B", "/A/B", "/A/B/", "A/B", ])) # We automatically uniquefy the names, using the first string as the # value of `collect:rootName`. self.assertEqual(collect["out"].childNames("/"), IECore.InternedStringVectorData(["A"])) self.assertEqual(collect["out"].childNames("/A"), IECore.InternedStringVectorData(["B"])) self.assertEqual( collect["out"].attributes("/A/B/sphere"), IECore.CompoundObject({"test": IECore.StringData("A/B")})) self.assertEqual(collect["out"].setNames(), IECore.InternedStringVectorData(["A/B"])) self.assertEqual(collect["out"].set("A/B").value, IECore.PathMatcher(["/A/B/sphere"])) self.assertEqual( collect["out"].globals(), IECore.CompoundObject({"option:test": IECore.StringData("A/B")}))
def test(self): plane = GafferScene.Plane() options = GafferScene.CustomOptions() options["in"].setInput(plane["out"]) deleteOptions = GafferScene.DeleteOptions() deleteOptions["in"].setInput(options["out"]) copyOptions = GafferScene.CopyOptions() copyOptions["in"].setInput(deleteOptions["out"]) copyOptions["source"].setInput(options["out"]) # set up some options that we can delete and copy options["options"].addMember("test1", 1) options["options"].addMember("test2", 2) options["options"].addMember("test3", 3) # verify result g = deleteOptions["out"]["globals"].getValue() self.assertEqual(g["option:test1"], IECore.IntData(1)) self.assertEqual(g["option:test2"], IECore.IntData(2)) self.assertEqual(g["option:test3"], IECore.IntData(3)) # delete options deleteOptions["names"].setValue("test*") # verify result g = deleteOptions["out"]["globals"].getValue() self.assertFalse("option:test1" in g) self.assertFalse("option:test2" in g) self.assertFalse("option:test3" in g) # copy options copyOptions["names"].setValue("test*") # verify result g = copyOptions["out"]["globals"].getValue() self.assertEqual(g["option:test1"], IECore.IntData(1)) self.assertEqual(g["option:test2"], IECore.IntData(2)) self.assertEqual(g["option:test3"], IECore.IntData(3)) # test dirty propagation cs = GafferTest.CapturingSlot(copyOptions.plugDirtiedSignal()) copyOptions["names"].setValue("") self.assertTrue(copyOptions["out"]["globals"] in set(e[0] for e in cs))
def testSerialisation(self): s = Gaffer.ScriptNode() s["optionsNode"] = GafferScene.CustomOptions() s["optionsNode"]["options"].addMember("test", IECore.IntData(10)) s["optionsNode"]["options"].addMember("test2", IECore.StringData("10")) ss = s.serialise() s2 = Gaffer.ScriptNode() s2.execute(ss) g = s2["optionsNode"]["out"]["globals"].getValue() self.assertEqual(len(g), 2) self.assertEqual(g["option:test"], IECore.IntData(10)) self.assertEqual(g["option:test2"], IECore.StringData("10")) self.assertTrue("options1" not in s2["optionsNode"])
def testOptions( self ) : s = Gaffer.ScriptNode() s["fileName"].setValue( self.temporaryDirectory() + "/test.gfr" ) s["p"] = GafferScene.Plane() s["o"] = GafferScene.CustomOptions() s["o"]["options"].addMember( "user:test", IECore.IntData( 10 ) ) s["r"] = GafferSceneTest.TestRender() s["r"]["in"].setInput( s["o"]["out"] ) # CapturingRenderer outputs some spurious errors which # we suppress by capturing them. with IECore.CapturingMessageHandler() : s["r"].execute() self.assertEqual( s["r"].renderer().getOption( "user:test" ), IECore.IntData( 10 ) )
def testDirtyPropagation(self): p = GafferScene.Plane() o = GafferScene.CustomOptions() o["in"].setInput(p["out"]) cs = GafferTest.CapturingSlot(o.plugDirtiedSignal()) p["dimensions"]["x"].setValue(100.1) dirtiedPlugs = set([x[0].relativeName(x[0].node()) for x in cs]) self.assertEqual(len(dirtiedPlugs), 6) self.assertTrue("in.bound" in dirtiedPlugs) self.assertTrue("in.object" in dirtiedPlugs) self.assertTrue("in" in dirtiedPlugs) self.assertTrue("out.bound" in dirtiedPlugs) self.assertTrue("out.object" in dirtiedPlugs) self.assertTrue("out" in dirtiedPlugs)
def testExtraOptions(self): options = GafferScene.CustomOptions() options["options"].addChild( Gaffer.NameValuePlug("test1", IECore.IntData(1))) options["options"].addChild( Gaffer.NameValuePlug("test2", IECore.IntData(2))) options["extraOptions"].setValue( IECore.CompoundObject({ "test1": IECore.IntData(-1), "test3": IECore.IntData(3), })) self.assertEqual( options["out"].globals(), IECore.CompoundObject({ "option:test1": IECore.IntData(-1), "option:test2": IECore.IntData(2), "option:test3": IECore.IntData(3) }))
def testTraceSets( self ) : s = Gaffer.ScriptNode() s["reflector"] = GafferScene.Plane() s["reflector"]["name"].setValue( "reflector" ) s["reflector"]["transform"]["translate"].setValue( IECore.V3f( 0, 0, -1 ) ) s["reflected"] = GafferScene.Plane() s["reflected"]["name"].setValue( "reflected" ) s["reflected"]["transform"]["translate"].setValue( IECore.V3f( 0, 0, 1 ) ) s["group"] = GafferScene.Group() s["group"]["in"][0].setInput( s["reflector"]["out"] ) s["group"]["in"][1].setInput( s["reflected"]["out"] ) s["constant"], constantParameter = self._createConstantShader() s["constantAssignment"] = GafferScene.ShaderAssignment() s["constantAssignment"]["in"].setInput( s["group"]["out"] ) s["constantAssignment"]["shader"].setInput( s["constant"]["out"] ) traceShader, traceSetParameter = self._createTraceSetShader() if traceShader is None : self.skipTest( "Trace set shader not available" ) s["traceShader"] = traceShader s["traceAssignmentFilter"] = GafferScene.PathFilter() s["traceAssignmentFilter"]["paths"].setValue( IECore.StringVectorData( [ "/group/reflector" ] ) ) s["traceAssignment"] = GafferScene.ShaderAssignment() s["traceAssignment"]["in"].setInput( s["constantAssignment"]["out"] ) s["traceAssignment"]["shader"].setInput( s["traceShader"]["out"] ) s["traceAssignment"]["filter"].setInput( s["traceAssignmentFilter"]["out"] ) s["set"] = GafferScene.Set() s["set"]["in"].setInput( s["traceAssignment"]["out"] ) s["set"]["name"].setValue( "render:myTraceSet" ) s["options"] = GafferScene.CustomOptions() s["options"]["in"].setInput( s["set"]["out"] ) for o in self._traceDepthOptions() : s["options"]["options"].addMember( o, IECore.IntData( 1 ) ) s["outputs"] = GafferScene.Outputs() s["outputs"].addOutput( "beauty", IECore.Display( "test", "ieDisplay", "rgba", { "driverType" : "ImageDisplayDriver", "handle" : "traceSetsTest", } ) ) s["outputs"]["in"].setInput( s["options"]["out"] ) s["render"] = self._createInteractiveRender() s["render"]["in"].setInput( s["outputs"]["out"] ) s["render"]["state"].setValue( s["render"].State.Running ) time.sleep( 0.5 ) # We haven't used the trace sets yet, so should be able to see # the reflection. def assertReflected( reflected ) : image = IECore.ImageDisplayDriver.storedImage( "traceSetsTest" ) self.assertGreater( self.__color4fAtUV( image, IECore.V2f( 0.5 ) ).a, 0.9 ) if reflected : self.assertGreater( self.__color4fAtUV( image, IECore.V2f( 0.5 ) ).r, 0.9 ) else : self.assertLess( self.__color4fAtUV( image, IECore.V2f( 0.5 ) ).r, 0.1 ) assertReflected( True ) # Ask to use a trace set. Reflection should disappear because # we haven't added anything to the set. traceSetParameter.setValue( "myTraceSet" ) time.sleep( 0.5 ) assertReflected( False ) # Now add the reflected object into the set. Reflection should # come back. s["set"]["paths"].setValue( IECore.StringVectorData( [ "/group/reflected" ] ) ) time.sleep( 0.5 ) assertReflected( True ) # Rename the set so that it's not a trace set any more. Reflection # should disappear. s["set"]["name"].setValue( "myTraceSet" ) time.sleep( 0.5 ) assertReflected( False ) # Rename the set so that it is a trace set, but with a different namer. # Reflection should not reappear. s["set"]["name"].setValue( "render:myOtherTraceSet" ) time.sleep( 0.5 ) assertReflected( False ) # Update the shader to use this new trace set. Reflection should # reappear. traceSetParameter.setValue( "myOtherTraceSet" ) time.sleep( 0.5 ) assertReflected( True )
def testCapsuleHash(self): sphere = GafferScene.Sphere() group1 = GafferScene.Group() group1["in"][0].setInput(sphere["out"]) group2 = GafferScene.Group() group2["in"][0].setInput(group1["out"]) pathFilter = GafferScene.PathFilter() pathFilter["paths"].setValue(IECore.StringVectorData(["/group/group"])) encapsulate = GafferScene.Encapsulate() encapsulate["in"].setInput(group2["out"]) encapsulate["filter"].setInput(pathFilter["out"]) objectHashes = set() capsuleHashes = set() def assertHashesUnique(path): objectHash = encapsulate["out"].objectHash(path) capsule = encapsulate["out"].object(path) self.assertIsInstance(capsule, GafferScene.Capsule) capsuleHash = capsule.hash() self.assertNotIn(objectHash, objectHashes) self.assertNotIn(capsuleHash, capsuleHashes) objectHashes.add(objectHash) capsuleHashes.add(capsuleHash) assertHashesUnique("/group/group") sphere["radius"].setValue(2) assertHashesUnique("/group/group") sphere["name"].setValue("bigSphere") assertHashesUnique("/group/group") sphere["transform"]["translate"]["x"].setValue(1) assertHashesUnique("/group/group") pathFilter["paths"].setValue(IECore.StringVectorData(["/group"])) assertHashesUnique("/group") encapsulate["in"].setInput(group1["out"]) assertHashesUnique("/group") # Test changing the filter or globals group2["in"][1].setInput(group1["out"]) options = GafferScene.CustomOptions() options["in"].setInput(group2["out"]) encapsulate["in"].setInput(options["out"]) pathFilter["paths"].setValue(IECore.StringVectorData(["/group/group"])) c = encapsulate["out"].object("/group/group") # Changing filter doesn't affect hash pathFilter["paths"].setValue( IECore.StringVectorData(["/group/group", "/group/group2"])) self.assertEqual(c, encapsulate["out"].object("/group/group")) # Changing globals shouldn't affect hash # \todo : But it currently does due to current issue with handling motion blur. Change this # assertNotEqual to an assertEqual after fixing shutter handling for capsules options["options"].addChild( Gaffer.NameValuePlug("test", IECore.IntData(10))) self.assertNotEqual(c, encapsulate["out"].object("/group/group"))