Commits

Phillip Nguyen  committed 5322c19

Updated cocoa backend to be compatible with Python 3.2+ (still must be converted with 2to3)

  • Participants
  • Parent commits e4c909e

Comments (0)

Files changed (8)

File pyglet/libs/darwin/cocoapy/__init__.py

 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 # POSSIBILITY OF SUCH DAMAGE.
 
-from runtime import objc, send_message, send_super
-from runtime import get_selector
-from runtime import ObjCClass, ObjCInstance, ObjCSubclass
+from .runtime import objc, send_message, send_super
+from .runtime import get_selector
+from .runtime import ObjCClass, ObjCInstance, ObjCSubclass
 
-from cocoatypes import *
-from cocoalibs import *
+from .cocoatypes import *
+from .cocoalibs import *

File pyglet/libs/darwin/cocoapy/cocoalibs.py

 from ctypes import *
 from ctypes import util
 
-from runtime import send_message, ObjCInstance
-from cocoatypes import *
+from .runtime import send_message, ObjCInstance
+from .cocoatypes import *
 
 ######################################################################
 

File pyglet/libs/darwin/cocoapy/cocoatypes.py

 from ctypes import *
 
-import sys, platform
-__LP64__ = (sys.maxint > 2**32)
+import sys, platform, struct
+
+__LP64__ = (8*struct.calcsize("P") == 64)
 __i386__ = (platform.machine() == 'i386')
 
-PyObjectEncoding = '{PyObject=@}'
+PyObjectEncoding = b'{PyObject=@}'
 
 def encoding_for_ctype(vartype):
