Thanks Daniel. Unfortunately, using two Expressions as you suggest, still makes the expensive one run per frame, per wedge:
import Gaffer
import GafferDispatch
import GafferImage
import IECore
import imath
Gaffer.Metadata.registerValue( parent, "serialiser:milestoneVersion", 0, persistent=False )
Gaffer.Metadata.registerValue( parent, "serialiser:majorVersion", 61, persistent=False )
Gaffer.Metadata.registerValue( parent, "serialiser:minorVersion", 5, persistent=False )
Gaffer.Metadata.registerValue( parent, "serialiser:patchVersion", 0, persistent=False )
__children = {}
parent["variables"].addChild( Gaffer.NameValuePlug( "image:catalogue:port", Gaffer.IntPlug( "value", defaultValue = 0, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ), "imageCataloguePort", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
parent["variables"].addChild( Gaffer.NameValuePlug( "project:name", Gaffer.StringPlug( "value", defaultValue = 'default', flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ), "projectName", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
parent["variables"].addChild( Gaffer.NameValuePlug( "project:rootDirectory", Gaffer.StringPlug( "value", defaultValue = '$HOME/gaffer/projects/${project:name}', flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ), "projectRootDirectory", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
__children["defaultFormat"] = GafferImage.FormatPlug( "defaultFormat", defaultValue = GafferImage.Format( 1920, 1080, 1.000 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, )
parent.addChild( __children["defaultFormat"] )
__children["Text"] = GafferImage.Text( "Text" )
parent.addChild( __children["Text"] )
__children["Text"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["ImageWriter"] = GafferImage.ImageWriter( "ImageWriter" )
parent.addChild( __children["ImageWriter"] )
__children["ImageWriter"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Wedge"] = GafferDispatch.Wedge( "Wedge" )
parent.addChild( __children["Wedge"] )
__children["Wedge"]["preTasks"].addChild( GafferDispatch.TaskNode.TaskPlug( "preTask1", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Wedge"]["ramp"].clearPoints()
__children["Wedge"]["ramp"].addChild( Gaffer.ValuePlug( "p0", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Wedge"]["ramp"]["p0"].addChild( Gaffer.FloatPlug( "x", defaultValue = 0.0, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Wedge"]["ramp"]["p0"].addChild( Gaffer.Color3fPlug( "y", defaultValue = imath.Color3f( 0, 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Wedge"]["ramp"].addChild( Gaffer.ValuePlug( "p1", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Wedge"]["ramp"]["p1"].addChild( Gaffer.FloatPlug( "x", defaultValue = 1.0, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Wedge"]["ramp"]["p1"].addChild( Gaffer.Color3fPlug( "y", defaultValue = imath.Color3f( 1, 1, 1 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Wedge"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["StoreData"] = Gaffer.Node( "StoreData" )
parent.addChild( __children["StoreData"] )
__children["StoreData"]["user"].addChild( Gaffer.StringVectorDataPlug( "data", defaultValue = IECore.StringVectorData( [ ] ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["StoreData"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["CalculateData"] = Gaffer.Expression( "CalculateData" )
parent.addChild( __children["CalculateData"] )
__children["CalculateData"]["__in"].addChild( Gaffer.StringPlug( "p0", defaultValue = '$HOME/gaffer/projects/${project:name}', flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["CalculateData"]["__in"].addChild( Gaffer.StringPlug( "p1", defaultValue = 'default', flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["CalculateData"]["__out"].addChild( Gaffer.IntPlug( "p0", direction = Gaffer.Plug.Direction.Out, defaultValue = 11, minValue = 2, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["CalculateData"]["__out"].addChild( Gaffer.StringVectorDataPlug( "p1", direction = Gaffer.Plug.Direction.Out, defaultValue = IECore.StringVectorData( [ ] ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["CalculateData"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["ContextVariables"] = Gaffer.ContextVariables( "ContextVariables" )
parent.addChild( __children["ContextVariables"] )
__children["ContextVariables"].setup( GafferImage.ImagePlug( "in", ) )
__children["ContextVariables"]["variables"].addChild( Gaffer.NameValuePlug( "", Gaffer.StringPlug( "value", defaultValue = '', flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ), True, "member1", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
__children["ContextVariables"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Expression"] = Gaffer.Expression( "Expression" )
parent.addChild( __children["Expression"] )
__children["Expression"]["__in"].addChild( Gaffer.StringVectorDataPlug( "p0", defaultValue = IECore.StringVectorData( [ ] ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Expression"]["__out"].addChild( Gaffer.StringPlug( "p0", direction = Gaffer.Plug.Direction.Out, defaultValue = '', flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Expression"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
parent["frameRange"]["start"].setValue( 1001 )
parent["frameRange"]["end"].setValue( 1024 )
parent["frame"].setValue( 1001.0 )
parent["variables"]["imageCataloguePort"]["value"].setValue( 38396 )
parent["variables"]["projectName"]["value"].setValue( 'expensiveExpression' )
Gaffer.Metadata.registerValue( parent["variables"]["imageCataloguePort"], 'readOnly', True )
Gaffer.Metadata.registerValue( parent["variables"]["projectName"]["name"], 'readOnly', True )
Gaffer.Metadata.registerValue( parent["variables"]["projectRootDirectory"]["name"], 'readOnly', True )
__children["Text"]["out"].setInput( __children["Text"]["__merge"]["out"] )
__children["Text"]["text"].setValue( '${mydata}\n${frame}' )
__children["Text"]["area"].setValue( imath.Box2i( imath.V2i( 0, 0 ), imath.V2i( 1920, 1080 ) ) )
__children["Text"]["__uiPosition"].setValue( imath.V2f( 4.94926643, 15.5640621 ) )
__children["ImageWriter"]["in"].setInput( __children["ContextVariables"]["out"] )
__children["ImageWriter"]["fileName"].setValue( '${project:rootDirectory}/${project:name}_${wedge:index}/${project:name}_${wedge:index}.####.jpg' )
__children["ImageWriter"]["__uiPosition"].setValue( imath.V2f( 3.44926524, -0.764061749 ) )
__children["Wedge"]["preTasks"][0].setInput( __children["ImageWriter"]["task"] )
__children["Wedge"]["floatSteps"].setInput( __children["CalculateData"]["__out"]["p0"] )
__children["Wedge"]["__uiPosition"].setValue( imath.V2f( 4.14926529, -8.92812347 ) )
__children["StoreData"]["user"]["data"].setInput( __children["CalculateData"]["__out"]["p1"] )
Gaffer.Metadata.registerValue( __children["StoreData"]["user"]["data"], 'nodule:type', '' )
__children["StoreData"]["__uiPosition"].setValue( imath.V2f( -17.2999916, 7.05000067 ) )
Gaffer.Metadata.registerValue( __children["CalculateData"], 'nodeGadget:type', 'GafferUI::StandardNodeGadget' )
__children["CalculateData"]["__in"]["p0"].setInput( parent["variables"]["projectRootDirectory"]["value"] )
__children["CalculateData"]["__in"]["p1"].setInput( parent["variables"]["projectName"]["value"] )
__children["CalculateData"]["__uiPosition"].setValue( imath.V2f( -17.1999969, -8.75000095 ) )
__children["ContextVariables"]["variables"]["member1"]["name"].setValue( 'mydata' )
__children["ContextVariables"]["variables"]["member1"]["value"].setInput( __children["Expression"]["__out"]["p0"] )
__children["ContextVariables"]["in"].setInput( __children["Text"]["out"] )
Gaffer.Metadata.registerValue( __children["ContextVariables"]["in"], 'noduleLayout:section', 'top' )
Gaffer.Metadata.registerValue( __children["ContextVariables"]["out"], 'noduleLayout:section', 'bottom' )
__children["ContextVariables"]["__uiPosition"].setValue( imath.V2f( 4.94926643, 7.40000057 ) )
__children["Expression"]["__in"]["p0"].setInput( __children["StoreData"]["user"]["data"] )
__children["Expression"]["__uiPosition"].setValue( imath.V2f( -6.32661057, 7.39918041 ) )
__children["CalculateData"]["__engine"].setValue( 'python' )
__children["CalculateData"]["__expression"].setValue( 'import datetime\n\nEXPENSIVE_DATA = ["alice", "bob"]\n\nwith open("%s/%s.log" % (parent["__in"]["p0"], parent["__in"]["p1"]), "a") as f:\n f.write(datetime.datetime.now().isoformat(" ") + "\\n")\n\nparent["__out"]["p0"] = len(EXPENSIVE_DATA)\nparent["__out"]["p1"] = IECore.StringVectorData(EXPENSIVE_DATA)' )
__children["Expression"]["__engine"].setValue( 'python' )
__children["Expression"]["__expression"].setValue( 'data = parent["__in"]["p0"]\nparent["__out"]["p0"] = data[context["wedge:index"]]' )
del __children