Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class HookType:
- '''
- Pre - Calls the callback before the orignal function
- Post - Calls the callback after the orignal function
- '''
- Pre, Post = range(2)
- class Override(object):
- '''
- Return an object of this class to use a custom return value.
- EXAMPLES:
- Override() -> None
- Override(1) -> 1
- Override(1, 2) -> (1, 2)
- '''
- def __init__(self, *args):
- self.args = args
- def getReturnValue(self):
- return self.args[0] if len(self.args) == 1 else self.args or None
- class Detour(object):
- '''
- Detours a function by overriding it with a Detour instance.
- EXAMPLE:
- def myfunc(x, y):
- print 'Original function:', (x, y)
- return x + y
- def mycallback(args, kw):
- print 'Detour callback:', (args, kw)
- # Set the first parameter to 10
- args[0] = 10
- myfunc = Detour.detourFunction(myfunc, HookType.Pre, mycallback)
- print myfunc(1, 2), type(myfunc)
- myfunc = Detour.undetourFunction(myfunc, HookType.Pre, mycallback)
- print myfunc(1, 2), type(myfunc)
- OUTPUT:
- >>> Detour callback: ([1, 2], {})
- >>> Original function: (10, 2)
- >>> 12 <class 'Detour'>
- >>> Original function: (1, 2)
- >>> 3 <type 'function'>
- '''
- def __new__(cls, func, hooktype, callback):
- # Function already detoured?
- if isinstance(func, Detour):
- func.callbacks[hooktype].add(callback)
- return func
- # Create a detour
- self = super(Detour, cls).__new__(cls, func, hooktype, callback)
- self.trampoline = func
- self.callbacks = {HookType.Pre: set(), HookType.Post: set()}
- return self
- def __init__(self, func, hooktype, callback):
- self.callbacks[hooktype].add(callback)
- def __call__(self, *args, **kw):
- # Convert "args" into a list, so we can modify the parameters
- args = list(args)
- ret = None
- # Do pre-calls
- for callback in self.callbacks[HookType.Pre]:
- temp = callback(args, kw)
- if isinstance(temp, Override):
- ret = temp
- # Was an Override instance returned?
- if ret is not None:
- return ret.getReturnValue()
- # Call the trampoline
- ret = self.trampoline(*args, **kw)
- # Do post-calls
- for callback in self.callbacks[HookType.Post]:
- temp = callback(args, kw, ret)
- if isinstance(temp, Override):
- ret = temp
- return ret.getReturnValue() if isinstance(ret, Override) else ret
- @classmethod
- def detourFunction(cls, func, hooktype, callback):
- return cls(func, hooktype, callback)
- @staticmethod
- def undetourFunction(func, hooktype, callback):
- func.callbacks[hooktype].discard(callback)
- return func if any(func.callbacks.values()) else func.trampoline
Advertisement
Add Comment
Please, Sign In to add comment