-    typecodes = {c_char:'c', c_int:'i', c_short:'s', c_long:'l', c_longlong:'q',
-                 c_ubyte:'C', c_uint:'I', c_ushort:'S', c_ulong:'L', c_ulonglong:'Q',
-                 c_float:'f', c_double:'d', c_bool:'B', c_char_p:'*', c_void_p:'@',
+    typecodes = {c_char:b'c', c_int:b'i', c_short:b's', c_long:b'l', c_longlong:b'q',
+                 c_ubyte:b'C', c_uint:b'I', c_ushort:b'S', c_ulong:b'L', c_ulonglong:b'Q',
+                 c_float:b'f', c_double:b'd', c_bool:b'B', c_char_p:b'*', c_void_p:b'@',
                  py_object:PyObjectEncoding}
-    return typecodes.get(vartype, '?')
+    return typecodes.get(vartype, b'?')
 
 # Note CGBase.h located at
 # /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Headers/CGBase.h
     NSInteger = c_long
     NSUInteger = c_ulong
     CGFloat = c_double
-    NSPointEncoding = '{CGPoint=dd}'
-    NSSizeEncoding = '{CGSize=dd}'
-    NSRectEncoding = '{CGRect={CGPoint=dd}{CGSize=dd}}'
-    NSRangeEncoding = '{_NSRange=QQ}'
+    NSPointEncoding = b'{CGPoint=dd}'
+    NSSizeEncoding = b'{CGSize=dd}'
+    NSRectEncoding = b'{CGRect={CGPoint=dd}{CGSize=dd}}'
+    NSRangeEncoding = b'{_NSRange=QQ}'
 else:
     NSInteger = c_int
     NSUInteger = c_uint
     CGFloat = c_float
-    NSPointEncoding = '{_NSPoint=ff}'
-    NSSizeEncoding = '{_NSSize=ff}'
-    NSRectEncoding = '{_NSRect={_NSPoint=ff}{_NSSize=ff}}'
-    NSRangeEncoding = '{_NSRange=II}'
+    NSPointEncoding = b'{_NSPoint=ff}'
+    NSSizeEncoding = b'{_NSSize=ff}'
+    NSRectEncoding = b'{_NSRect={_NSPoint=ff}{_NSSize=ff}}'
+    NSRangeEncoding = b'{_NSRange=II}'
 
 NSIntegerEncoding = encoding_for_ctype(NSInteger)
 NSUIntegerEncoding = encoding_for_ctype(NSUInteger)
 CGFloatEncoding = encoding_for_ctype(CGFloat)    
 
 # Special case so that NSImage.initWithCGImage_size_() will work.
-CGImageEncoding = '{CGImage=}'
+CGImageEncoding = b'{CGImage=}'
 
-NSZoneEncoding = '{_NSZone=}'
+NSZoneEncoding = b'{_NSZone=}'
 
 # from /System/Library/Frameworks/Foundation.framework/Headers/NSGeometry.h
 class NSPoint(Structure):

File pyglet/libs/darwin/cocoapy/runtime.py

 
 import sys
 import platform
+import struct
 
 from ctypes import *
 from ctypes import util
 
-from cocoatypes import *
+from .cocoatypes import *
 
-__LP64__ = (sys.maxint > 2**32)
+__LP64__ = (8*struct.calcsize("P") == 64)
 __i386__ = (platform.machine() == 'i386')
 
 if sizeof(c_void_p) == 4:
 
 ######################################################################
 
+def ensure_bytes(x):
+    if isinstance(x, bytes):
+        return x
+    return x.encode('ascii')
+
+######################################################################
+
 def get_selector(name):
-    return c_void_p(objc.sel_registerName(name))
+    return c_void_p(objc.sel_registerName(ensure_bytes(name)))
 
 def get_class(name):
-    return c_void_p(objc.objc_getClass(name))
+    return c_void_p(objc.objc_getClass(ensure_bytes(name)))
 
 def get_object_class(obj):
     return c_void_p(objc.object_getClass(obj))
 
 def get_metaclass(name):
-    return c_void_p(objc.objc_getMetaClass(name))
+    return c_void_p(objc.objc_getMetaClass(ensure_bytes(name)))
 
 def get_superclass_of_object(obj):
     cls = c_void_p(objc.object_getClass(obj))
 # and argtypes should be a list of ctypes types for
 # the arguments of the message only.
 def send_message(receiver, selName, *args, **kwargs):
-    if isinstance(receiver, basestring):
+    if isinstance(receiver, str):
         receiver = get_class(receiver)
     selector = get_selector(selName)
     restype = kwargs.get('restype', c_void_p)
 def parse_type_encoding(encoding):
     """Takes a type encoding string and outputs a list of the separated type codes.
     Currently does not handle unions or bitfields and strips out any field width
-    specifiers or type specifiers from the encoding.
+    specifiers or type specifiers from the encoding.  For Python 3.2+, encoding is
+    assumed to be a bytes object and not unicode.
 
     Examples:
     parse_type_encoding('^v16@0:8') --> ['^v', '@', ':']
     type_encodings = []
     brace_count = 0    # number of unclosed curly braces
     bracket_count = 0  # number of unclosed square brackets
-    typecode = ''
+    typecode = b''
     for c in encoding:
-        if c == '{':
+        # In Python 3, c comes out as an integer in the range 0-255.  In Python 2, c is a single character string.
+        # To fix the disparity, we convert c to a bytes object if necessary.
+        if isinstance(c, int):
+            c = bytes([c])
+            
+        if c == b'{':
             # Check if this marked the end of previous type code.
-            if typecode and typecode[-1] != '^' and brace_count == 0 and bracket_count == 0:
+            if typecode and typecode[-1:] != b'^' and brace_count == 0 and bracket_count == 0:
                 type_encodings.append(typecode)
-                typecode = ''
+                typecode = b''
             typecode += c
             brace_count += 1
-        elif c == '}':
+        elif c == b'}':
             typecode += c
             brace_count -= 1
             assert(brace_count >= 0)
-        elif c == '[':
+        elif c == b'[':
             # Check if this marked the end of previous type code.
-            if typecode and typecode[-1] != '^' and brace_count == 0 and bracket_count == 0:
+            if typecode and typecode[-1:] != b'^' and brace_count == 0 and bracket_count == 0:
                 type_encodings.append(typecode)
-                typecode = ''
+                typecode = b''
             typecode += c
             bracket_count += 1
-        elif c == ']':
+        elif c == b']':
             typecode += c
             bracket_count -= 1
             assert(bracket_count >= 0)
         elif brace_count or bracket_count:
             # Anything encountered while inside braces or brackets gets stuck on.
             typecode += c
-        elif c in '0123456789':
+        elif c in b'0123456789':
             # Ignore field width specifiers for now.
             pass
-        elif c in 'rnNoORV':
+        elif c in b'rnNoORV':
             # Also ignore type specifiers.
             pass
-        elif c in '^cislqCISLQfdBv*@#:b?':
-            if typecode and typecode[-1] == '^':
+        elif c in b'^cislqCISLQfdBv*@#:b?':
+            if typecode and typecode[-1:] == b'^':
                 # Previous char was pointer specifier, so keep going.
                 typecode += c
             else:
 
 # Limited to basic types and pointers to basic types.
 # Does not try to handle arrays, arbitrary structs, unions, or bitfields.
+# Assume that encoding is a bytes object and not unicode.
 def cfunctype_for_encoding(encoding):
     # Check if we've already created a CFUNCTYPE for this encoding.
     # If so, then return the cached CFUNCTYPE.
         return cfunctype_table[encoding]
 
     # Otherwise, create a new CFUNCTYPE for the encoding.
-    typecodes = {'c':c_char, 'i':c_int, 's':c_short, 'l':c_long, 'q':c_longlong, 
-                 'C':c_ubyte, 'I':c_uint, 'S':c_ushort, 'L':c_ulong, 'Q':c_ulonglong, 
-                 'f':c_float, 'd':c_double, 'B':c_bool, 'v':None, '*':c_char_p,
-                 '@':c_void_p, '#':c_void_p, ':':c_void_p, NSPointEncoding:NSPoint,
+    typecodes = {b'c':c_char, b'i':c_int, b's':c_short, b'l':c_long, b'q':c_longlong, 
+                 b'C':c_ubyte, b'I':c_uint, b'S':c_ushort, b'L':c_ulong, b'Q':c_ulonglong, 
+                 b'f':c_float, b'd':c_double, b'B':c_bool, b'v':None, b'*':c_char_p,
+                 b'@':c_void_p, b'#':c_void_p, b':':c_void_p, NSPointEncoding:NSPoint,
                  NSSizeEncoding:NSSize, NSRectEncoding:NSRect, NSRangeEncoding:NSRange,
                  PyObjectEncoding:py_object}
     argtypes = []
     for code in parse_type_encoding(encoding):
         if code in typecodes:
             argtypes.append(typecodes[code])
-        elif code[0] == '^' and code[1:] in typecodes:
+        elif code[0:1] == b'^' and code[1:] in typecodes:
             argtypes.append(POINTER(typecodes[code[1:]]))
         else:
             raise Exception('unknown type encoding: ' + code)
 # You can add new methods after the class is registered,
 # but you cannot add any new ivars.
 def create_subclass(superclass, name):
-    if isinstance(superclass, basestring):
+    if isinstance(superclass, str):
         superclass = get_class(superclass)
-    return c_void_p(objc.objc_allocateClassPair(superclass, name, 0))
+    return c_void_p(objc.objc_allocateClassPair(superclass, ensure_bytes(name), 0))
 
 def register_subclass(subclass):
     objc.objc_registerClassPair(subclass)
 # Additional type codes are for types of other arguments if any.
 def add_method(cls, selName, method, types):
     type_encodings = parse_type_encoding(types)
-    assert(type_encodings[1] == '@')  # ensure id self typecode
-    assert(type_encodings[2] == ':')  # ensure SEL cmd typecode
+    assert(type_encodings[1] == b'@')  # ensure id self typecode
+    assert(type_encodings[2] == b':')  # ensure SEL cmd typecode
     selector = get_selector(selName)
     cfunctype = cfunctype_for_encoding(types)
     imp = cfunctype(method)
     return imp
 
 def add_ivar(cls, name, vartype):
-    return objc.class_addIvar(cls, name, sizeof(vartype), alignment(vartype), encoding_for_ctype(vartype))
+    return objc.class_addIvar(cls, ensure_bytes(name), sizeof(vartype), alignment(vartype), encoding_for_ctype(vartype))
 
 def set_instance_variable(obj, varname, value, vartype):
     objc.object_setInstanceVariable.argtypes = [c_void_p, c_char_p, vartype]
-    objc.object_setInstanceVariable(obj, varname, value)
+    objc.object_setInstanceVariable(obj, ensure_bytes(varname), value)
     
 def get_instance_variable(obj, varname, vartype):
     variable = vartype()
-    objc.object_getInstanceVariable(obj, varname, byref(variable))
+    objc.object_getInstanceVariable(obj, ensure_bytes(varname), byref(variable))
     return variable.value
 
 ######################################################################
     # Note, need to map 'c' to c_byte rather than c_char, because otherwise
     # ctypes converts the value into a one-character string which is generally
     # not what we want at all, especially when the 'c' represents a bool var.
-    typecodes = {'c':c_byte, 'i':c_int, 's':c_short, 'l':c_long, 'q':c_longlong, 
-                 'C':c_ubyte, 'I':c_uint, 'S':c_ushort, 'L':c_ulong, 'Q':c_ulonglong, 
-                 'f':c_float, 'd':c_double, 'B':c_bool, 'v':None, 'Vv':None, '*':c_char_p,
-                 '@':c_void_p, '#':c_void_p, ':':c_void_p, '^v':c_void_p, '?':c_void_p, 
+    typecodes = {b'c':c_byte, b'i':c_int, b's':c_short, b'l':c_long, b'q':c_longlong, 
+                 b'C':c_ubyte, b'I':c_uint, b'S':c_ushort, b'L':c_ulong, b'Q':c_ulonglong, 
+                 b'f':c_float, b'd':c_double, b'B':c_bool, b'v':None, b'Vv':None, b'*':c_char_p,
+                 b'@':c_void_p, b'#':c_void_p, b':':c_void_p, b'^v':c_void_p, b'?':c_void_p, 
                  NSPointEncoding:NSPoint, NSSizeEncoding:NSSize, NSRectEncoding:NSRect,
                  NSRangeEncoding:NSRange,
                  PyObjectEncoding:py_object}
         the return type and argument type information of the method."""
         self.selector = c_void_p(objc.method_getName(method))
         self.name = objc.sel_getName(self.selector)
-        self.pyname = self.name.replace(':', '_')
+        self.pyname = self.name.replace(b':', b'_')
         self.encoding = objc.method_getTypeEncoding(method)
         self.return_type = objc.method_copyReturnType(method)
         self.nargs = objc.method_getNumberOfArguments(method)
             self.argtypes = None
         # Get types for the return type.
         try:
-            if self.return_type == '@':
+            if self.return_type == b'@':
                 self.restype = ObjCInstance
-            elif self.return_type == '#':
+            elif self.return_type == b'#':
                 self.restype = ObjCClass
             else:
                 self.restype = self.ctype_for_encoding(self.return_type)
         """Return ctypes type for an encoded Objective-C type."""
         if encoding in self.typecodes:
             return self.typecodes[encoding]
-        elif encoding[0] == '^' and encoding[1:] in self.typecodes:
+        elif encoding[0:1] == b'^' and encoding[1:] in self.typecodes:
             return POINTER(self.typecodes[encoding[1:]])
-        elif encoding[0] == '^' and encoding[1:] in [CGImageEncoding, NSZoneEncoding]:
+        elif encoding[0:1] == b'^' and encoding[1:] in [CGImageEncoding, NSZoneEncoding]:
             # special cases
             return c_void_p
-        elif encoding[0] == 'r' and encoding[1:] in self.typecodes:
+        elif encoding[0:1] == b'r' and encoding[1:] in self.typecodes:
             # const decorator, don't care
             return self.typecodes[encoding[1:]]
-        elif encoding[0:2] == 'r^' and encoding[2:] in self.typecodes:
+        elif encoding[0:2] == b'r^' and encoding[2:] in self.typecodes:
             # const pointer, also don't care
             return POINTER(self.typecodes[encoding[2:]])
         else:
         instance for the given Objective-C class.  The argument may be either
         the name of the class to retrieve, or a pointer to the class."""
         # Determine name and ptr values from passed in argument.
-        if isinstance(class_name_or_ptr, basestring):
+        if isinstance(class_name_or_ptr, str):
             name = class_name_or_ptr
-            ptr = c_void_p(objc.objc_getClass(name))
+            ptr = get_class(name)
         else:
             ptr = class_name_or_ptr
             # Make sure that ptr value is wrapped in c_void_p object
         else:
             # If method name isn't in the cached list, it might be a method of
             # the superclass, so call class_getInstanceMethod to check.
-            selector = get_selector(name.replace('_', ':'))
+            selector = get_selector(name.replace(b'_', b':'))
             method = c_void_p(objc.class_getInstanceMethod(self.ptr, selector))
             if method.value:
                 objc_method = ObjCMethod(method)
         else:
             # If method name isn't in the cached list, it might be a method of
             # the superclass, so call class_getInstanceMethod to check.
-            selector = get_selector(name.replace('_', ':'))
+            selector = get_selector(name.replace(b'_', b':'))
             method = c_void_p(objc.class_getClassMethod(self.ptr, selector))
             if method.value:
                 objc_method = ObjCMethod(method)
         """Returns a callable method object with the given name."""
         # If name refers to a class method, then return a callable object
         # for the class method with self.ptr as hidden first parameter.
+        name = ensure_bytes(name)
         method = self.get_class_method(name)
         if method:
             return ObjCBoundMethod(method, self.ptr)
         return objc_instance
 
     def __repr__(self):
-        if self.objc_class.name == 'NSCFString':
+        if self.objc_class.name == b'NSCFString':
             # Display contents of NSString objects
-            from cocoalibs import cfstring_to_string
+            from .cocoalibs import cfstring_to_string
             string = cfstring_to_string(self)
             return "<ObjCInstance %#x: %s (%s) at %s>" % (id(self), self.objc_class.name, string, str(self.ptr.value))
 
         # ObjCBoundMethod, so that it will be able to keep the ObjCInstance
         # alive for chained calls like MyClass.alloc().init() where the 
         # object created by alloc() is not assigned to a variable.
+        name = ensure_bytes(name)
         method = self.objc_class.get_instance_method(name)
         if method:
             return ObjCBoundMethod(method, self)
     new_args = []
     arg_encodings = parse_type_encoding(encoding)[3:]
     for e, a in zip(arg_encodings, args):
-        if e == '@':
+        if e == b'@':
             new_args.append(ObjCInstance(a))
-        elif e == '#':
+        elif e == b'#':
             new_args.append(ObjCClass(a))
         else:
             new_args.append(a)
         The function must have the signature f(self, cmd, *args)
         where both self and cmd are just pointers to objc objects."""
         # Add encodings for hidden self and cmd arguments.
+        encoding = ensure_bytes(encoding)
         typecodes = parse_type_encoding(encoding)
-        typecodes.insert(1, '@:')
-        encoding = ''.join(typecodes)
+        typecodes.insert(1, b'@:')
+        encoding = b''.join(typecodes)
         def decorator(f):
-            name = f.func_name.replace('_', ':')
+            name = f.__name__.replace('_', ':')
             self.add_method(f, name, encoding)
             return f
         return decorator
     def method(self, encoding):
         """Function decorator for instance methods."""
         # Add encodings for hidden self and cmd arguments.
+        encoding = ensure_bytes(encoding)
         typecodes = parse_type_encoding(encoding)
-        typecodes.insert(1, '@:')
-        encoding = ''.join(typecodes)
+        typecodes.insert(1, b'@:')
+        encoding = b''.join(typecodes)
         def decorator(f):
             def objc_method(objc_self, objc_cmd, *args):
                 py_self = ObjCInstance(objc_self)
                 elif isinstance(result, ObjCInstance):
                     result = result.ptr.value
                 return result
-            name = f.func_name.replace('_', ':')
+            name = f.__name__.replace('_', ':')
             self.add_method(objc_method, name, encoding)
             return objc_method
         return decorator
     def classmethod(self, encoding):
         """Function decorator for class methods."""
         # Add encodings for hidden self and cmd arguments.
+        encoding = ensure_bytes(encoding)
         typecodes = parse_type_encoding(encoding)
-        typecodes.insert(1, '@:')
-        encoding = ''.join(typecodes)
+        typecodes.insert(1, b'@:')
+        encoding = b''.join(typecodes)
         def decorator(f):
             def objc_class_method(objc_cls, objc_cmd, *args):
                 py_cls = ObjCClass(objc_cls)
                 elif isinstance(result, ObjCInstance):
                     result = result.ptr.value
                 return result
-            name = f.func_name.replace('_', ':')
+            name = f.__name__.replace('_', ':')
             self.add_class_method(objc_class_method, name, encoding)
             return objc_class_method
         return decorator

File pyglet/window/cocoa/pyglet_delegate.py

 class PygletDelegate_Implementation(object):
     PygletDelegate = ObjCSubclass('NSObject', 'PygletDelegate')
     
-    @PygletDelegate.method('@'+PyObjectEncoding)
+    @PygletDelegate.method(b'@'+PyObjectEncoding)
     def initWithWindow_(self, window):
         self = ObjCInstance(send_super(self, 'init'))
 

File pyglet/window/cocoa/pyglet_textview.py

 class PygletTextView_Implementation(object):
     PygletTextView = ObjCSubclass('NSTextView', 'PygletTextView')
 
-    @PygletTextView.method('@'+PyObjectEncoding)
+    @PygletTextView.method(b'@'+PyObjectEncoding)
     def initWithCocoaWindow_(self, window):
         self = ObjCInstance(send_super(self, 'init'))
         if not self:

File pyglet/window/cocoa/pyglet_view.py

 class PygletView_Implementation(object):
     PygletView = ObjCSubclass('NSView', 'PygletView')
 
-    @PygletView.method('@'+NSRectEncoding+PyObjectEncoding)
+    @PygletView.method(b'@'+NSRectEncoding+PyObjectEncoding)
     def initWithFrame_cocoaWindow_(self, frame, window):
 
         # The tracking area is used to get mouseEntered, mouseExited, and cursorUpdate 
     ## Event responders.
 
     # This method is called whenever the view changes size.
-    @PygletView.method('v'+NSSizeEncoding) 
+    @PygletView.method(b'v'+NSSizeEncoding) 
     def setFrameSize_(self, size):
         send_super(self, 'setFrameSize:', size, argtypes=[NSSize])
 

File pyglet/window/cocoa/pyglet_window.py

     # method is being called instead of this one.  I don't really feel like
     # subclassing NSApplication just to fix this.  Also, to prevent white flashes
     # while resizing, we must also call idle() from the view's reshape method.
-    @PygletWindow.method('@'+NSUIntegerEncoding+'@@B')
+    @PygletWindow.method(b'@'+NSUIntegerEncoding+'@@B')
     def nextEventMatchingMask_untilDate_inMode_dequeue_(self, mask, date, mode, dequeue):
         if self.inLiveResize():
             # Call the idle() method while we're stuck in a live resize event.
 
 
     # Need this for set_size to not flash.
-    @PygletWindow.method('d'+NSRectEncoding)
+    @PygletWindow.method(b'd'+NSRectEncoding)
     def animationResizeTime_(self, newFrame):
         return 0.0
 
 class PygletToolWindow_Implementation(object):
     PygletToolWindow = ObjCSubclass('NSPanel', 'PygletToolWindow')
 
-    @PygletToolWindow.method('@'+NSUIntegerEncoding+'@@B')
+    @PygletToolWindow.method(b'@'+NSUIntegerEncoding+'@@B')
     def nextEventMatchingMask_untilDate_inMode_dequeue_(self, mask, date, mode, dequeue):
         if self.inLiveResize():
             # Call the idle() method while we're stuck in a live resize event.
             return event.value
 
     # Need this for set_size to not flash.
-    @PygletToolWindow.method('d'+NSRectEncoding)
+    @PygletToolWindow.method(b'd'+NSRectEncoding)
     def animationResizeTime_(self, newFrame):
         return 0.0