def testDispatchAndGIL(self): script = Gaffer.ScriptNode() script["plane"] = GafferScene.Plane() script["plane"]["divisions"].setValue(imath.V2i(20)) script["sphere"] = GafferScene.Sphere() script["expression"] = Gaffer.Expression() script["expression"].setExpression( "parent['sphere']['radius'] = context.get( 'minRadius', 0.1 ) + context.getFrame()" ) script["instancer"] = GafferScene.Instancer() script["instancer"]["in"].setInput(script["plane"]["out"]) script["instancer"]["instances"].setInput(script["sphere"]["out"]) script["instancer"]["parent"].setValue("/plane") script["pythonCommand"] = GafferDispatch.PythonCommand() script["pythonCommand"]["command"].setValue("pass") traverseConnection = Gaffer.ScopedConnection( GafferSceneTest.connectTraverseSceneToPreDispatchSignal( script["instancer"]["out"])) dispatcher = GafferDispatch.LocalDispatcher() dispatcher["jobsDirectory"].setValue(self.temporaryDirectory()) with Gaffer.Context() as c: for i in range(1, 10): c.setFrame(i) dispatcher.dispatch([script["pythonCommand"]])
def test( self ) : s = Gaffer.ScriptNode() s["task"] = GafferDispatchTest.LoggingTaskNode() s["task"]["frameDependency"] = Gaffer.StringPlug( defaultValue = "#" ) s["mask"] = GafferDispatch.FrameMask() s["mask"]["preTasks"][0].setInput( s["task"]["task"] ) s["mask"]["mask"].setValue( "1,3,10-15,20-30x2" ) d = GafferDispatch.LocalDispatcher() d["jobsDirectory"].setValue( self.temporaryDirectory() + "/jobs" ) d["framesMode"].setValue( d.FramesMode.CustomRange ) d["frameRange"].setValue( "1-50" ) d.dispatch( [ s["mask"] ] ) self.assertEqual( [ l.context.getFrame() for l in s["task"].log ], IECore.FrameList.parse( s["mask"]["mask"].getValue() ).asList() ) # Check that empty mask is a pass-through del s["task"].log[:] s["mask"]["mask"].setValue( "" ) d.dispatch( [ s["mask"] ] ) self.assertEqual( [ l.context.getFrame() for l in s["task"].log ], IECore.FrameList.parse( d["frameRange"].getValue() ).asList() )
def testParentJob(self): djc = GafferDeadline.GafferDeadlineJob() djp = GafferDeadline.GafferDeadlineJob() task_node = GafferDispatch.TaskNode() task_node2 = GafferDispatch.TaskNode() djc.addParentJob(djp) self.assertIn(djp, djc.getParentJobs()) djp.setGafferNode(task_node) self.assertEqual(djc.getParentJobByGafferNode(task_node), djp) self.assertEqual(djc.getParentJobByGafferNode(task_node2), None)
def test(self): n = GafferDispatch.TaskList() c = Gaffer.Context() c2 = Gaffer.Context() c2["frame"] = 10.0 self.assertEqual(n.hash(c), n.hash(c2)) n2 = GafferDispatch.TaskList("TaskList2") self.assertEqual(n.hash(c), n2.hash(c)) self.assertEqual(n.hash(c2), n2.hash(c2))
def testContext(self): script = Gaffer.ScriptNode() script["writer"] = GafferDispatchTest.TextWriter() script["writer"]["fileName"].setValue(self.temporaryDirectory() + "/${name}.####.txt") script["wedge"] = GafferDispatch.Wedge() script["wedge"]["preTasks"][0].setInput(script["writer"]["task"]) script["wedge"]["variable"].setValue("name") script["wedge"]["mode"].setValue( int(GafferDispatch.Wedge.Mode.StringList)) script["wedge"]["strings"].setValue( IECore.StringVectorData(["tom", "dick", "harry"])) self.__dispatcher(frameRange="21-22").dispatch([script["wedge"]]) self.assertEqual( set(glob.glob(self.temporaryDirectory() + "/*.txt")), { self.temporaryDirectory() + "/tom.0021.txt", self.temporaryDirectory() + "/tom.0022.txt", self.temporaryDirectory() + "/dick.0021.txt", self.temporaryDirectory() + "/dick.0022.txt", self.temporaryDirectory() + "/harry.0021.txt", self.temporaryDirectory() + "/harry.0022.txt", })
def testColorRange(self): script = Gaffer.ScriptNode() script["writer"] = GafferDispatchTest.TextWriter() script["writer"]["fileName"].setValue(self.temporaryDirectory() + "/${wedge:index}.txt") script["expression"] = Gaffer.Expression() script["expression"].setExpression( 'c = context["wedge:value"]; parent["writer"]["text"] = "%.1f %.1f %.1f" % ( c[0], c[1], c[2] )' ) script["wedge"] = GafferDispatch.Wedge() script["wedge"]["preTasks"][0].setInput(script["writer"]["task"]) script["wedge"]["mode"].setValue( int(GafferDispatch.Wedge.Mode.ColorRange)) script["wedge"]["colorSteps"].setValue(3) self.__dispatcher().dispatch([script["wedge"]]) self.assertEqual( set(glob.glob(self.temporaryDirectory() + "/*.txt")), { self.temporaryDirectory() + "/0.txt", self.temporaryDirectory() + "/1.txt", self.temporaryDirectory() + "/2.txt", }) self.assertEqual(next(open(self.temporaryDirectory() + "/0.txt")), "0.0 0.0 0.0") self.assertEqual(next(open(self.temporaryDirectory() + "/1.txt")), "0.5 0.5 0.5") self.assertEqual(next(open(self.temporaryDirectory() + "/2.txt")), "1.0 1.0 1.0")
def testIntRange(self): script = Gaffer.ScriptNode() script["writer"] = GafferDispatchTest.TextWriter() script["writer"]["fileName"].setValue(self.temporaryDirectory() + "/${number}.txt") script["wedge"] = GafferDispatch.Wedge() script["wedge"]["preTasks"][0].setInput(script["writer"]["task"]) script["wedge"]["variable"].setValue("number") script["wedge"]["mode"].setValue( int(GafferDispatch.Wedge.Mode.IntRange)) script["wedge"]["intMin"].setValue(3) script["wedge"]["intMax"].setValue(7) script["wedge"]["intStep"].setValue(2) self.__dispatcher().dispatch([script["wedge"]]) self.assertEqual( set(glob.glob(self.temporaryDirectory() + "/*.txt")), { self.temporaryDirectory() + "/3.txt", self.temporaryDirectory() + "/5.txt", self.temporaryDirectory() + "/7.txt", })
def testFloatList(self): script = Gaffer.ScriptNode() script["writer"] = GafferDispatchTest.TextWriter() script["writer"]["fileName"].setValue(self.temporaryDirectory() + "/${wedge:index}.txt") script["writer"]["text"].setValue("${wedge:value}") script["wedge"] = GafferDispatch.Wedge() script["wedge"]["preTasks"][0].setInput(script["writer"]["task"]) script["wedge"]["mode"].setValue( int(GafferDispatch.Wedge.Mode.FloatList)) script["wedge"]["floats"].setValue( IECore.FloatVectorData([1.25, 2.75, 44.0])) self.__dispatcher().dispatch([script["wedge"]]) self.assertEqual( set(glob.glob(self.temporaryDirectory() + "/*.txt")), { self.temporaryDirectory() + "/0.txt", self.temporaryDirectory() + "/1.txt", self.temporaryDirectory() + "/2.txt", }) self.assertEqual(next(open(self.temporaryDirectory() + "/0.txt")), "1.25") self.assertEqual(next(open(self.temporaryDirectory() + "/1.txt")), "2.75") self.assertEqual(next(open(self.temporaryDirectory() + "/2.txt")), "44")
def testNoOpDoesntBreakFrameParallelism( self ) : # perFrame1 # | # contextVariables # | # perFrame2 s = Gaffer.ScriptNode() log = [] s["perFrame1"] = GafferDispatchTest.LoggingExecutableNode( log = log ) s["perFrame1"]["f"] = Gaffer.StringPlug( defaultValue = "perFrame1.####" ) s["contextVariables"] = GafferDispatch.TaskContextVariables() s["contextVariables"]["preTasks"][0].setInput( s["perFrame1"]["task"] ) s["perFrame2"] = GafferDispatchTest.LoggingExecutableNode( log = log ) s["perFrame2"]["f"] = Gaffer.StringPlug( defaultValue = "perFrame2.####" ) s["perFrame2"]["preTasks"][0].setInput( s["contextVariables"]["task"] ) dispatcher = GafferDispatch.Dispatcher.create( "testDispatcher" ) dispatcher["framesMode"].setValue( dispatcher.FramesMode.CustomRange ) dispatcher["frameRange"].setValue( "1-5" ) dispatcher.dispatch( [ s["perFrame2"] ] ) self.assertEqual( [ l.context.getFrame() for l in log ], [ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 ] ) self.assertEqual( [ l.node for l in log ], [ s["perFrame1"], s["perFrame2"] ] * 5 )
def testSequence(self): s = Gaffer.ScriptNode() s["n"] = GafferDispatch.PythonCommand() s["n"]["command"] = Gaffer.StringPlug( defaultValue="for i in frames:\n\tcontext.setFrame(i)\n\tprint(context.getFrame())", flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) s["n"]["sequence"].setValue(True) s["n"]["dispatcher"]["batchSize"].setValue(1) dispatcher = self.__dispatcher() dispatcher["framesMode"].setValue(dispatcher.FramesMode.CustomRange) dispatcher["frameRange"].setValue("1-50") with mock.patch( "GafferDeadline.DeadlineTools.submitJob", return_value=("testID", "testMessage") ): jobs = self.__job([s["n"]], dispatcher) self.assertEqual(len(jobs), 1) for j in jobs: if j.getJobProperties()["Name"] == "n": self.assertEqual(len(j.getDependencies()), 0) self.assertEqual(len(j.getTasks()), 1)
def testNoOpBatch(self): # n1 # | # t1 # | # n2 s = Gaffer.ScriptNode() s["n1"] = GafferDispatchTest.LoggingTaskNode() s["n1"]["frame"] = Gaffer.StringPlug( defaultValue="${frame}", flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) s["t1"] = GafferDispatch.TaskList() s["t1"]["dispatcher"]["batchSize"].setValue(10) s["t1"]["preTasks"][0].setInput(s["n1"]["task"]) s["n2"] = GafferDispatchTest.LoggingTaskNode() s["n2"]["frame"] = Gaffer.StringPlug( defaultValue="${frame}", flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) s["n2"]["preTasks"][0].setInput(s["t1"]["task"]) dispatcher = self.__dispatcher() dispatcher["framesMode"].setValue(dispatcher.FramesMode.CustomRange) dispatcher["frameRange"].setValue("1-50") with mock.patch( "GafferDeadline.DeadlineTools.submitJob", return_value=("testID", "testMessage") ): self.assertRaises(RuntimeError, dispatcher.dispatch, [s["n2"]])
def testUpstreamConstant(self): script = Gaffer.ScriptNode() script["constant"] = GafferDispatchTest.LoggingTaskNode() script["writer"] = GafferDispatchTest.TextWriter() script["writer"]["preTasks"][0].setInput(script["constant"]["task"]) script["writer"]["fileName"].setValue(self.temporaryDirectory() + "/${name}.txt") script["wedge"] = GafferDispatch.Wedge() script["wedge"]["preTasks"][0].setInput(script["writer"]["task"]) script["wedge"]["variable"].setValue("name") script["wedge"]["mode"].setValue( int(GafferDispatch.Wedge.Mode.StringList)) script["wedge"]["strings"].setValue( IECore.StringVectorData(["tom", "dick", "harry"])) self.__dispatcher().dispatch([script["wedge"]]) self.assertEqual( set(glob.glob(self.temporaryDirectory() + "/*.txt")), { self.temporaryDirectory() + "/tom.txt", self.temporaryDirectory() + "/dick.txt", self.temporaryDirectory() + "/harry.txt", }) # Even though the constant node is upstream from the wedge, # it should only execute once because it doesn't reference # the wedge variable at all. self.assertEqual(len(script["constant"].log), 1)
def testContextModificationsDontLeak(self): command = GafferDispatch.PythonCommand() command["command"].setValue("context.setFrame( 2 )") command["task"].execute() self.assertEqual(Gaffer.Context.current(), Gaffer.Context())
def testRequiresSequenceExecution(self): n = GafferDispatch.PythonCommand() self.assertFalse(n.requiresSequenceExecution()) n["sequence"].setValue(True) self.assertTrue(n.requiresSequenceExecution())
def testComments(self): c = GafferDispatch.PythonCommand() c["command"].setValue("self.test = 10 # this is a comment") c["task"].execute() self.assertEqual(c.test, 10)
def testNestedDispatchBorrowingOuterJobDirectory( self ) : s = Gaffer.ScriptNode() s["nestedTask"] = GafferDispatchTest.TextWriter() s["nestedTask"]["fileName"].setValue( self.temporaryDirectory() + "/nested.txt" ) s["nestedTask"]["text"].setValue( "${dispatcher:jobDirectory} : ${dispatcher:scriptFileName}" ) s["dispatchTask"] = GafferDispatch.PythonCommand() s["dispatchTask"]["command"].setValue( inspect.cleandoc( """ import GafferDispatch dispatcher = GafferDispatch.LocalDispatcher() dispatcher.dispatch( [ self.parent()["nestedTask"] ] ) """ ) ) s["outerTask"] = GafferDispatchTest.TextWriter() s["outerTask"]["preTasks"][0].setInput( s["dispatchTask"]["task"] ) s["outerTask"]["fileName"].setValue( self.temporaryDirectory() + "/outer.txt" ) s["outerTask"]["text"].setValue( "${dispatcher:jobDirectory} : ${dispatcher:scriptFileName}" ) d = self.__createLocalDispatcher() d["executeInBackground"].setValue( True ) d.dispatch( [ s["outerTask"] ] ) d.jobPool().waitForAll() self.assertTrue( os.path.exists( self.temporaryDirectory() + "/nested.txt" ) ) self.assertTrue( os.path.exists( self.temporaryDirectory() + "/outer.txt" ) ) self.assertEqual( open( self.temporaryDirectory() + "/nested.txt" ).readlines(), open( self.temporaryDirectory() + "/outer.txt" ).readlines(), )
def test( self ) : s = Gaffer.ScriptNode() s["c1"] = GafferDispatchTest.LoggingTaskNode() s["c2"] = GafferDispatchTest.LoggingTaskNode() s["s"] = GafferDispatch.TaskSwitch() self.assertEqual( s["s"]["index"].getValue(), 0 ) s["s"]["preTasks"][0].setInput( s["c1"]["task"] ) s["s"]["preTasks"][1].setInput( s["c2"]["task"] ) d = self.__dispatcher() d.dispatch( [ s["s"] ] ) self.assertEqual( len( s["c1"].log ), 1 ) self.assertEqual( len( s["c2"].log ), 0 ) s["s"]["index"].setValue( 1 ) d.dispatch( [ s["s"] ] ) self.assertEqual( len( s["c1"].log ), 1 ) self.assertEqual( len( s["c2"].log ), 1 ) s["s"]["index"].setValue( 2 ) d.dispatch( [ s["s"] ] ) self.assertEqual( len( s["c1"].log ), 2 ) self.assertEqual( len( s["c2"].log ), 1 )
def testImathContextVariable( self ) : s = Gaffer.ScriptNode() s["t"] = GafferDispatchTest.TextWriter() s["t"]["fileName"].setValue( self.temporaryDirectory() + "/test.txt" ) s["e"] = Gaffer.Expression() s["e"].setExpression( inspect.cleandoc( """ c = context["c"] parent["t"]["text"] = "{0} {1} {2}".format( *c ) """ ) ) s["v"] = GafferDispatch.TaskContextVariables() s["v"]["variables"].addChild( Gaffer.NameValuePlug( "c", imath.Color3f( 0, 1, 2 ) ) ) s["v"]["preTasks"][0].setInput( s["t"]["task"] ) d = self.__createLocalDispatcher() d["executeInBackground"].setValue( True ) d.dispatch( [ s["v"] ] ) d.jobPool().waitForAll() self.assertEqual( open( s["t"]["fileName"].getValue() ).read(), "0.0 1.0 2.0" )
def testEnvironmentCommandSubstitutions(self): s = Gaffer.ScriptNode() testFile = os.path.join(self.temporaryDirectory(), "test") s["c"] = GafferDispatch.SystemCommand() s["c"]["command"].setValue( r"echo HELLO \$GAFFERDISPATCHTEST_ENVVAR > " + testFile) dispatcher = self.__createLocalDispatcher() dispatcher["executeInBackground"].setValue(True) dispatcher["framesMode"].setValue( GafferDispatch.Dispatcher.FramesMode.CurrentFrame) dispatcher["environmentCommand"].setValue( "env GAFFERDISPATCHTEST_ENVVAR=$world") with Gaffer.Context() as c: c["world"] = "WORLD" dispatcher.dispatch([s["c"]]) dispatcher.jobPool().waitForAll() with open(testFile) as f: self.assertEqual(f.readlines(), ["HELLO WORLD\n"])
def testSequenceModeStaticVariable( self ) : # We shouldn't need to set a frame in order to read a variable that doesn't depend on frame s = Gaffer.ScriptNode() s["n"] = GafferDispatch.PythonCommand() s["n"]["sequence"].setValue( True ) s["n"]["variables"].addChild( Gaffer.NameValuePlug( "testInt", 42 ) ) commandLines = inspect.cleandoc( """ self.testInt = variables["testInt"] self.frames = frames try : self.numCalls += 1 except AttributeError : self.numCalls = 1 """ ).split( "\n" ) s["n"]["command"].setValue( "\n".join( commandLines ) ) d = self.__dispatcher( frameRange = "1-5" ) d.dispatch( [ s[ "n" ] ] ) self.assertEqual( s["n"].testInt, 42 ) self.assertEqual( s["n"].frames, [ 1, 2, 3, 4, 5 ] ) self.assertEqual( s["n"].numCalls, 1 )
def __writeTask(self, script, args): import GafferDispatch task = script.descendant(args["task"].value) if isinstance(task, GafferDispatch.TaskNode.TaskPlug): task = task.node() if task is None: IECore.msg(IECore.Msg.Level.Error, "stats", "Task \"%s\" does not exist" % args["task"].value) return dispatcher = GafferDispatch.LocalDispatcher() dispatcher["jobsDirectory"].setValue( tempfile.mkdtemp(prefix="gafferStats")) memory = _Memory.maxRSS() with _Timer() as taskTimer: with self.__performanceMonitor or _NullContextManager( ), self.__contextMonitor or _NullContextManager(): with Gaffer.Context(script.context()) as context: for frame in self.__frames(script, args): context.setFrame(frame) dispatcher.dispatch([task]) self.__timers["Task execution"] = taskTimer self.__memory["Task execution"] = _Memory.maxRSS() - memory
def __dispatcher(self, frameRange=None): result = GafferDispatch.LocalDispatcher( jobPool=GafferDispatch.LocalDispatcher.JobPool()) result["jobsDirectory"].setValue(self.temporaryDirectory() + "/jobs") return result
def testFileNameWithFrameDependency(self): script = Gaffer.ScriptNode() script["plane"] = GafferScene.Plane() script["writer"] = GafferScene.SceneWriter() script["writer"]["in"].setInput(script["plane"]["out"]) script["writer"]["fileName"].setValue( os.path.join(self.temporaryDirectory(), "test.####.scc")) dispatcher = GafferDispatch.LocalDispatcher() dispatcher["jobsDirectory"].setValue(self.temporaryDirectory()) dispatcher["framesMode"].setValue(dispatcher.FramesMode.CustomRange) dispatcher["frameRange"].setValue("1-10") dispatcher.dispatch([script["writer"]]) with Gaffer.Context(script.context()) as context: for frame in range(1, 10): context.setFrame(frame) scene = IECoreScene.SceneInterface.create( context.substitute( script["writer"]["fileName"].getValue()), IECore.IndexedIO.OpenMode.Read) plane = scene.child("plane") self.assertEqual(plane.numObjectSamples(), 1) self.assertEqual(plane.objectSampleTime(0), context.getTime())
def test( self ) : s = Gaffer.ScriptNode() s["c1"] = GafferDispatchTest.CountingExecutableNode() s["c2"] = GafferDispatchTest.CountingExecutableNode() s["s"] = GafferDispatch.TaskSwitch() self.assertEqual( s["s"]["index"].getValue(), 0 ) s["s"]["preTasks"][0].setInput( s["c1"]["task"] ) s["s"]["preTasks"][1].setInput( s["c2"]["task"] ) d = self.__dispatcher() d.dispatch( [ s["s"] ] ) self.assertEqual( s["c1"].executionCount, 1 ) self.assertEqual( s["c2"].executionCount, 0 ) s["s"]["index"].setValue( 1 ) d.dispatch( [ s["s"] ] ) self.assertEqual( s["c1"].executionCount, 1 ) self.assertEqual( s["c2"].executionCount, 1 ) s["s"]["index"].setValue( 2 ) d.dispatch( [ s["s"] ] ) self.assertEqual( s["c1"].executionCount, 2 ) self.assertEqual( s["c2"].executionCount, 1 )
def testImath(self): c = GafferDispatch.PythonCommand() c["command"].setValue("self.test = imath.V2i( 1, 2 )") c["task"].execute() self.assertEqual(c.test, imath.V2i(1, 2))
def testFileNameWithArtificalFrameDependency(self): script = Gaffer.ScriptNode() script["plane"] = GafferScene.Plane() script["writer"] = GafferScene.SceneWriter() script["writer"]["in"].setInput(script["plane"]["out"]) fileName = os.path.join(self.temporaryDirectory(), "test.scc") script["expression"] = Gaffer.Expression() script["expression"].setExpression( inspect.cleandoc(""" # Add artificial dependency on frame context.getFrame() parent["writer"]["fileName"] = "{}" """.format(fileName))) dispatcher = GafferDispatch.LocalDispatcher() dispatcher["jobsDirectory"].setValue(self.temporaryDirectory()) dispatcher["framesMode"].setValue(dispatcher.FramesMode.CustomRange) dispatcher["frameRange"].setValue("1-10") dispatcher.dispatch([script["writer"]]) scene = IECoreScene.SceneInterface.create( fileName, IECore.IndexedIO.OpenMode.Read) self.assertEqual(scene.child("plane").numObjectSamples(), 10)
def test(self): n = GafferDispatch.TaskList() with Gaffer.Context() as c: h1 = n["task"].hash() c["frame"] = 10.0 h2 = n["task"].hash() self.assertEqual(h1, h2) n2 = GafferDispatch.TaskList("TaskList2") with Gaffer.Context() as c: self.assertEqual(n2["task"].hash(), h1) c["frame"] = 10.0 self.assertEqual(n2["task"].hash(), h2)
def test( self ) : n = GafferDispatch.SystemCommand() n["command"].setValue( "touch " + self.temporaryDirectory() + "/systemCommandTest.txt" ) n["task"].execute() self.assertTrue( os.path.exists( self.temporaryDirectory() + "/systemCommandTest.txt" ) )
def testScaling(self): # See DispatcherTest.testScaling for details. s = Gaffer.ScriptNode() lastTask = None for i in range(0, 5): perFrame = GafferDispatch.PythonCommand() perFrame["command"].setValue("context.getFrame()") s["perFrame%d" % i] = perFrame if lastTask is not None: perFrame["preTasks"][0].setInput(lastTask["task"]) perSequence = GafferDispatch.PythonCommand() perSequence["command"].setValue("pass") perSequence["sequence"].setValue(True) perSequence["preTasks"][0].setInput(perFrame["task"]) s["perSequence%d" % i] = perSequence lastTask = perSequence d = self.__createLocalDispatcher() d["framesMode"].setValue(d.FramesMode.CustomRange) d["frameRange"].setValue("1-1000") clock = time.process_time if six.PY3 else time.clock t = clock() d.dispatch([lastTask]) timeLimit = 6 if Gaffer.isDebug(): timeLimit *= 2 self.assertLess(clock() - t, timeLimit) d["executeInBackground"].setValue(True) d.dispatch([lastTask]) t = clock() d.jobPool().jobs()[0].kill() self.assertLess(clock() - t, 1) d.jobPool().waitForAll()
def testFrameRangeSubstitutions( self ) : s = Gaffer.ScriptNode() s["n"] = GafferDispatch.SystemCommand() s["n"]["command"].setValue( "touch " + self.temporaryDirectory() + "/systemCommandTest.####.txt" ) d = GafferDispatch.LocalDispatcher() d["jobsDirectory"].setValue( self.temporaryDirectory() + "/jobs" ) d["framesMode"].setValue( d.FramesMode.CustomRange ) d["frameRange"].setValue( "1-10" ) d.dispatch( [ s["n"] ] ) sequences = IECore.ls( self.temporaryDirectory() ) self.assertEqual( len( sequences ), 1 ) self.assertEqual( str( sequences[0] ), "systemCommandTest.####.txt 1-10" )