def testErrorAndDelete( self ) : # Create a script with a dodgy node, # and a GraphGadget for displaying it. script = Gaffer.ScriptNode() script["n"] = GafferTest.BadNode() graphGadget = GafferUI.GraphGadget( script ) # Arrange for the node to error on # a background thread. def f() : with IECore.IgnoredExceptions( Exception ) : script["n"]["out1"].getValue() r = threading.Thread( target = f ) r.start() r.join() # Delete the node on the # foreground thread - this will # remove the NodeGadget inside # the GraphGadget. del script["n"] # Run idle events. Woe betide any NodeGadget # implementation assuming it will still be # alive at arbitrary points in the future! self.waitForIdle( 1000 )
def testErrorSignalledOnIntermediateNodes(self): nodes = [GafferTest.BadNode()] for i in range(0, 10): nodes.append(GafferTest.AddNode()) nodes[-1]["op1"].setInput( nodes[-2]["sum"] if i != 0 else nodes[-2]["out3"]) slots = [GafferTest.CapturingSlot(n.errorSignal()) for n in nodes] self.assertRaises(RuntimeError, nodes[-1]["sum"].getValue) for i, slot in enumerate(slots): self.assertEqual(len(slot), 1) self.assertTrue(slot[0][0].isSame(nodes[i]["out3"] if i == 0 else nodes[i]["sum"])) self.assertTrue(slot[0][1].isSame(nodes[0]["out3"]))
def testErrorSignal(self): b = GafferTest.BadNode() a = GafferTest.AddNode() a["op1"].setInput(b["out3"]) cs = GafferTest.CapturingSlot(b.errorSignal()) self.assertRaises(RuntimeError, b["out1"].getValue) self.assertEqual(len(cs), 1) self.assertTrue(cs[0][0].isSame(b["out1"])) self.assertTrue(cs[0][1].isSame(b["out1"])) self.assertTrue(isinstance(cs[0][2], str)) self.assertRaises(RuntimeError, a["sum"].getValue) self.assertEqual(len(cs), 2) self.assertTrue(cs[1][0].isSame(b["out3"])) self.assertTrue(cs[1][1].isSame(b["out3"])) self.assertTrue(isinstance(cs[1][2], str))
def testErrorSignalledAtScopeTransitions(self): s = Gaffer.ScriptNode() s["b"] = Gaffer.Box() s["b"]["b"] = GafferTest.BadNode() s["b"]["a"] = GafferTest.AddNode() s["b"]["a"]["op1"].setInput(s["b"]["b"]["out3"]) css = GafferTest.CapturingSlot(s.errorSignal()) csb = GafferTest.CapturingSlot(s["b"].errorSignal()) csbb = GafferTest.CapturingSlot(s["b"]["b"].errorSignal()) p = Gaffer.PlugAlgo.promote(s["b"]["a"]["sum"]) self.assertRaises(RuntimeError, p.getValue) self.assertEqual(len(css), 0) self.assertEqual(len(csb), 1) self.assertTrue(csb[0][0].isSame(p)) self.assertTrue(csb[0][1].isSame(s["b"]["b"]["out3"])) self.assertEqual(len(csbb), 1) self.assertTrue(csbb[0][0].isSame(s["b"]["b"]["out3"])) self.assertTrue(csbb[0][1].isSame(s["b"]["b"]["out3"]))
def testThrowInAffects(self): # Dirty propagation is a secondary process that # is triggered by primary operations like adding # plugs, setting values, and changing inputs. # We don't want errors that occur during dirty # propagation to prevent the original operation # from succeeding, so that although dirtiness is # not propagated fully, the graph itself is in # an intact state. node = GafferTest.BadNode() with IECore.CapturingMessageHandler() as mh: node["in3"] = Gaffer.IntPlug(flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic) # We want the addition of the child to have succeeded. self.assertTrue("in3" in node) # And to have been informed of the bug in BadNode. self.assertEqual(len(mh.messages), 1) self.assertEqual(mh.messages[0].level, mh.Level.Error) self.assertEqual(mh.messages[0].context, "BadNode::affects()") self.assertTrue("BadNode is bad" in mh.messages[0].message) with IECore.CapturingMessageHandler() as mh: del node["in3"] # We want the removal of the child to have succeeded. self.assertTrue("in3" not in node) # And to have been informed of the bug in BadNode. self.assertEqual(len(mh.messages), 1) self.assertEqual(mh.messages[0].level, mh.Level.Error) self.assertEqual(mh.messages[0].context, "BadNode::affects()") self.assertTrue("BadNode is bad" in mh.messages[0].message) # And after all that, we still want dirty propagation to work properly. cs = GafferTest.CapturingSlot(node.plugDirtiedSignal()) node["in1"].setValue(10) self.assertTrue(node["out1"] in [c[0] for c in cs])
def testErrorSlotsDontSeeException( self ) : self.fRan = False def f( *unusedArgs ) : # If there's an active python exception (from # the error in BadNode below) when we try this # import, it'll appear (falsely) as if the error # originated from the import, and throw an exception # here. This is not the intention - error slots are # just meant to be informed of the error, without # ever seeing the exception itself. import IECore self.fRan = True n = GafferTest.BadNode() c = n.errorSignal().connect( f ) with IECore.IgnoredExceptions( Exception ) : n["out1"].getValue() self.assertTrue( self.fRan )
def testPlugNotSet(self): n = GafferTest.BadNode() self.assertRaises(RuntimeError, n["out3"].getValue)
def testWrongPlugSet(self): n = GafferTest.BadNode() self.assertRaises(RuntimeError, n["out1"].getValue)