Skip to content

Commit

Permalink
Merge pull request #3029 from johnhaddon/pythonCommandCrashFix
Browse files Browse the repository at this point in the history
PythonCommand improvements
  • Loading branch information
johnhaddon committed Feb 19, 2019
2 parents 190ca2f + 9e30df9 commit 39df5b1
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 4 deletions.
23 changes: 19 additions & 4 deletions python/GafferDispatch/PythonCommand.py
Expand Up @@ -65,13 +65,16 @@ def hash( self, context ) :

h.append( command )

parser = _Parser( command )
for name in parser.contextReads :
for name in _contextReadsCache.get( command ) :
value = context.get( name )
if isinstance( value, IECore.Object ) :
value.hash( h )
else :
elif value is not None :
h.append( value )
else :
# Variable not in context. Hash a value that is
# extremely unlikely to be found in a context.
h.append( "__pythonCommandMissingContextVariable__" )

self["variables"].hash( h )

Expand All @@ -83,7 +86,7 @@ def hash( self, context ) :
def execute( self ) :

executionDict = self.__executionDict()
exec( self["command"].getValue(), executionDict, executionDict )
exec( _codeObjectCache.get( self["command"].getValue() ), executionDict, executionDict )

def executeSequence( self, frames ) :

Expand Down Expand Up @@ -207,4 +210,16 @@ def visit_Call( self, node ) :

ast.NodeVisitor.generic_visit( self, node )

def __contextReadsCacheGetter( expression ) :

return _Parser( expression ).contextReads, 1

_contextReadsCache = IECore.LRUCache( __contextReadsCacheGetter, 10000 )

def __codeObjectCacheGetter( expression ) :

return compile( expression, "<string>", "exec" ), 1

_codeObjectCache = IECore.LRUCache( __codeObjectCacheGetter, 10000 )

IECore.registerRunTimeTyped( PythonCommand, typeName = "GafferDispatch::PythonCommand" )
29 changes: 29 additions & 0 deletions python/GafferDispatchTest/PythonCommandTest.py
Expand Up @@ -322,5 +322,34 @@ def testEmptyCommand( self ) :
self.assertEqual( c["command"].getValue(), "" )
self.assertEqual( c["task"].hash(), IECore.MurmurHash() )

def testContextGetNone( self ) :

command = Gaffer.PythonCommand()
command["command"].setValue( "print context.get( 'iAmNotHere' )" )

with Gaffer.Context() as c :
h = command["task"].hash()
c["iAmNotHere"] = 10
self.assertNotEqual( command["task"].hash(), h )

def testAlternateMissingContextVariables( self ) :

command = Gaffer.PythonCommand()
command["command"].setValue( "print 'a : ', context.get( 'a' ), 'b : ', context.get( 'b' )" )

neitherHash = command["task"].hash()

with Gaffer.Context() as c :
c["a"] = 10
aHash = command["task"].hash()

with Gaffer.Context() as c :
c["b"] = 10
bHash = command["task"].hash()
c["a"] = 10
bothHash = command["task"].hash()

self.assertEqual( len( { str( x ) for x in ( neitherHash, aHash, bHash, bothHash ) } ), 4 )

if __name__ == "__main__":
unittest.main()

0 comments on commit 39df5b1

Please sign in to comment.