Skip to content

Commit

Permalink
Merge pull request GafferHQ#5741 from GafferHQ/shuffleCompatImproveme…
Browse files Browse the repository at this point in the history
…ntsAgain

Shuffle compatibility improvements
  • Loading branch information
johnhaddon authored Mar 21, 2024
2 parents c02ce07 + c06ded1 commit 5e95d88
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 15 deletions.
2 changes: 2 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Fixes
- ImageGadget :
- Fixed loading of 2 channel images [^1].
- Fixed error message to include filename [^1].
- Expression : `setExpression()` now respects configs that provide backwards compatibility for old plug names.
- Shuffle : Fixed default name for plugs constructed via the legacy `ChannelPlug( out, in )` constructor [^1].

API
---
Expand Down
35 changes: 20 additions & 15 deletions python/Gaffer/PythonExpressionEngine.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,18 @@ def execute( self, context, inputs ) :
plugDict = {}
for plugPath, plug in zip( self.__inPlugPaths, inputs ) :
parentDict = plugDict
plugPathSplit = plugPath.split( "." )
for p in plugPathSplit[:-1] :
for p in plugPath[:-1] :
parentDict = parentDict.setdefault( p, {} )
if isinstance( plug, Gaffer.CompoundDataPlug ) :
value = IECore.CompoundData()
plug.fillCompoundData( value )
else :
value = plug.getValue()
parentDict[plugPathSplit[-1]] = value
parentDict[plugPath[-1]] = value

for plugPath in self.__outPlugPaths :
parentDict = plugDict
for p in plugPath.split( "." )[:-1] :
for p in plugPath[:-1] :
parentDict = parentDict.setdefault( p, {} )

executionDict = { "imath" : imath, "IECore" : IECore, "parent" : plugDict, "context" : _ContextProxy( context ) }
Expand All @@ -91,17 +90,20 @@ def execute( self, context, inputs ) :
result = IECore.ObjectVector()
for plugPath in self.__outPlugPaths :
parentDict = plugDict
plugPathSplit = plugPath.split( "." )
for p in plugPathSplit[:-1] :
for p in plugPath[:-1] :
parentDict = parentDict[p]
r = parentDict.get( plugPathSplit[-1], IECore.NullObject.defaultNullObject() )
r = parentDict.get( plugPath[-1], IECore.NullObject.defaultNullObject() )
try:
if isinstance( r, pathlib.Path ) :
result.append( r.as_posix() )
else :
result.append( r )
except:
raise TypeError( "Unsupported type for result \"%s\" for expression output \"%s\"" % ( str( r ), plugPath ) )
raise TypeError(
"Unsupported type for result \"{}\" for expression output \"{}\"".format(
r, ".".join( plugPath )
)
)

return result

Expand Down Expand Up @@ -204,14 +206,17 @@ def canExtractValue( plug, topLevelPlug, value ) :

def __plug( self, node, plugPath ) :

plug = node.parent().descendant( plugPath )
try :
plug = node.parent()
for p in plugPath :
plug = plug[p]
except KeyError :
raise RuntimeError( "\"{}\" does not exist".format( ".".join( plugPath ) ) ) from None

if isinstance( plug, Gaffer.ValuePlug ) :
return plug

if plug is None :
raise RuntimeError( "\"%s\" does not exist" % plugPath )
else :
raise RuntimeError( "\"%s\" is not a ValuePlug" % plugPath )
raise RuntimeError( "\"{}\" is not a ValuePlug".format( ".".join( plugPath ) ) )

def __plugRegex( self, node, plug ) :

Expand Down Expand Up @@ -326,9 +331,9 @@ def __path( self, node ) :
def __plugPath( self, path ) :

if len( path ) < 2 or path[0] != "parent" :
return ""
return ()
else :
return ".".join( path[1:] )
return tuple( path[1:] )

def __contextName( self, path ) :

Expand Down
20 changes: 20 additions & 0 deletions python/GafferImageTest/ShuffleTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,5 +412,25 @@ def testIgnoreMissingSourceDoesnCreateChannels( self ) :
shuffle["missingSourceMode"].setValue( shuffle.MissingSourceMode.Ignore )
self.assertEqual( shuffle["out"].channelNames(), IECore.StringVectorData( [ "R", "G", "B", "A" ] ) )

def testLegacyChannelPlugConstructor( self ) :

p = GafferImage.Shuffle.ChannelPlug( "R", "R" )
self.assertEqual( p.getName(), "channel" )

def testCreateExpressionWithLegacyNames( self ) :

script = Gaffer.ScriptNode()
script["shuffle"] = GafferImage.Shuffle()
script["shuffle"]["shuffles"].addChild( GafferImage.Shuffle.ChannelPlug( "R", "R" ) )
script["shuffle"]["shuffles"].addChild( GafferImage.Shuffle.ChannelPlug( "G", "G" ) )

script["expression"] = Gaffer.Expression()
script["expression"].setExpression(
'parent["shuffle"]["channels"]["channel"]["in"] = "X"; parent["shuffle"]["channels"]["channel1"]["in"] = "Y"'
)

self.assertEqual( script["shuffle"]["shuffles"][0]["source"].getValue(), "X" )
self.assertEqual( script["shuffle"]["shuffles"][1]["source"].getValue(), "Y" )

if __name__ == "__main__":
unittest.main()
12 changes: 12 additions & 0 deletions python/GafferTest/ExpressionTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1673,6 +1673,18 @@ def testPathForStringPlug( self ) :

self.assertEqual( script["node"]["in"].getValue(), pathlib.Path.cwd().as_posix() )

def testCreateExpressionWithLegacyPlugName( self ) :

script = Gaffer.ScriptNode()
script["random"] = Gaffer.Random()

script["expression"] = Gaffer.Expression()
script["expression"].setExpression(
'parent["random"]["contextEntry"] = "x"'
)

self.assertEqual( script["random"]["seedVariable"].getValue(), "x" )

@GafferTest.TestRunner.CategorisedTestMethod( { "taskCollaboration:hashAliasing" } )
def testHashAliasing( self ) :

Expand Down
1 change: 1 addition & 0 deletions startup/GafferImage/shuffleCompatibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def __init__( self, *args, **kw ) :
and isinstance( args[0], str ) and isinstance( args[1], str )
) :
Gaffer.ShufflePlug.__init__( self, args[1], args[0] )
self.setName( "channel" )
else :
Gaffer.ShufflePlug.__init__( self, *args, **kw )

Expand Down

0 comments on commit 5e95d88

Please sign in to comment.