first commit
This commit is contained in:
64
objc/_FoundationSignatures.py
Executable file
64
objc/_FoundationSignatures.py
Executable file
@@ -0,0 +1,64 @@
|
||||
from _objc import setSignatureForSelector
|
||||
|
||||
setSignatureForSelector("NSScanner", "scanCharactersFromSet:intoString:", "c@:@o^@")
|
||||
setSignatureForSelector("NSScanner", "scanDouble:", "c@:o^d")
|
||||
setSignatureForSelector("NSScanner", "scanFloat:", "c@:o^f")
|
||||
setSignatureForSelector("NSScanner", "scanHexInt:", "c@:o^I")
|
||||
setSignatureForSelector("NSScanner", "scanInt:", "c@:o^i")
|
||||
setSignatureForSelector("NSScanner", "scanLongLong:", "c@:o^q")
|
||||
setSignatureForSelector("NSScanner", "scanString:intoString:", "c@:@o^@")
|
||||
setSignatureForSelector("NSScanner", "scanUpToCharactersFromSet:intoString:", "c@:@o^@")
|
||||
setSignatureForSelector("NSScanner", "scanUpToString:intoString:", "c@:@o^@")
|
||||
setSignatureForSelector("NSStream", "getStreamsToHost:port:inputStream:outputStream:", "v@:@io^@o^@")
|
||||
setSignatureForSelector("NSString", "completePathIntoString:caseSensitive:matchesIntoArray:filterTypes:", "I@:o^@co^@@")
|
||||
setSignatureForSelector("NSString", "getLineStart:end:contentsEnd:forRange:", "v@:o^Io^Io^I{_NSRange=II}")
|
||||
setSignatureForSelector("NSMutableAttributedString", "readFromURL:options:documentAttributes:", "c@:@@o^@")
|
||||
setSignatureForSelector("NSAttributedString", "attribute:atIndex:effectiveRange:", "@0@4:8@12I16o^{_NSRange=II}20")
|
||||
setSignatureForSelector("NSAttributedString", "attribute:atIndex:longestEffectiveRange:inRange:", "@0@4:8@12I16o^{_NSRange=II}20{_NSRange=II}24")
|
||||
setSignatureForSelector("NSAttributedString", "attributesAtIndex:effectiveRange:", "@0@4:8I12o^{_NSRange=II}16")
|
||||
setSignatureForSelector("NSAttributedString", "attributesAtIndex:longestEffectiveRange:inRange:", "@0@4:8I12o^{_NSRange=II}16{_NSRange=II}20")
|
||||
setSignatureForSelector("NSAttributedString", "initWithHTML:baseURL:documentAttributes:", "@0@4:8@12@16o^@20")
|
||||
setSignatureForSelector("NSAttributedString", "initWithHTML:documentAttributes:", "@@:@o^@")
|
||||
setSignatureForSelector("NSAttributedString", "initWithPath:documentAttributes:", "@@:@o^@")
|
||||
setSignatureForSelector("NSAttributedString", "initWithRTFDFileWrapper:documentAttributes:", "@@:@o^@")
|
||||
setSignatureForSelector("NSAttributedString", "initWithRTFD:documentAttributes:", "@0@4:8@12o^@16")
|
||||
setSignatureForSelector("NSAttributedString", "initWithRTF:documentAttributes:", "@0@4:8@12o^@16")
|
||||
setSignatureForSelector("NSAttributedString", "initWithURL:documentAttributes:", "@0@4:8@12o^@16")
|
||||
setSignatureForSelector("NSFileManager", "fileExistsAtPath:isDirectory:", "c0@4:8@12o^c16")
|
||||
setSignatureForSelector("NSArray", "getObject:atIndex:", "c@:o^@I")
|
||||
setSignatureForSelector("NSCalendarDate", "years:months:days:hours:minutes:seconds:sinceDate:", "v@:o^io^io^io^io^io^i@")
|
||||
setSignatureForSelector("NSPropertyListSerialization", "dataFromPropertyList:format:errorDescription:", "@@:@io^@")
|
||||
setSignatureForSelector("NSPropertyListSerialization", "propertyListFromData:mutabilityOption:format:errorDescription:", "@@:@io^io^@")
|
||||
setSignatureForSelector("NSAppleScript", "_initWithContentsOfFile:error:", "@@:@o^@")
|
||||
setSignatureForSelector("NSAppleScript", "_initWithData:error:", "@@:@o^@")
|
||||
setSignatureForSelector("NSAppleScript", "compileAndReturnError:", "c@:o^@")
|
||||
setSignatureForSelector("NSAppleScript", "executeAndReturnError:", "@@:o^@")
|
||||
setSignatureForSelector("NSAppleScript", "executeAppleEvent:error:", "@@:@o^@")
|
||||
setSignatureForSelector("NSAppleScript", "initWithContentsOfURL:error:", "@@:@o^@")
|
||||
setSignatureForSelector("NSFaultHandler", "extraData", "i@:")
|
||||
setSignatureForSelector("NSFaultHandler", "setTargetClass:extraData:", "v@:#i")
|
||||
setSignatureForSelector("NSFormatter", "getObjectValue:forString:errorDescription:", "c@:o^@@o^@")
|
||||
setSignatureForSelector("NSFormatter", "isPartialStringValid:newEditingString:errorDescription:", "c@:@o^@o^@")
|
||||
setSignatureForSelector("NSFormatter", "isPartialStringValid:proposedSelectedRange:originalString:originalSelectedRange:errorDescription:", "c0@4:8o^@12o^{_NSRange=II}16@20{_NSRange=II}24o^@32")
|
||||
|
||||
setSignatureForSelector("NSObject", "validateValue:forKey:error:", "c@:N^@@o^@")
|
||||
setSignatureForSelector("NSObject", "validateValue:forKeyPath:error:", "c@:N^@@o^@")
|
||||
setSignatureForSelector("NSObject", "addObserver:forKeyPath:options:context:",
|
||||
"v@:@@Ii")
|
||||
setSignatureForSelector("NSObject", "observeValueForKeyPath:ofObject:change:context:", "v@:@@@i")
|
||||
setSignatureForSelector("NSArray", "addObserver:toObjectsAtIndexes:forKeyPath:options:context:", 'v@:@@@Ii')
|
||||
setSignatureForSelector("NSURLConnection", "sendSynchronousRequest:returningResponse:error:", "@@:@o^@o^@")
|
||||
setSignatureForSelector("NSString", "getParagraphStart:end:contentsEnd:forRange:", "v@:o^Io^Io^I{_NSRange=II}")
|
||||
setSignatureForSelector("NSMutableAttributedString", "readFromData:options:documentAttributes:", "c@:@@o^@")
|
||||
setSignatureForSelector("NSAttributedString", "initWithHTML:options:documentAttributes:", "@20@0:4@8@12o^@16")
|
||||
setSignatureForSelector("NSAttributedString", "initWithDocFormat:documentAttributes:", "@@:@o^@")
|
||||
setSignatureForSelector("NSKeyValueProperty", "keyPathIfAffectedByValueForKey:exactMatch:", "@@:@o^c")
|
||||
setSignatureForSelector("NSKeyValueObservationForwarder", "initWithObserver:relationshipKey:keyPathFromRelatedObject:options:context:", "@@:@@@Ii")
|
||||
setSignatureForSelector("NSDeserializer", "deserializePropertyListFromData:atCursor:mutableContainers:", "@@:@O^Ic")
|
||||
setSignatureForSelector("NSDeserializer", "deserializePropertyListLazilyFromData:atCursor:length:mutableContainers:", "@@:@O^IIc")
|
||||
setSignatureForSelector("OC_PythonObject", "addObserver:forKeyPath:options:context:", "v@:@@Ii")
|
||||
|
||||
|
||||
# Technically incorrect, but not used anyway
|
||||
setSignatureForSelector("NSObject", "setObservationInfo:", "v@:i")
|
||||
setSignatureForSelector("NSObject", "observationInfo", "i@:")
|
||||
40
objc/__init__.py
Executable file
40
objc/__init__.py
Executable file
@@ -0,0 +1,40 @@
|
||||
"""
|
||||
Python <-> Objective-C bridge (PyObjC)
|
||||
|
||||
This module defines the core interfaces of the Python<->Objective-C bridge.
|
||||
"""
|
||||
|
||||
# Aliases for some common Objective-C constants
|
||||
nil = None
|
||||
YES = True
|
||||
NO = False
|
||||
|
||||
# Import the namespace from the _objc extension
|
||||
def _update(g=globals()):
|
||||
import _objc
|
||||
for k,v in _objc.__dict__.iteritems():
|
||||
g.setdefault(k,v)
|
||||
_update()
|
||||
del _update
|
||||
|
||||
from _convenience import *
|
||||
import _FoundationSignatures
|
||||
|
||||
# Add useful utility functions below
|
||||
if platform == 'MACOSX':
|
||||
from _dyld import *
|
||||
else:
|
||||
from _gnustep import *
|
||||
|
||||
from _protocols import *
|
||||
from _descriptors import *
|
||||
from _category import *
|
||||
from _bridges import *
|
||||
from _compat import *
|
||||
from _pythonify import *
|
||||
from _functions import *
|
||||
|
||||
###
|
||||
# This can be usefull to hunt down memory problems in the testsuite.
|
||||
#import atexit
|
||||
#atexit.register(recycleAutoreleasePool)
|
||||
30
objc/_bridges.py
Executable file
30
objc/_bridges.py
Executable file
@@ -0,0 +1,30 @@
|
||||
from _objc import *
|
||||
|
||||
__all__ = []
|
||||
|
||||
BRIDGED_STRUCTURES = {}
|
||||
BRIDGED_TYPES = []
|
||||
|
||||
try:
|
||||
from array import array
|
||||
from Carbon.File import FSRef
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
def struct_to_FSRef(s):
|
||||
return FSRef(rawdata=array('B', s[0]).tostring())
|
||||
BRIDGED_STRUCTURES['{FSRef=[80C]}'] = struct_to_FSRef
|
||||
|
||||
def FSRef_to_struct(fsRef):
|
||||
return (tuple(array('B').fromstring(fsRef.data)),)
|
||||
BRIDGED_TYPES.append((FSRef, FSRef_to_struct))
|
||||
|
||||
def _bridgePythonTypes():
|
||||
# python TO Obj-C
|
||||
OC_PythonObject = lookUpClass('OC_PythonObject')
|
||||
if BRIDGED_TYPES:
|
||||
OC_PythonObject.depythonifyTable().extend(BRIDGED_TYPES)
|
||||
if BRIDGED_STRUCTURES:
|
||||
OC_PythonObject.pythonifyStructTable().update(BRIDGED_STRUCTURES)
|
||||
|
||||
_bridgePythonTypes()
|
||||
63
objc/_category.py
Executable file
63
objc/_category.py
Executable file
@@ -0,0 +1,63 @@
|
||||
__all__ = ['classAddMethod', 'Category']
|
||||
|
||||
from _objc import selector, classAddMethods, objc_class
|
||||
|
||||
def classAddMethod(cls, name, method):
|
||||
"""
|
||||
Add a single method to a class. 'name' is the ObjC selector
|
||||
"""
|
||||
if isinstance(method, selector):
|
||||
sel = selector(method.callable,
|
||||
selector=name,
|
||||
signature=method.signature,
|
||||
isClassMethod=method.isClassMethod)
|
||||
else:
|
||||
sel = selector(method, selector=name)
|
||||
|
||||
return classAddMethods(cls, [sel])
|
||||
|
||||
|
||||
#
|
||||
# Syntactic support for categories
|
||||
#
|
||||
|
||||
class _CategoryMeta(type):
|
||||
"""
|
||||
Meta class for categories.
|
||||
"""
|
||||
__slots__ = ()
|
||||
_IGNORENAMES = ('__module__', '__name__')
|
||||
def _newSubclass(cls, name, bases, methods):
|
||||
return type.__new__(cls, name, bases, methods)
|
||||
_newSubclass = classmethod(_newSubclass)
|
||||
|
||||
def __new__(cls, name, bases, methods):
|
||||
if len(bases) != 1:
|
||||
raise TypeError, "Cannot have multiple inheritance with Categories"
|
||||
|
||||
c = bases[0].real_class
|
||||
|
||||
if c.__name__ != name:
|
||||
raise TypeError, "Category name must be same as class name"
|
||||
|
||||
m = [ x[1] for x in methods.iteritems() if x[0] not in cls._IGNORENAMES ]
|
||||
classAddMethods(c, m)
|
||||
return c
|
||||
|
||||
def Category(cls):
|
||||
"""
|
||||
Create a category on ``cls``.
|
||||
|
||||
Usage:
|
||||
class SomeClass (Category(SomeClass)):
|
||||
def method(self):
|
||||
pass
|
||||
|
||||
``SomeClass`` is an existing class that will be rebound to the same
|
||||
value. The side-effect of this class definition is that the methods
|
||||
in the class definition will be added to the existing class.
|
||||
"""
|
||||
if not isinstance(cls, objc_class):
|
||||
raise TypeError, "Category can only be used on Objective-C classes"
|
||||
retval = _CategoryMeta._newSubclass('Category', (), dict(real_class=cls))
|
||||
return retval
|
||||
58
objc/_compat.py
Executable file
58
objc/_compat.py
Executable file
@@ -0,0 +1,58 @@
|
||||
__all__ = ['runtime', 'pluginBundle', 'registerPlugin']
|
||||
|
||||
class Runtime:
|
||||
"""
|
||||
Backward compatibility interface.
|
||||
|
||||
This class provides (partial) support for the interface of
|
||||
older versions of PyObjC.
|
||||
"""
|
||||
def __getattr__(self, name):
|
||||
import warnings
|
||||
warnings.warn("Deprecated: use objc.lookUpClass",
|
||||
DeprecationWarning)
|
||||
import objc
|
||||
if name == '__objc_classes__':
|
||||
return objc.getClassList()
|
||||
elif name == '__kind__':
|
||||
return 'python'
|
||||
|
||||
try:
|
||||
return objc.lookUpClass(name)
|
||||
except objc.nosuchclass_error:
|
||||
raise AttributeError, name
|
||||
|
||||
def __eq__(self, other):
|
||||
return self is other
|
||||
|
||||
def __repr__(self):
|
||||
return "objc.runtime"
|
||||
|
||||
runtime = Runtime()
|
||||
|
||||
_PLUGINS = {}
|
||||
def registerPlugin(pluginName):
|
||||
"""
|
||||
Deprecated: use currentBundle()
|
||||
|
||||
Register the current py2app plugin by name and return its bundle
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
path = os.path.dirname(os.path.dirname(os.environ['RESOURCEPATH']))
|
||||
if not isinstance(path, unicode):
|
||||
path = unicode(path, sys.getfilesystemencoding())
|
||||
_PLUGINS[pluginName] = path
|
||||
return pluginBundle(pluginName)
|
||||
|
||||
def pluginBundle(pluginName):
|
||||
"""
|
||||
Deprecated: use currentBundle()
|
||||
|
||||
Return the main bundle for the named plugin. This should be used
|
||||
only after it has been registered with registerPlugin
|
||||
"""
|
||||
import warnings
|
||||
warnings.warn("Deprecated: use currentBundle()", DeprecationWarning)
|
||||
from Foundation import NSBundle
|
||||
return NSBundle.bundleWithPath_(_PLUGINS[pluginName])
|
||||
602
objc/_convenience.py
Executable file
602
objc/_convenience.py
Executable file
@@ -0,0 +1,602 @@
|
||||
"""
|
||||
This module implements a callback function that is used by the C code to
|
||||
add Python special methods to Objective-C classes with a suitable interface.
|
||||
|
||||
This module contains no user callable code.
|
||||
|
||||
TODO:
|
||||
- Add external interface: Framework specific modules may want to add to this.
|
||||
|
||||
- These are candidates for implementation:
|
||||
|
||||
>>> from Foundation import *
|
||||
>>> set(dir(list)) - set(dir(NSMutableArray))
|
||||
set(['__delslice__', '__imul__', '__getslice__', '__setslice__',
|
||||
'__iadd__', '__mul__', '__add__', '__rmul__'])
|
||||
>>> set(dir(dict)) - set(dir(NSMutableDictionary))
|
||||
set(['__cmp__'])
|
||||
|
||||
"""
|
||||
from _objc import setClassExtender, selector, lookUpClass, currentBundle, repythonify, splitSignature
|
||||
from itertools import imap
|
||||
|
||||
__all__ = ['CONVENIENCE_METHODS', 'CLASS_METHODS']
|
||||
|
||||
CONVENIENCE_METHODS = {}
|
||||
CLASS_METHODS = {}
|
||||
|
||||
NSObject = lookUpClass('NSObject')
|
||||
|
||||
HAS_KVO = NSObject.instancesRespondToSelector_('willChangeValueForKey:')
|
||||
|
||||
def isNative(sel):
|
||||
return not hasattr(sel, 'callable')
|
||||
|
||||
def add_convenience_methods(super_class, name, type_dict):
|
||||
try:
|
||||
return _add_convenience_methods(super_class, name, type_dict)
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
raise
|
||||
|
||||
|
||||
def _add_convenience_methods(super_class, name, type_dict):
|
||||
"""
|
||||
Add additional methods to the type-dict of subclass 'name' of
|
||||
'super_class'.
|
||||
|
||||
CONVENIENCE_METHODS is a global variable containing a mapping from
|
||||
an Objective-C selector to a Python method name and implementation.
|
||||
|
||||
CLASS_METHODS is a global variable containing a mapping from
|
||||
class name to a list of Python method names and implementation.
|
||||
|
||||
Matching entries from both mappings are added to the 'type_dict'.
|
||||
"""
|
||||
if type_dict.get('__objc_python_subclass__'):
|
||||
if 'bundleForClass' not in type_dict:
|
||||
cb = currentBundle()
|
||||
def bundleForClass(cls):
|
||||
return cb
|
||||
type_dict['bundleForClass'] = selector(bundleForClass, isClassMethod=True)
|
||||
if (HAS_KVO and
|
||||
'__useKVO__' not in type_dict and
|
||||
isNative(type_dict.get('willChangeValueForKey_')) and
|
||||
isNative(type_dict.get('didChangeValueForKey_'))):
|
||||
useKVO = issubclass(super_class, NSObject)
|
||||
type_dict['__useKVO__'] = useKVO
|
||||
if '__bundle_hack__' in type_dict:
|
||||
import warnings
|
||||
warnings.warn(
|
||||
"__bundle_hack__ is not necessary in PyObjC 1.3+ / py2app 0.1.8+",
|
||||
DeprecationWarning)
|
||||
|
||||
for k, sel in type_dict.items():
|
||||
if not isinstance(sel, selector):
|
||||
continue
|
||||
|
||||
if sel.selector == "alloc" or sel.selector == "allocWithZone:":
|
||||
sel.isAlloc = 1
|
||||
|
||||
if sel.selector.endswith(':error:'):
|
||||
sigParts = splitSignature(sel.signature)
|
||||
if sigParts[-1] == '^@':
|
||||
sigParts = sigParts[:-1] + ('o^@',)
|
||||
sel.signature = ''.join(sigParts)
|
||||
|
||||
if sel.selector in ( 'copy', 'copyWithZone:',
|
||||
'mutableCopy', 'mutableCopyWithZone:'):
|
||||
# These methods transfer ownership to the caller, the runtime uses
|
||||
# this information to adjust the reference count.
|
||||
sel.doesDonateReference = 1
|
||||
|
||||
sel = sel.selector
|
||||
|
||||
if sel in CONVENIENCE_METHODS:
|
||||
v = CONVENIENCE_METHODS[sel]
|
||||
for nm, value in v:
|
||||
if nm in type_dict and isinstance(type_dict[nm], selector):
|
||||
|
||||
# Clone attributes of already existing version
|
||||
|
||||
t = type_dict[nm]
|
||||
v = selector(value, selector=t.selector,
|
||||
signature=t.signature, isClassMethod=t.isClassMethod)
|
||||
v.isAlloc = t.isAlloc
|
||||
|
||||
type_dict[nm] = v
|
||||
else:
|
||||
type_dict[nm] = value
|
||||
|
||||
if name in CLASS_METHODS:
|
||||
for nm, value in CLASS_METHODS[name]:
|
||||
type_dict[nm] = value
|
||||
|
||||
setClassExtender(add_convenience_methods)
|
||||
|
||||
def __getitem__objectForKey_(self, key):
|
||||
res = self.objectForKey_(container_wrap(key))
|
||||
return container_unwrap(res, KeyError, key)
|
||||
|
||||
def has_key_objectForKey_(self, key):
|
||||
res = self.objectForKey_(container_wrap(key))
|
||||
return res is not None
|
||||
|
||||
def get_objectForKey_(self, key, dflt=None):
|
||||
res = self.objectForKey_(container_wrap(key))
|
||||
if res is None:
|
||||
res = dflt
|
||||
return res
|
||||
|
||||
CONVENIENCE_METHODS['objectForKey:'] = (
|
||||
('__getitem__', __getitem__objectForKey_),
|
||||
('has_key', has_key_objectForKey_),
|
||||
('get', get_objectForKey_),
|
||||
('__contains__', has_key_objectForKey_),
|
||||
)
|
||||
|
||||
def __delitem__removeObjectForKey_(self, key):
|
||||
self.removeObjectForKey_(container_wrap(key))
|
||||
|
||||
CONVENIENCE_METHODS['removeObjectForKey:'] = (
|
||||
('__delitem__', __delitem__removeObjectForKey_),
|
||||
)
|
||||
|
||||
def update_setObject_forKey_(self, other):
|
||||
# XXX - should this be more flexible?
|
||||
for key, value in other.items():
|
||||
self[key] = value
|
||||
|
||||
def setdefault_setObject_forKey_(self, key, dflt=None):
|
||||
try:
|
||||
return self[key]
|
||||
except KeyError:
|
||||
self[key] = dflt
|
||||
return dflt
|
||||
|
||||
def __setitem__setObject_forKey_(self, key, value):
|
||||
self.setObject_forKey_(container_wrap(value), container_wrap(key))
|
||||
|
||||
def pop_setObject_forKey_(self, key, dflt=None):
|
||||
try:
|
||||
res = self[key]
|
||||
except KeyError:
|
||||
res = dflt
|
||||
else:
|
||||
del self[key]
|
||||
return res
|
||||
|
||||
def popitem_setObject_forKey_(self):
|
||||
try:
|
||||
k = self[iter(self).next()]
|
||||
except StopIteration:
|
||||
raise KeyError, "popitem on an empty %s" % (type(self).__name__,)
|
||||
else:
|
||||
return (k, self[k])
|
||||
|
||||
CONVENIENCE_METHODS['setObject:forKey:'] = (
|
||||
('__setitem__', __setitem__setObject_forKey_),
|
||||
('update', update_setObject_forKey_),
|
||||
('setdefault', setdefault_setObject_forKey_),
|
||||
('pop', pop_setObject_forKey_),
|
||||
('popitem', popitem_setObject_forKey_),
|
||||
)
|
||||
|
||||
|
||||
CONVENIENCE_METHODS['count'] = (
|
||||
('__len__', lambda self: self.count()),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['containsObject:'] = (
|
||||
('__contains__', lambda self, elem: bool(self.containsObject_(container_wrap(elem)))),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['hash'] = (
|
||||
('__hash__', lambda self: self.hash()),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['isEqualTo:'] = (
|
||||
('__eq__', lambda self, other: bool(self.isEqualTo_(other))),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['isEqual:'] = (
|
||||
('__eq__', lambda self, other: bool(self.isEqual_(other))),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['isGreaterThan:'] = (
|
||||
('__gt__', lambda self, other: bool(self.isGreaterThan_(other))),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['isGreaterThanOrEqualTo:'] = (
|
||||
('__ge__', lambda self, other: bool(self.isGreaterThanOrEqualTo_(other))),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['isLessThan:'] = (
|
||||
('__lt__', lambda self, other: bool(self.isLessThan_(other))),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['isLessThanOrEqualTo:'] = (
|
||||
('__le__', lambda self, other: bool(self.isLessThanOrEqualTo_(other))),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['isNotEqualTo:'] = (
|
||||
('__ne__', lambda self, other: bool(self.isNotEqualTo_(other))),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['length'] = (
|
||||
('__len__', lambda self: self.length()),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['addObject:'] = (
|
||||
('append', lambda self, item: self.addObject_(container_wrap(item))),
|
||||
)
|
||||
|
||||
def reverse_exchangeObjectAtIndex_withObjectAtIndex_(self):
|
||||
begin = 0
|
||||
end = len(self) - 1
|
||||
while begin < end:
|
||||
self.exchangeObjectAtIndex_withObjectAtIndex_(begin, end)
|
||||
begin += 1
|
||||
end -= 1
|
||||
|
||||
CONVENIENCE_METHODS['exchangeObjectAtIndex:withObjectAtIndex:'] = (
|
||||
('reverse', reverse_exchangeObjectAtIndex_withObjectAtIndex_),
|
||||
)
|
||||
|
||||
def ensureArray(anArray):
|
||||
if not isinstance(anArray, (NSArray, list, tuple)):
|
||||
anArray = list(anArray)
|
||||
return anArray
|
||||
|
||||
|
||||
def extend_addObjectsFromArray_(self, anArray):
|
||||
self.addObjectsFromArray_(ensureArray(anArray))
|
||||
|
||||
CONVENIENCE_METHODS['addObjectsFromArray:'] = (
|
||||
('extend', extend_addObjectsFromArray_),
|
||||
)
|
||||
|
||||
def index_indexOfObject_(self, item):
|
||||
from Foundation import NSNotFound
|
||||
res = self.indexOfObject_(container_wrap(item))
|
||||
if res == NSNotFound:
|
||||
raise ValueError, "%s.index(x): x not in list" % (type(self).__name__,)
|
||||
return res
|
||||
|
||||
CONVENIENCE_METHODS['indexOfObject:'] = (
|
||||
('index', index_indexOfObject_),
|
||||
)
|
||||
|
||||
def insert_insertObject_atIndex_(self, idx, item):
|
||||
idx = slice(idx, None, None).indices(len(self)).start
|
||||
self.insertObject_atIndex_(container_wrap(item), idx)
|
||||
|
||||
CONVENIENCE_METHODS['insertObject:atIndex:'] = (
|
||||
( 'insert', insert_insertObject_atIndex_),
|
||||
)
|
||||
|
||||
def __getitem__objectAtIndex_(self, idx):
|
||||
length = len(self)
|
||||
if isinstance(idx, slice):
|
||||
start, stop, step = idx.indices(length)
|
||||
#if step == 1:
|
||||
# m = getattr(self, 'subarrayWithRange_', None)
|
||||
# if m is not None:
|
||||
# return m((start, stop - start))
|
||||
return [self[i] for i in xrange(start, stop, step)]
|
||||
if idx < 0:
|
||||
idx += length
|
||||
if idx < 0:
|
||||
raise IndexError, "index out of range"
|
||||
elif idx >= length:
|
||||
raise IndexError, "index out of range"
|
||||
return container_unwrap(self.objectAtIndex_(idx), RuntimeError)
|
||||
|
||||
CONVENIENCE_METHODS['objectAtIndex:'] = (
|
||||
('__getitem__', __getitem__objectAtIndex_),
|
||||
)
|
||||
|
||||
def __delitem__removeObjectAtIndex_(self, idx):
|
||||
length = len(self)
|
||||
if isinstance(idx, slice):
|
||||
start, stop, step = idx.indices(length)
|
||||
if step == 1:
|
||||
if start > stop:
|
||||
start, stop = stop, start
|
||||
m = getattr(self, 'removeObjectsInRange_', None)
|
||||
if m is not None:
|
||||
m((start, stop - start))
|
||||
return
|
||||
r = range(start, stop, step)
|
||||
r.sort()
|
||||
r.reverse()
|
||||
for i in r:
|
||||
self.removeObjectAtIndex_(i)
|
||||
return
|
||||
if idx < 0:
|
||||
idx += length
|
||||
if idx < 0:
|
||||
raise IndexError, "index out of range"
|
||||
elif idx >= length:
|
||||
raise IndexError, "index out of range"
|
||||
self.removeObjectAtIndex_(idx)
|
||||
|
||||
def pop_removeObjectAtIndex_(self, idx=-1):
|
||||
length = len(self)
|
||||
if length <= 0:
|
||||
raise IndexError("pop from empty list")
|
||||
elif idx >= length or (idx + length) < 0:
|
||||
raise IndexError("pop index out of range")
|
||||
elif idx < 0:
|
||||
idx += length
|
||||
rval = self[idx]
|
||||
self.removeObjectAtIndex_(idx)
|
||||
return rval
|
||||
|
||||
def remove_removeObjectAtIndex_(self, obj):
|
||||
idx = self.index(obj)
|
||||
self.removeObjectAtIndex_(idx)
|
||||
|
||||
CONVENIENCE_METHODS['removeObjectAtIndex:'] = (
|
||||
('remove', remove_removeObjectAtIndex_),
|
||||
('pop', pop_removeObjectAtIndex_),
|
||||
('__delitem__', __delitem__removeObjectAtIndex_),
|
||||
)
|
||||
|
||||
def __setitem__replaceObjectAtIndex_withObject_(self, idx, anObject):
|
||||
length = len(self)
|
||||
if isinstance(idx, slice):
|
||||
start, stop, step = idx.indices(length)
|
||||
if step == 1:
|
||||
m = getattr(self, 'replaceObjectsInRange_withObjectsFromArray_', None)
|
||||
if m is not None:
|
||||
m((start, stop - start), ensureArray(anObject))
|
||||
return
|
||||
# XXX - implement this..
|
||||
raise NotImplementedError
|
||||
if idx < 0:
|
||||
idx += length
|
||||
if idx < 0:
|
||||
raise IndexError, "index out of range"
|
||||
elif idx >= length:
|
||||
raise IndexError, "index out of range"
|
||||
self.replaceObjectAtIndex_withObject_(idx, anObject)
|
||||
|
||||
CONVENIENCE_METHODS['replaceObjectAtIndex:withObject:'] = (
|
||||
('__setitem__', __setitem__replaceObjectAtIndex_withObject_),
|
||||
)
|
||||
|
||||
def enumeratorGenerator(anEnumerator):
|
||||
while True:
|
||||
yield container_unwrap(anEnumerator.nextObject(), StopIteration)
|
||||
|
||||
def dictItems(aDict):
|
||||
"""
|
||||
NSDictionary.items()
|
||||
"""
|
||||
keys = aDict.allKeys()
|
||||
return zip(keys, imap(aDict.__getitem__, keys))
|
||||
|
||||
CONVENIENCE_METHODS['allKeys'] = (
|
||||
('keys', lambda self: self.allKeys()),
|
||||
('items', lambda self: dictItems(self)),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['allValues'] = (
|
||||
('values', lambda self: self.allValues()),
|
||||
)
|
||||
|
||||
def itemsGenerator(aDict):
|
||||
for key in aDict:
|
||||
yield (key, aDict[key])
|
||||
|
||||
def __iter__objectEnumerator_keyEnumerator(self):
|
||||
meth = getattr(self, 'keyEnumerator', None)
|
||||
if meth is None:
|
||||
meth = self.objectEnumerator
|
||||
return iter(meth())
|
||||
|
||||
CONVENIENCE_METHODS['keyEnumerator'] = (
|
||||
('__iter__', __iter__objectEnumerator_keyEnumerator),
|
||||
('iterkeys', lambda self: iter(self.keyEnumerator())),
|
||||
('iteritems', lambda self: itemsGenerator(self)),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['objectEnumerator'] = (
|
||||
('__iter__', __iter__objectEnumerator_keyEnumerator),
|
||||
('itervalues', lambda self: iter(self.objectEnumerator())),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['reverseObjectEnumerator'] = (
|
||||
('__reversed__', lambda self: iter(self.reverseObjectEnumerator())),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['removeAllObjects'] = (
|
||||
('clear', lambda self: self.removeAllObjects()),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['dictionaryWithDictionary:'] = (
|
||||
('copy', lambda self: type(self).dictionaryWithDictionary_(self)),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['nextObject'] = (
|
||||
('__iter__', enumeratorGenerator),
|
||||
)
|
||||
|
||||
#
|
||||
# NSNumber seems to be and abstract base-class that is implemented using
|
||||
# NSCFNumber, a CoreFoundation 'proxy'.
|
||||
#
|
||||
NSNull = lookUpClass('NSNull')
|
||||
NSArray = lookUpClass('NSArray')
|
||||
null = NSNull.null()
|
||||
|
||||
number_wrap = repythonify
|
||||
|
||||
def container_wrap(v):
|
||||
if v is None:
|
||||
return null
|
||||
return v
|
||||
|
||||
def container_unwrap(v, exc_type, *exc_args):
|
||||
if v is None:
|
||||
raise exc_type(*exc_args)
|
||||
elif v is null:
|
||||
return None
|
||||
return v
|
||||
|
||||
#
|
||||
# Special wrappers for a number of varargs functions (constructors)
|
||||
#
|
||||
|
||||
def initWithObjects_(self, *args):
|
||||
if args[-1] is not None:
|
||||
raise ValueError, "Need None as the last argument"
|
||||
return self.initWithArray_(args[:-1])
|
||||
|
||||
CONVENIENCE_METHODS['initWithObjects:'] = (
|
||||
('initWithObjects_', initWithObjects_),
|
||||
)
|
||||
|
||||
def arrayWithObjects_(self, *args):
|
||||
if args[-1] is not None:
|
||||
raise ValueError, "Need None as the last argument"
|
||||
return self.arrayWithArray_(args[:-1])
|
||||
|
||||
CONVENIENCE_METHODS['arrayWithObjects:'] = (
|
||||
('arrayWithObjects_', selector(arrayWithObjects_, signature='@@:@', isClassMethod=1)),
|
||||
)
|
||||
|
||||
|
||||
def setWithObjects_(self, *args):
|
||||
if args[-1] is not None:
|
||||
raise ValueError, "Need None as the last argument"
|
||||
return self.setWithArray_(args[:-1])
|
||||
|
||||
CONVENIENCE_METHODS['setWithObjects:'] = (
|
||||
('setWithObjects_', selector(setWithObjects_, signature='@@:@', isClassMethod=1)),
|
||||
)
|
||||
|
||||
def setWithObjects_count_(self, args, count):
|
||||
return self.setWithArray_(args[:count])
|
||||
|
||||
CONVENIENCE_METHODS['setWithObjects:count:'] = (
|
||||
('setWithObjects_count_', selector(setWithObjects_count_, signature='@@:^@i', isClassMethod=1)),
|
||||
)
|
||||
|
||||
def splitObjectsAndKeys(values):
|
||||
if values[-1] is not None:
|
||||
raise ValueError, "Need None as the last argument"
|
||||
if len(values) % 2 != 1:
|
||||
raise ValueError, "Odd number of arguments"
|
||||
|
||||
objects = []
|
||||
keys = []
|
||||
for i in range(0, len(values)-1, 2):
|
||||
objects.append(container_wrap(values[i]))
|
||||
keys.append(container_wrap(values[i+1]))
|
||||
return objects, keys
|
||||
|
||||
def dictionaryWithObjectsAndKeys_(self, *values):
|
||||
objects, keys = splitObjectsAndKeys(values)
|
||||
return self.dictionaryWithObjects_forKeys_(objects, keys)
|
||||
|
||||
CONVENIENCE_METHODS['dictionaryWithObjectsAndKeys:'] = (
|
||||
('dictionaryWithObjectsAndKeys_',
|
||||
selector(dictionaryWithObjectsAndKeys_, signature='@@:@',isClassMethod=1)),
|
||||
)
|
||||
|
||||
def fromkeys_dictionaryWithObjects_forKeys_(cls, keys, values=None):
|
||||
if not isinstance(keys, (list, tuple)):
|
||||
keys = list(keys)
|
||||
if values is None:
|
||||
values = (None,) * len(keys)
|
||||
elif not isinstance(values, (list, tuple)):
|
||||
values = list(values)
|
||||
return cls.dictionaryWithObjects_forKeys_(values, keys)
|
||||
|
||||
CONVENIENCE_METHODS['dictionaryWithObjects:forKeys:'] = (
|
||||
('fromkeys',
|
||||
classmethod(fromkeys_dictionaryWithObjects_forKeys_)),
|
||||
)
|
||||
|
||||
def initWithObjectsAndKeys_(self, *values):
|
||||
objects, keys = splitObjectsAndKeys(values)
|
||||
return self.initWithObjects_forKeys_(objects, keys)
|
||||
|
||||
CONVENIENCE_METHODS['initWithObjectsAndKeys:'] = (
|
||||
( 'initWithObjectsAndKeys_', initWithObjectsAndKeys_ ),
|
||||
)
|
||||
|
||||
def sort(self, cmpfunc=cmp):
|
||||
def doCmp(a, b, cmpfunc):
|
||||
return cmpfunc(a, b)
|
||||
|
||||
self.sortUsingFunction_context_(doCmp, cmpfunc)
|
||||
|
||||
CONVENIENCE_METHODS['sortUsingFunction:context:'] = (
|
||||
('sort', sort),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['hasPrefix:'] = (
|
||||
('startswith', lambda self, pfx: self.hasPrefix_(pfx)),
|
||||
)
|
||||
|
||||
CONVENIENCE_METHODS['hasSuffix:'] = (
|
||||
('endswith', lambda self, pfx: self.hasSuffix_(pfx)),
|
||||
)
|
||||
|
||||
CLASS_METHODS['NSNull'] = (
|
||||
('__nonzero__', lambda self: False ),
|
||||
)
|
||||
|
||||
NSDecimalNumber = lookUpClass('NSDecimalNumber')
|
||||
def _makeD(v):
|
||||
if isinstance(v, NSDecimalNumber):
|
||||
return v
|
||||
return NSDecimalNumber.decimalNumberWithDecimal_(v)
|
||||
|
||||
CLASS_METHODS['NSDecimalNumber'] = (
|
||||
('__add__', lambda self, other: _makeD(self.decimalValue() + other)),
|
||||
('__radd__', lambda self, other: _makeD(other + self.decimalValue())),
|
||||
('__sub__', lambda self, other: _makeD(self.decimalValue() - other)),
|
||||
('__rsub__', lambda self, other: _makeD(other - self.decimalValue())),
|
||||
('__mul__', lambda self, other: _makeD(self.decimalValue() * other)),
|
||||
('__rmul__', lambda self, other: _makeD(other * self.decimalValue())),
|
||||
('__div__', lambda self, other: _makeD(self.decimalValue() / other)),
|
||||
('__rdiv__', lambda self, other: _makeD(other / self.decimalValue())),
|
||||
('__mod__', lambda self, other: _makeD(self.decimalValue() % other)),
|
||||
('__rmod__', lambda self, other: _makeD(other % self.decimalValue())),
|
||||
('__neg__', lambda self: _makeD(-(self.decimalValue()))),
|
||||
('__pos__', lambda self: _makeD(+(self.decimalValue()))),
|
||||
('__abs__', lambda self: _makeD(abs(self.decimalValue()))),
|
||||
)
|
||||
|
||||
def NSData__getslice__(self, i, j):
|
||||
return self.bytes()[i:j]
|
||||
|
||||
def NSData__getitem__(self, item):
|
||||
buff = self.bytes()
|
||||
try:
|
||||
return buff[item]
|
||||
except TypeError:
|
||||
return buff[:][item]
|
||||
|
||||
CLASS_METHODS['NSData'] = (
|
||||
('__str__', lambda self: self.bytes()[:]),
|
||||
('__getitem__', NSData__getitem__),
|
||||
('__getslice__', NSData__getslice__),
|
||||
)
|
||||
|
||||
def NSMutableData__setslice__(self, i, j, sequence):
|
||||
# XXX - could use replaceBytes:inRange:, etc.
|
||||
self.mutableBytes()[i:j] = sequence
|
||||
|
||||
def NSMutableData__setitem__(self, item, value):
|
||||
self.mutableBytes()[item] = value
|
||||
|
||||
CLASS_METHODS['NSMutableData'] = (
|
||||
('__setslice__', NSMutableData__setslice__),
|
||||
('__setitem__', NSMutableData__setitem__),
|
||||
)
|
||||
98
objc/_descriptors.py
Executable file
98
objc/_descriptors.py
Executable file
@@ -0,0 +1,98 @@
|
||||
"""
|
||||
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)
|
||||
129
objc/_dyld.py
Executable file
129
objc/_dyld.py
Executable file
@@ -0,0 +1,129 @@
|
||||
"""
|
||||
dyld emulation
|
||||
"""
|
||||
|
||||
__all__ = [
|
||||
'dyld_framework', 'dyld_library', 'dyld_find', 'pathForFramework',
|
||||
'infoForFramework',
|
||||
]
|
||||
|
||||
import os
|
||||
from _framework import infoForFramework
|
||||
|
||||
# These are the defaults as per man dyld(1)
|
||||
#
|
||||
DEFAULT_FRAMEWORK_FALLBACK = u':'.join([
|
||||
os.path.expanduser(u"~/Library/Frameworks"),
|
||||
u"/Library/Frameworks",
|
||||
u"/Network/Library/Frameworks",
|
||||
u"/System/Library/Frameworks",
|
||||
])
|
||||
|
||||
DEFAULT_LIBRARY_FALLBACK = u':'.join([
|
||||
os.path.expanduser(u"~/lib"),
|
||||
u"/usr/local/lib",
|
||||
u"/lib",
|
||||
u"/usr/lib",
|
||||
])
|
||||
|
||||
def ensure_unicode(s):
|
||||
"""Not all of PyObjC understands unicode paths very well yet"""
|
||||
if isinstance(s, str):
|
||||
return unicode(s, 'utf8')
|
||||
return s
|
||||
|
||||
def injectSuffixes(iterator):
|
||||
suffix = ensure_unicode(os.environ.get('DYLD_IMAGE_SUFFIX', None))
|
||||
if suffix is None:
|
||||
return iterator
|
||||
def _inject(iterator=iterator,suffix=suffix):
|
||||
for path in iterator:
|
||||
if path.endswith(u'.dylib'):
|
||||
yield path[:-6] + suffix + u'.dylib'
|
||||
else:
|
||||
yield path + suffix
|
||||
yield path
|
||||
return _inject()
|
||||
|
||||
def dyld_framework(filename, framework_name, version=None):
|
||||
"""Find a framework using dyld semantics"""
|
||||
filename = ensure_unicode(filename)
|
||||
framework_name = ensure_unicode(framework_name)
|
||||
version = ensure_unicode(version)
|
||||
|
||||
def _search():
|
||||
spath = ensure_unicode(os.environ.get('DYLD_FRAMEWORK_PATH', None))
|
||||
if spath is not None:
|
||||
for path in spath.split(u':'):
|
||||
if version:
|
||||
yield os.path.join(
|
||||
path, framework_name + u'.framework',
|
||||
u'Versions', version, framework_name
|
||||
)
|
||||
else:
|
||||
yield os.path.join(
|
||||
path, framework_name + u'.framework', framework_name
|
||||
)
|
||||
yield filename
|
||||
spath = ensure_unicode(os.environ.get(
|
||||
'DYLD_FALLBACK_FRAMEWORK_PATH', DEFAULT_FRAMEWORK_FALLBACK
|
||||
))
|
||||
for path in spath.split(u':'):
|
||||
if version:
|
||||
yield os.path.join(
|
||||
path, framework_name + u'.framework', u'Versions',
|
||||
version, framework_name
|
||||
)
|
||||
else:
|
||||
yield os.path.join(
|
||||
path, framework_name + u'.framework', framework_name
|
||||
)
|
||||
|
||||
|
||||
for f in injectSuffixes(_search()):
|
||||
if os.path.exists(f):
|
||||
return f
|
||||
# raise ..
|
||||
raise ValueError, "Framework %s could not be found" % (framework_name,)
|
||||
|
||||
def dyld_library(filename, libname):
|
||||
"""Find a dylib using dyld semantics"""
|
||||
filename = ensure_unicode(filename)
|
||||
libname = ensure_unicode(libname)
|
||||
def _search():
|
||||
spath = ensure_unicode(os.environ.get('DYLD_LIBRARY_PATH', None))
|
||||
if spath is not None:
|
||||
for path in spath.split(u':'):
|
||||
yield os.path.join(path, libname)
|
||||
yield filename
|
||||
spath = ensure_unicode(os.environ.get(
|
||||
'DYLD_FALLBACK_LIBRARY_PATH', DEFAULT_LIBRARY_FALLBACK
|
||||
))
|
||||
for path in spath.split(u':'):
|
||||
yield os.path.join(path, libname)
|
||||
for f in injectSuffixes(_search()):
|
||||
if os.path.exists(f):
|
||||
return f
|
||||
raise ValueError, "dylib %s could not be found" % (filename,)
|
||||
|
||||
def dyld_find(filename):
|
||||
"""Generic way to locate a dyld framework or dyld"""
|
||||
# if they passed in a framework directory, not a mach-o file
|
||||
# then go ahead and look where one would expect to find the mach-o
|
||||
filename = ensure_unicode(filename)
|
||||
if os.path.isdir(filename):
|
||||
filename = os.path.join(
|
||||
filename,
|
||||
os.path.basename(filename)[:-len(os.path.splitext(filename)[-1])]
|
||||
)
|
||||
filename = os.path.realpath(filename)
|
||||
res = infoForFramework(filename)
|
||||
if res:
|
||||
framework_loc, framework_name, version = res
|
||||
return dyld_framework(filename, framework_name, version)
|
||||
else:
|
||||
return dyld_library(filename, os.path.basename(filename))
|
||||
|
||||
def pathForFramework(path):
|
||||
fpath, name, version = infoForFramework(dyld_find(path))
|
||||
return os.path.join(fpath, name + u'.framework')
|
||||
24
objc/_framework.py
Executable file
24
objc/_framework.py
Executable file
@@ -0,0 +1,24 @@
|
||||
"""
|
||||
Generic framework path manipulation
|
||||
"""
|
||||
|
||||
__all__ = ['infoForFramework']
|
||||
|
||||
# This regexp should find:
|
||||
# \1 - framework location
|
||||
# \2 - framework name
|
||||
# \3 - framework version (optional)
|
||||
#
|
||||
FRAMEWORK_RE_STR = ur"""(^.*)(?:^|/)(\w+).framework(?:/(?:Versions/([^/]+)/)?\2)?$"""
|
||||
FRAMEWORK_RE = None
|
||||
|
||||
def infoForFramework(filename):
|
||||
"""returns (location, name, version) or None"""
|
||||
global FRAMEWORK_RE
|
||||
if FRAMEWORK_RE is None:
|
||||
import re
|
||||
FRAMEWORK_RE = re.compile(FRAMEWORK_RE_STR)
|
||||
is_framework = FRAMEWORK_RE.findall(filename)
|
||||
if not is_framework:
|
||||
return None
|
||||
return is_framework[-1]
|
||||
44
objc/_functions.py
Executable file
44
objc/_functions.py
Executable file
@@ -0,0 +1,44 @@
|
||||
__all__ = ['inject', 'signature']
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
def _ensure_path(p):
|
||||
p = os.path.realpath(p)
|
||||
if isinstance(p, unicode):
|
||||
p = p.encode(sys.getfilesystemencoding())
|
||||
return p
|
||||
|
||||
def inject(pid, bundle, useMainThread=True):
|
||||
"""Loads the given MH_BUNDLE in the target process identified by pid"""
|
||||
try:
|
||||
from _objc import _inject
|
||||
from _dyld import dyld_find
|
||||
except ImportError:
|
||||
raise NotImplementedError("objc.inject is only supported on Mac OS X 10.3 and later")
|
||||
bundlePath = bundle
|
||||
systemPath = dyld_find('/usr/lib/libSystem.dylib')
|
||||
carbonPath = dyld_find('/System/Library/Frameworks/Carbon.framework/Carbon')
|
||||
paths = map(_ensure_path, (bundlePath, systemPath, carbonPath))
|
||||
return _inject(
|
||||
pid,
|
||||
useMainThread,
|
||||
*paths
|
||||
)
|
||||
|
||||
def signature(signature, **kw):
|
||||
"""
|
||||
A Python method decorator that allows easy specification
|
||||
of Objective-C selectors.
|
||||
|
||||
Usage::
|
||||
|
||||
@objc.signature('i@:if')
|
||||
def methodWithX_andY_(self, x, y):
|
||||
return 0
|
||||
"""
|
||||
from _objc import selector
|
||||
kw['signature'] = signature
|
||||
def makeSignature(func):
|
||||
return selector(func, **kw)
|
||||
return makeSignature
|
||||
13
objc/_gnustep.py
Executable file
13
objc/_gnustep.py
Executable file
@@ -0,0 +1,13 @@
|
||||
__all__ = ['pathForFramework', 'infoForFramework']
|
||||
#
|
||||
# TODO - I have no idea what the semantics are for GNUStep ..
|
||||
#
|
||||
from _framework import infoForFramework
|
||||
|
||||
def ensure_unicode(s):
|
||||
if isinstance(s, str):
|
||||
return unicode(s)
|
||||
return s
|
||||
|
||||
def pathForFramework(path):
|
||||
return ensure_unicode(path)
|
||||
BIN
objc/_objc.so
Executable file
BIN
objc/_objc.so
Executable file
Binary file not shown.
31
objc/_protocols.py
Executable file
31
objc/_protocols.py
Executable file
@@ -0,0 +1,31 @@
|
||||
import _objc
|
||||
|
||||
__all__ = ['protocolNamed', 'ProtocolError']
|
||||
|
||||
class ProtocolError(_objc.error):
|
||||
__module__ = 'objc'
|
||||
|
||||
PROTOCOL_CACHE = {}
|
||||
def protocolNamed(name):
|
||||
"""
|
||||
Returns a Protocol object for the named protocol. This is the
|
||||
equivalent of @protocol(name) in Objective-C.
|
||||
Raises objc.ProtocolError when the protocol does not exist.
|
||||
"""
|
||||
name = unicode(name)
|
||||
try:
|
||||
return PROTOCOL_CACHE[name]
|
||||
except KeyError:
|
||||
pass
|
||||
for p in _objc.protocolsForProcess():
|
||||
pname = p.__name__
|
||||
PROTOCOL_CACHE.setdefault(pname, p)
|
||||
if pname == name:
|
||||
return p
|
||||
for cls in _objc.getClassList():
|
||||
for p in _objc.protocolsForClass(cls):
|
||||
pname = p.__name__
|
||||
PROTOCOL_CACHE.setdefault(pname, p)
|
||||
if pname == name:
|
||||
return p
|
||||
raise ProtocolError("protocol %r does not exist" % (name,), name)
|
||||
81
objc/_pythonify.py
Executable file
81
objc/_pythonify.py
Executable file
@@ -0,0 +1,81 @@
|
||||
import _objc
|
||||
|
||||
__all__ = []
|
||||
|
||||
|
||||
class OC_PythonFloat(float):
|
||||
__slots__=('__pyobjc_object__',)
|
||||
|
||||
|
||||
def __new__(cls, obj, value):
|
||||
self = float.__new__(cls, value)
|
||||
self.__pyobjc_object__ = obj
|
||||
return self
|
||||
|
||||
__class__ = property(lambda self: self.__pyobjc_object__.__class__)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.__pyobjc_object__, attr)
|
||||
|
||||
class OC_PythonLong(long):
|
||||
|
||||
def __new__(cls, obj, value):
|
||||
self = long.__new__(cls, value)
|
||||
self.__pyobjc_object__ = obj
|
||||
return self
|
||||
|
||||
__class__ = property(lambda self: self.__pyobjc_object__.__class__)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.__pyobjc_object__, attr)
|
||||
|
||||
# The long type doesn't support __slots__ on subclasses, fake
|
||||
# one part of the effect of __slots__: don't allow setting of attributes.
|
||||
def __setattr__(self, attr, value):
|
||||
if attr != '__pyobjc_object__':
|
||||
raise AttributeError, "'%s' object has no attribute '%s')"%(self.__class__.__name__, attr)
|
||||
self.__dict__['__pyobjc_object__'] = value
|
||||
|
||||
class OC_PythonInt(int):
|
||||
__slots__=('__pyobjc_object__',)
|
||||
|
||||
def __new__(cls, obj, value):
|
||||
self = int.__new__(cls, value)
|
||||
self.__pyobjc_object__ = obj
|
||||
return self
|
||||
|
||||
__class__ = property(lambda self: self.__pyobjc_object__.__class__)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.__pyobjc_object__, attr)
|
||||
|
||||
NSNumber = _objc.lookUpClass('NSNumber')
|
||||
NSDecimalNumber = _objc.lookUpClass('NSDecimalNumber')
|
||||
Foundation = None
|
||||
|
||||
def numberWrapper(obj):
|
||||
if isinstance(obj, NSDecimalNumber):
|
||||
return obj
|
||||
# ensure that NSDecimal is around
|
||||
global Foundation
|
||||
if Foundation is None:
|
||||
import Foundation
|
||||
# return NSDecimal
|
||||
return Foundation.NSDecimal(obj)
|
||||
try:
|
||||
tp = obj.objCType()
|
||||
except AttributeError:
|
||||
import warnings
|
||||
warnings.warn(RuntimeWarning, "NSNumber instance doesn't implement objCType? %r" % (obj,))
|
||||
return obj
|
||||
if tp in 'qQLfd':
|
||||
if tp == 'q':
|
||||
return OC_PythonLong(obj, obj.longLongValue())
|
||||
elif tp in 'QL':
|
||||
return OC_PythonLong(obj, obj.unsignedLongLongValue())
|
||||
else:
|
||||
return OC_PythonFloat(obj, obj.doubleValue())
|
||||
else:
|
||||
return OC_PythonInt(obj, obj.longValue())
|
||||
|
||||
_objc.setNSNumberWrapper(numberWrapper)
|
||||
Reference in New Issue
Block a user