Re: [Pyobjc-dev] PyObjcC class method swizzling
Brought to you by:
ronaldoussoren
From: James R E. <Jam...@lr...> - 2009-09-20 17:11:25
|
Hi Lukas, Here's a copy of the method i use. I haven't tried swizzling any classmethods, so it may or may not work for your purposes. One problem I've had in particular with PyObjC decorators is that Objective-C and consequently PyObjC don't like *args and **kwargs- style parameters very well. My workaround is to inspect the decorated method and return the appropriate version from a lookup table. This works in most reasonable cases, but it not as clean as I'd like (If anyone else has a better suggestion, I'd love to hear it!). Anyways, here's my swizzle decorator : # Replacement wrapper lambdas depending on the number of parameters required. Support up to 8 # parameters, including self. This is necessary to suppress a PyObjC DeprecationWarning about # Not all Objective-C arguments being present in the Python argument list (collapsed as *args). __swizzleIMPMap = {0: lambda f: lambda: f(), 1: lambda f: lambda self: f(self), 2: lambda f: lambda self, a: f(self, a), 3: lambda f: lambda self, a, b: f(self, a, b), 4: lambda f: lambda self, a, b, c: f(self, a, b, c), 5: lambda f: lambda self, a, b, c, d: f(self, a, b, c, d), 6: lambda f: lambda self, a, b, c, d, e: f(self, a, b, c, d, e), 7: lambda f: lambda self, a, b, c, d, e, g: f (self, a, b, c, d, e, g), 8: lambda f: lambda self, a, b, c, d, e, g, h: f (self, a, b, c, d, e, g, h), } def swizzleMethod(old): def swizzleWithNewMethod_(f): cls = old.definingClass oldSelectorName = old.__name__.replace("_", ":") oldIMP = cls.instanceMethodForSelector_(oldSelectorName) newSelectorName = f.__name__.replace("_", ":") argc = len(inspect.getargspec(f)[0]) newSEL = objc.selector(f, selector=newSelectorName, signature=old.signature) #oldSEL = objc.selector(lambda self, *args: oldIMP(self, *args), selector=newSelectorName, signature=old.signature) oldSEL = objc.selector(__swizzleIMPMap[argc](oldIMP), selector=newSelectorName, signature=old.signature) # Swap the two methods objc.classAddMethod(cls, newSelectorName, oldSEL) objc.classAddMethod(cls, oldSelectorName, newSEL) #NSLog(u"Swizzled %s.%s <-> %s" % (cls.__name__, oldSelectorName, newSelectorName)) return f return swizzleWithNewMethod_ Use it like this: @swizzle(NSPreferences.sharedPreferences) # Note: this hasn't been tested with classmethods! def sharedPreferences(self): # ... self.sharedPreferences() # Calls the original method # ... Cheers! James Le 19 sept. 2009 à 14:02, Lukas Pitschl | Dressy Vagabonds a écrit : > Hi everyone! > > I've just recently started to explore the power of PyObjC by rewriting > the GPGMail plugin and I'm more than impressed. > A big compliment to the developers! > > Unfortunately at the moment I'm stuck with class method swizzling. > I've found a very nice decorator which can be used > to swizzle instance methods: > > def swizzle(*args): > cls, SEL = args > def decorator(func): > oldIMP = cls.instanceMethodForSelector_(SEL) > def wrapper(self, *args, **kwargs): > return func(self, oldIMP, *args, **kwargs) > newMethod = objc.selector(wrapper, > selector = oldIMP.selector, > signature = oldIMP.signature) > objc.classAddMethod(cls, SEL, newMethod) > return wrapper > return decorator > > My poor attempt to convert this into a decorator which swizzles class > methods looks like the one below, but unfortunately doesn't > work. > > def swizzleClassMethod(*args): > cls, SEL = args > def decorator(func): > oldIMP = cls.methodForSelector_(SEL) > def wrapper(klass, *args, **kwargs): > return func(klass, oldIMP, *args, **kwargs) > newMethod = objc.selector(wrapper, > selector = oldIMP.selector, > signature = oldIMP.signature) > objc.classAddMethod(cls, SEL, newMethod) > return wrapper > return decorator > > I'd really appreciate it, if someone could help me to find out how to > do this. > What I wanna do with that is replacing the + sharedPreferences class > method of the NSPreferences class > with my own implementation and call the original method from within > there. > > Please anyone point me into the right direction, so I can finally > finish the GPGMail plugin. > > Thanks in advance > > Lukas > > ------------------------------------------------------------------------------ > Come build with us! The BlackBerry® Developer Conference in SF, CA > is the only developer event you need to attend this year. Jumpstart > your > developing skills, take BlackBerry mobile applications to market and > stay > ahead of the curve. Join us from November 9-12, 2009. Register > now! > http://p.sf.net/sfu/devconf > _______________________________________________ > Pyobjc-dev mailing list > Pyo...@li... > https://lists.sourceforge.net/lists/listinfo/pyobjc-dev |