I've been using the Aspects module to trace and patch routines on the fly in my wxPython app. The problem I've run in to occurs when wx binds an event to a function. ie:
an event is binded to function <function func at 0x03969A30>
after aspects.with_wrap() func now becomes <function func at 0x03973030>
the namespace is updated but is seems that wx maintains a copy of the old function in memory rather than just a reference. When the event is triggered the old routine is called rather than the new 'patched' one. So far the only dependable way to fix this is to rebind all of the events to the new routines.... Sometimes events seem to rebind themselves, but I haven't been able to figure out what triggers it.
Below is my 'ActivePatching' module(still a work in progress)a. Also I modified aspects.with_wrap to return (wrapid, newmethod) instead of just the standard wrapid.
from traceback import format_exc as E
from aspects import aspects
import inspect
PRECEDING_TYPE, \
SUCCEEDING_TYPE,\
MUTATING_TYPE, \
OVERRIDING_TYPE = range(4)
def Patch(Type, Target, Patch, *args, **kwargs):
"""Specify patch type: 0:Preceding, 1:Succeeding, 2:Mutating, 3:Overriding"""
try:
return Interceder(Type, Target, Patch, *args, **kwargs)
except:
print E()
class Interceder:
def __init__(self, TYPE, target, patch, *args, **kwargs):
self.aspects = aspects
self.type = TYPE
self.original = target
assert inspect.isroutine(target)
assert hasattr(target, 'im_class') or inspect.isfunction(target)
self.patch = patch
self.p_args = args
self.p_kwargs = kwargs
self.args = ()
self.kwargs= ()
# I modified with_wrap to return the new method as well as the id
self.wrapid, self.newmethod = self.aspects.with_wrap(self.intermediary, target)
self.unwrapper = CreateUnwrapper(self.newmethod)
try:
self.newmethod.__InvokeUnwrapper__ = self.unwrapper
except:
print E()
print "could not attach unwrap method"
def intermediary(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
if self.type == PRECEDING_TYPE:
# patch code is run immediately
# before orginial code
rv = self.patch(*args, **kwargs)
rv = yield self.aspects.proceed
yield self.aspects.return_stop
elif self.type == OVERRIDING_TYPE:
# patch code is run in place
# of original code
rv = self.patch(*args, **kwargs)
yield self.aspects.return_stop(rv)
elif self.type == SUCCEEDING_TYPE:
# patch code is run immediately
# following original code
yield self.aspects.proceed
rv = self.patch(*args, **kwargs)
yield self.aspects.return_stop
elif self.type == MUTATING_TYPE:
# mutating type; receives return from
# original method, processes it, and returns
# its own value
rv = yield self.aspects.proceed
rv = self.patch(rv, *args, **kwargs)
yield self.aspects.return_stop(rv)
def CreateUnwrapper(Routine):
def remove_wrap(routine=Routine):
from aspects import aspects
try:
while hasattr(routine, '__aspects_wrapid'):
routine = aspects.peel_around(routine)
except Exception, e:
print 'unwrapping error', e
return remove_wrap