115 lines
5.2 KiB
Python
Executable File
115 lines
5.2 KiB
Python
Executable File
'''
|
|
Description:
|
|
This module allows us to easily instrument Modules, Classes, Functions and Methods.
|
|
The primary use for this is to allow us to use the pyfbsdk with cProfile.
|
|
|
|
Doesn't work with static/class methods only with instance methods
|
|
|
|
Author:
|
|
Ross George
|
|
'''
|
|
|
|
import compiler
|
|
|
|
_instrumentedMethodClosures = dict()
|
|
_instrumentedMethodIdPairings = dict()
|
|
def InstrumentMethod( targetClass, targetMethodName ):
|
|
|
|
#Get the target function and it's Id
|
|
targetInnerMethod = getattr( targetClass, targetMethodName )
|
|
targetInnerMethodId = id( targetInnerMethod )
|
|
|
|
#Check if we have processed this method
|
|
if ( _instrumentedMethodIdPairings.has_key( targetInnerMethodId ) ): return()
|
|
|
|
#Add the function to our closures list so that we can call it later
|
|
#We use the objects ID to do this.
|
|
_instrumentedMethodClosures[ targetInnerMethodId ] = targetInnerMethod
|
|
|
|
#Get the name we will give the outer function (this is how it will
|
|
#appear on the profiler so it's important that it is descriptive)
|
|
targetOuterFunctionName = '{0}_{1}_{2}'.format( targetClass.__module__, targetClass.__name__, targetMethodName )
|
|
|
|
#Compile into a function. We do this because we want the correct function and filename to appear on the profile stats.
|
|
outerFunctionSource = 'def {0}( *args, **kwargs ): return( _instrumentedMethodClosures[{1}]( *args, **kwargs ) )'.format( targetOuterFunctionName, targetInnerMethodId )
|
|
outerFunctionCompiled = compiler.compile( outerFunctionSource, 'pyfbsdk.pyc', 'exec' )
|
|
exec( outerFunctionCompiled )
|
|
|
|
#Get the outer function ready to override the inner method on our targetClass
|
|
exec( 'targetOuterFunction = {0}'.format( targetOuterFunctionName ) )
|
|
|
|
#Add this function to our list of functions that have been instrumented
|
|
outerFunctionId = id( targetOuterFunction )
|
|
_instrumentedMethodIdPairings[ outerFunctionId ] = targetInnerMethodId
|
|
|
|
#Finally we set the attribute on the class
|
|
setattr( targetClass, targetMethodName, targetOuterFunction )
|
|
|
|
_instrumentedFunctionClosures = dict()
|
|
_instrumentedFunctionIdPairings = dict()
|
|
def InstrumentFunction( targetModule, targetFunctionName ):
|
|
|
|
#Get the target function
|
|
targetInnerFunction = getattr( targetModule, targetFunctionName )
|
|
targetInnerFunctionId = id( targetInnerFunction )
|
|
|
|
#Check if we have processed this function
|
|
if ( _instrumentedFunctionIdPairings.has_key( targetInnerFunctionId ) ): return()
|
|
|
|
#Add the function to our closures list so that we can call it later
|
|
#We use the objects ID to do this.
|
|
_instrumentedFunctionClosures[ targetInnerFunctionId ] = targetInnerFunction
|
|
|
|
#Get the name we will give the outer function (this is how it will
|
|
#appear on the profiler so it's important that it is descriptive)
|
|
targetOuterFunctionName = '{0}_{1}'.format( targetModule.__name__, targetFunctionName )
|
|
|
|
#Compile into a function. We do this because we want the correct function and filename to appear on the profile stats.
|
|
outerFunctionSource = 'def {0}( *args, **kwargs ): return( _instrumentedFunctionClosures[{1}]( *args, **kwargs ) )'.format( targetOuterFunctionName, targetInnerFunctionId )
|
|
outerFunctionCompiled = compiler.compile( outerFunctionSource, 'pyfbsdk.pyc', 'exec' )
|
|
exec( outerFunctionCompiled )
|
|
|
|
#Get the outer function ready to override our inner function
|
|
exec( 'targetOuterFunction = {0}'.format( targetOuterFunctionName ) )
|
|
|
|
#Add this function to our list of functions that have been instrumented
|
|
outerFunctionId = id( targetOuterFunction )
|
|
_instrumentedFunctionIdPairings[ outerFunctionId ] = targetInnerFunctionId
|
|
|
|
#Finally we set the attribute on the module
|
|
setattr( targetModule, targetFunctionName, targetOuterFunction )
|
|
|
|
_instrumentedClassIdList = list()
|
|
def InstrumentClass( targetClass ):
|
|
|
|
#Check we haven't already processed this class
|
|
targetClassId = id( targetClass )
|
|
if targetClassId in _instrumentedClassIdList: return()
|
|
|
|
for attributeKey in dir( targetClass ):
|
|
attributeValue = getattr( targetClass, attributeKey )
|
|
|
|
if ( 'instancemethod' in type( attributeValue ).__name__ ):
|
|
InstrumentMethod( targetClass, attributeKey )
|
|
|
|
#Add the class so that we don't process it again
|
|
_instrumentedClassIdList.append( targetClassId )
|
|
|
|
_instrumentedModuleIdList = list()
|
|
def InstrumentModule( targetModule ):
|
|
|
|
#Check we haven't already processed this module
|
|
targetModuleId = id( targetModule )
|
|
if targetModuleId in _instrumentedModuleIdList: return()
|
|
|
|
for attributeKey in dir( targetModule ):
|
|
attributeValue = getattr( targetModule, attributeKey )
|
|
|
|
if ( 'function' in type( attributeValue ).__name__ ):
|
|
InstrumentFunction( targetModule, attributeKey )
|
|
|
|
if ( 'class' in type( attributeValue ).__name__ ):
|
|
InstrumentClass( attributeValue )
|
|
|
|
#Add the module so that we don't process it again
|
|
_instrumentedModuleIdList.append( targetModuleId ) |