""" Python <-> Objective-C bridge (PyObjC) This module defines the core interfaces of the Python<->Objective-C bridge. """ __all__ = ['IBOutlet', 'IBAction', 'accessor', 'Accessor', 'typedAccessor'] from _objc import ivar, selector # # Interface builder support. # def IBOutlet(name): """ Create an instance variable that can be used as an outlet in Interface Builder. """ return ivar(name, isOutlet=1) def IBAction(func): """ Return an Objective-C method object that can be used as an action in Interface Builder. """ return selector(func, signature="v@:@") def accessor(func, typeSignature='@'): """ Return an Objective-C method object that is conformant with key-value coding and key-value observing. """ from inspect import getargspec args, varargs, varkw, defaults = getargspec(func) funcName = func.__name__ maxArgs = len(args) minArgs = maxArgs - len(defaults or ()) # implicit self selArgs = 1 + funcName.count('_') if varargs is not None or varkw is not None: raise TypeError('%s can not be an accessor because it accepts varargs or varkw' % (funcName,)) if not (minArgs <= selArgs <= maxArgs): if selArgs == 3 and (minArgs <= 2 <= maxArgs) and funcName.startswith('validate') and funcName.endswith('_error_'): return selector(func, signature='c@:N^@o^@') elif minArgs == maxArgs: raise TypeError('%s expected to take %d args, but must accept %d from Objective-C (implicit self plus count of underscores)' % (funcName, maxArgs, selArgs)) else: raise TypeError('%s expected to take between %d and %d args, but must accept %d from Objective-C (implicit self plus count of underscores)' % (funcName, minArgs, maxArgs, selArgs)) if selArgs == 3: if funcName.startswith('insertObject_in') and funcName.endswith('AtIndex_'): return selector(func, signature='v@:@i') elif funcName.startswith('replaceObjectIn') and funcName.endswith('AtIndex_withObject_'): return selector(func, signature='v@:i@') # pass through to "too many arguments" elif selArgs == 2: if funcName.startswith('objectIn') and funcName.endswith('AtIndex_'): return selector(func, signature='@@:i') elif funcName.startswith('removeObjectFrom') and funcName.endswith('AtIndex_'): return selector(func, signature='v@:i') elif funcName.startswith('get') and funcName.endswith('_range_'): return selector(func, signature='@@:{_NSRange=ii}') return selector(func, signature="v@:" + typeSignature) elif selArgs == 1: if typeSignature == '@' and func.func_name.startswith('countOf'): typeSignature = 'i' return selector(func, signature=typeSignature + "@:") raise TypeError("%s takes too many arguments to be an accessor" % (funcName,)) def typedAccessor(typeSignature): """ Python 2.4 decorator for creating a typed accessor, usage: @typedAccessor('i') def someIntegerAccessor(self): return self.someInteger @typedAccessor('i') def setSomeIntegerAccessor_(self, anInteger): self.someInteger = anInteger """ def _typedAccessor(func): return accessor(func, typeSignature) return _typedAccessor def Accessor(func): import warnings warnings.warn( "Use objc.accessor instead of objc.Accessor", DeprecationWarning) return accessor(func)