Commits

Ronald Oussoren committed da9d583

- Added some documentation
- Change Lib/objc to 4-space indents and remove superfluor whitespace

Comments (0)

Files changed (7)

+2002-11-18 Ronald Oussoren <oussoren@cistron.nl>
+	* Doc/classes.txt: new file documenting how classes work
+	* Modules/objc: Reformatted (4-space indent)
+
 2002-11-17  Bill Bumgarner  <bbum@codefab.com>
 
 	* Normalize whitespace

pyobjc/Doc/classes.txt

+Python classes and Objective-C code
+===================================
+
+.. This file is formatted using the rules for StructuredText
+
+.. Version 0.1
+
+Introduction
+------------
+
+PyObjC is a proxy between Objective-C and Python and allows access to Python
+classes from Objective-C and vice versa. PyObjC also allows you to subclass
+Objective-C classes from Python. 
+
+Accessing Python objects from Objective-C
+-----------------------------------------
+
+All Python objects can be accessed from Objective-C through proxy objects. 
+Whenever a Python object crosses the line from Python to Objective-C a proxy
+object is created (of class OC_PythonObject, a subclass of NSProxy). This
+proxy object will forward all method calls from Objective-C to python, and
+will return the results back to Objective-C.
+
+See the section 'Method protocol' for a description of how PyObjC translates 
+between Python and Objective-C method calls.
+
+Other than being a plain proxy the OC_PythonObject class also provides an
+Objective-C flavored version of the Python C-API. 
+
+.. Is anyone actually using the Objective-C version of the Python C-API?
+
+A number of Python types/classes are treated specially:
+- Python numbers are translated into NSNumber instances
+- Python strings and unicode objects are translated into NSString instances
+- Python dictionaries are proxied using OC_PythonDictionary, a subclass of NSMutableDictionary.
+  This allows you to use a Python dictionary everywhere where an NSDictionary
+  is expected.
+- Python lists or tuples are proxied using OC_PythonArray, a subclas of NSMutableArray.
+  This allows you to use a Python list or tuple everywhere where an NSArray
+  is expected.
+
+The special cases allow for more transparent bridging between Python and
+Objective-C.
+
+Accessing Objective-C objects from Python
+-----------------------------------------
+
+Objective-C objects are accessed through proxy objects that forward method
+calls from Python to Objective-C. All proxy objects are instances of 
+objc.objc_object, or a subclass of this class.
+
+See the section 'Method protocol' for a description of how PyObjC translates 
+between Python and Objective-C method calls.
+
+The only Objective-C class that is not proxied is NSString, instances of this
+class are translated to Python strings or unicode objects (depending on the
+value of the string).
+
+Accessing Objective-C classes from Python
+-----------------------------------------
+
+Objective-C classes are also accessed through proxy objects, but those are
+subclasses of objc.objc_class. The proxies for Objective-C classes are 
+classes in Python. 
+
+Instances are created by calling allocator class methods (like 'alloc' or
+factory methods). Objective-C instances cannot be created by using the class
+as a factory function.
+
+It is possible to create subclasses from Objective-C classes using the normal
+mechanism. There are some limitations though:
+
+1. The Objective-C class must be the first base class
+2. There can be only 1 Objective-C base class.
+   It is not possible to multiple-inherit from two Objective-C classes, this
+   limitation is inherited from Objective-C.
+3. It is not possible to overide or extend an Objective-C method using a mixin.
+   This is limitation will be lifted in future versions of PyObjC.
+4. It is not possible to overide or extend an Objective-C method by adding a new method to the class after creating it.
+
+PyObjC provides limited support for Objective-C protocols. The type 
+obc.informal_protocol can be used to shadow protocol definitions in Objective-C.
+Instances of this type can be used as a superclass when defining a subclass of
+an existing Objective-C class. The information in an 'informal_protocol' object
+will be used to check if the new class does implement the protocol, and to
+provide information to the bridge that is needed to correctly forward methods.
+
+A subclass of an Objective-C (proxy) class is not only a Python class, but also
+an Objective-C class. This means that it is possible to create instances of 
+these classes from Objective-C using normal Objective-C syntax, although you
+must locate the class using the function 'objc_lookUpClass' (e.g. defining
+@class MyPythonClass will not work). One of the results of this feature is that
+these classes can be used to implement classes that are defined in Interface
+Builder NIB files.
+
+Like Python classes Objective-C classes can have instance variables. If you
+define new instance variables in the Python subclass they will only be visible
+in Python, and not in Objective-C. This means that normal Python instance
+variables cannot be used as 'outlets' in interface builder. Those can be 
+defined using special properties: objc.instance_variable or objc.IBOutlet.
+
+The Objective-C class:
+
+	@interface MyClass : NSObject
+	{
+		IBOutlet id my_outlet1;
+		IBOutlet id my_outlet2;
+	}
+
+	// ...
+	@end // MyClass
+
+can be defined in Python like this:
+
+	class MyClass (NSObject):
+		my_outlet1 = objc.IBOutlet('my_outlet1')
+		my_outlet2 = objc.IBOutlet('my_outlet2')
+
+		# ...
+
+Method protocol
+---------------
+
+There is a straightforward translation from Objective-C method names to
+Python method names: Concatenate all parts of the Objective-C method name
+(without any whitespace) and then replace all colons by underscores.
+
+Examples:
+- (void)myAction:(id)sender	<->	def myAction_(self, sender)
+- method:(int)x andY:y		<->	def method_andY_(self, x, y)
+
+As can be seen in the examples above, Objective-C allows you to specify
+the types of arguments and the return value, while this is not possible in
+Python. This is not a problem when calling existing Objective-C methods, 
+because PyObjC will automaticly read the needed information from the 
+Objective-C runtime, but it can be a problem when defining new Objective-C
+methods in Python.
+
+PyObjC therefore provides a function to define the signature of a python method
+in subclasses of Objective-C classes. This function, objc.selector, should be
+used whenever you define a method that does not extend or override an existing
+Objective-C method in the superclass. 
+
+The following Objective-C class:
+
+	@interface MyClass : NSObject
+	{
+	}
+
+	-(int)methodWithX:(int)x andY:(float)y;
+	-(void)myAction:(id)sender;
+
+can be defined in Python like this:
+	
+	class MyClass (NSObject):
+
+		def methodWithX_andY_(self, x, y):
+			pass
+
+		methodWithX_and_Y_ = selector(methodWithX_andY_,
+			signature='i@:if')
+
+		def myAction_(self, sender):
+			pass
+
+		myAction_ = selector(myAction_,
+			signature='v@:')
+
+The explicit selectors don't really help to increase readability, especially
+given the cryptic signature strings. It is therefore advisable to use other
+methods to define the signature if possible, the most likely way to do this
+is by using existing objc.informal_protocol definitions (like 
+AppKit.NSOutlineViewDataSource). 
+
+There is one instance where you don't have to define the signature: The default
+signature is for a method that returns and object and where all arguments are
+also objects.

pyobjc/Lib/objc/__init__.py

 ##
 import sys
 if sys.version_info[:3] == (2,2,0):
-	import gc
-	gc.disable()
+    import gc
+    gc.disable()
 
 # Aliases for some common Objective-C constants
 import __builtin__
 if hasattr(__builtin__, 'True'):
-	YES=True
-	NO=False
+    YES=True
+    NO=False
 else:
-	YES=1
-	NO=0
+    YES=1
+    NO=0
 nil=None
 
 from _objc import *
 import _objc
 gl = globals()
 for nm in [ x for x in dir(_objc) if x.startswith('_C_') ]:
-	gl[nm] = getattr(_objc, nm)
+    gl[nm] = getattr(_objc, nm)
 del gl, nm, _objc, x
 
 
 # are the only methods that transfer ownership.
 #
 def register_allocator_selector(selector):
-	"""
-	register 'selector' as a method that transfers ownership of the 
-	returned object to the caller. 
-	
-	This information is used by the proxy code to correctly maintain 
-	reference counts. It is highly unlikely that this function should
-	be called outside of the 'objc' module.
-	"""
-	ALLOCATOR_METHODS[selector] = 1
+    """
+    register 'selector' as a method that transfers ownership of the 
+    returned object to the caller. 
+    
+    This information is used by the proxy code to correctly maintain 
+    reference counts. It is highly unlikely that this function should
+    be called outside of the 'objc' module.
+    """
+    ALLOCATOR_METHODS[selector] = 1
 
 register_allocator_selector('alloc')
 register_allocator_selector('allocWithZone:')
 
 
 class _runtime:
-	"""
-	Backward compatibility interface.
+    """
+    Backward compatibility interface.
 
-	This class provides (partial) support for the interface of 
-	older versions of PyObjC.
-	"""
-	def __getattr__(self, name):
-		if name == '__objc_classes__':
-			return class_list()
-		elif name == '__kind__':
-			return 'python'
+    This class provides (partial) support for the interface of 
+    older versions of PyObjC.
+    """
+    def __getattr__(self, name):
+        if name == '__objc_classes__':
+            return class_list()
+        elif name == '__kind__':
+            return 'python'
 
-		return lookup_class(name)
+        return lookup_class(name)
 
-	def __eq__(self, other):
-		return self is other
+    def __eq__(self, other):
+        return self is other
 
-	def __repr__(self):
-		return "objc.runtime"
+    def __repr__(self):
+        return "objc.runtime"
 runtime = _runtime()
 del _runtime
 
 IBOutlet = ivar
 
 def IBAction(func):
-	"""
-	Return an Objective-C method object that can be used as an action
-	in Interface Builder.
-	"""
-	return selector(func, signature="v@:@")
+    """
+    Return an Objective-C method object that can be used as an action
+    in Interface Builder.
+    """
+    return selector(func, signature="v@:@")
 
 
 
 # is ugly, but it is also something that would be very
 # hard to avoid...
 try:
-	import _FoundationSignatures
-	del _FoundationSignatures
+    import _FoundationSignatures
+    del _FoundationSignatures
 except ImportError:
-	pass
+    pass
 
 try:
-	import _FoundationMapping
-	del _FoundationMapping
+    import _FoundationMapping
+    del _FoundationMapping
 except ImportError:
-	pass
+    pass
 
 # This is a hack, should probably patch python:
 # - We want the resources directory to be on the python search-path
 # - It must be at the start of the path
 # - The CWD must not be on the path
 if 1 :
-	b = lookup_class('NSBundle').mainBundle()
-	if b:
-		sys.path.insert(0, '%s/Contents/Resources'%str(b.bundlePath()))
-	del b
+    b = lookup_class('NSBundle').mainBundle()
+    if b:
+        sys.path.insert(0, '%s/Contents/Resources'%str(b.bundlePath()))
+    del b
 del sys, __builtin__

pyobjc/Lib/objc/_convenience.py

 CLASS_METHODS = {}
 
 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.
+    """
+    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'.
-	"""
-	for sel in type_dict.values():
-		if not isinstance(sel, selector):
-			continue
-		sel = sel.selector
+    Matching entries from both mappings are added to the 'type_dict'.
+    """
+    for sel in type_dict.values():
+        if not isinstance(sel, selector):
+            continue
+        sel = sel.selector
 
-		if CONVENIENCE_METHODS.has_key(sel):
-			v = CONVENIENCE_METHODS[sel]
-			for name, value in v:
-				type_dict[name] = value
-	
-	if CLASS_METHODS.has_key(name):
-		for name, value in CLASS_METHODS[name]:
-			type_dict[name] = value
+        if CONVENIENCE_METHODS.has_key(sel):
+            v = CONVENIENCE_METHODS[sel]
+            for name, value in v:
+                type_dict[name] = value
+    
+    if CLASS_METHODS.has_key(name):
+        for name, value in CLASS_METHODS[name]:
+            type_dict[name] = value
 
 set_class_extender(add_convenience_methods)
 
 # that have such a type.
 
 def __getitem__objectForKey(self, key):
-	res = self.objectForKey_(key)
-	if res is None:
-		raise KeyError, key
-	return res
+    res = self.objectForKey_(key)
+    if res is None:
+        raise KeyError, key
+    return res
 def has_key_objectForKey(self, key):
-	res = self.objectForKey_(key)
-	return not (res is None)
+    res = self.objectForKey_(key)
+    return not (res is None)
 def get_objectForKey(self, key, dflt=None):
-	res = self.objectForKey_(key)
-	if res is None: 
-		res = dflt
-	return res
-CONVENIENCE_METHODS['objectForKey:'] = (('__getitem__', __getitem__objectForKey),
-					('has_key', has_key_objectForKey),
-					('get', get_objectForKey),
-					('__contains__', lambda self, elem: (self.objectForKey_(elem) != None)
-					 ))
+    res = self.objectForKey_(key)
+    if res is None: 
+        res = dflt
+    return res
+CONVENIENCE_METHODS['objectForKey:'] = (
+    ('__getitem__', __getitem__objectForKey),
+    ('has_key', has_key_objectForKey),
+    ('get', get_objectForKey),
+    ('__contains__', lambda self, elem: (self.objectForKey_(elem) != None)),
+)
 
-CONVENIENCE_METHODS['removeObjectForKey:'] = (('__delitem__',
-					       lambda self, key: self.removeObjectForKey_( key ) ), )
+CONVENIENCE_METHODS['removeObjectForKey:'] = (
+    ('__delitem__', lambda self, key: self.removeObjectForKey_(key)), 
+)
 
-CONVENIENCE_METHODS['setObject:forKey:'] = (('__setitem__',
-					     lambda self, key, value: self.setObject_forKey_( value, key ) ), )
+CONVENIENCE_METHODS['setObject:forKey:'] = (
+    ('__setitem__', lambda self, key, value: self.setObject_forKey_(value, key)), 
+)
 
-CONVENIENCE_METHODS['count'] = (('__len__',
-				 lambda self: self.count() ),)
+CONVENIENCE_METHODS['count'] = (
+    ('__len__', lambda self: self.count()),
+)
 
-CONVENIENCE_METHODS['description'] = (('__repr__',
-				       lambda self: self.description() ),)
+CONVENIENCE_METHODS['description'] = (
+    ('__repr__', lambda self: self.description()),
+)
 
-CONVENIENCE_METHODS['containsObject:'] = (('__contains__',
-					   lambda self, elem: (self.containsObject_(elem) != 0)),)
+CONVENIENCE_METHODS['containsObject:'] = (
+    ('__contains__', lambda self, elem: (self.containsObject_(elem) != 0)),
+)
 
-CONVENIENCE_METHODS['hash'] = (('__hash__',
-				lambda self: self.hash() ),)
+CONVENIENCE_METHODS['hash'] = (
+    ('__hash__', lambda self: self.hash()),
+)
 
-CONVENIENCE_METHODS['isEqualTo:'] = (('__eq__',
-				      lambda self, other: self.isEqualTo_( other ) ),)
+CONVENIENCE_METHODS['isEqualTo:'] = (
+    ('__eq__', lambda self, other: self.isEqualTo_(other)),
+)
 
-CONVENIENCE_METHODS['isEqual:'] = (('__eq__',
-				    lambda self, other: self.isEqual_( other ) ),)
+CONVENIENCE_METHODS['isEqual:'] = (
+    ('__eq__', lambda self, other: self.isEqual_(other)),
+)
 
-CONVENIENCE_METHODS['isGreaterThan:'] = (('__gt__',
-					  lambda self, other: self.isGreaterThan_( other ) ),)
+CONVENIENCE_METHODS['isGreaterThan:'] = (
+    ('__gt__', lambda self, other: self.isGreaterThan_(other)),
+)
 
-CONVENIENCE_METHODS['isGreaterThanOrEqualTo:'] = (('__ge__',
-						   lambda self, other: self.isGreaterThanOrEqualTo_( other ) ),)
+CONVENIENCE_METHODS['isGreaterThanOrEqualTo:'] = (
+    ('__ge__', lambda self, other: self.isGreaterThanOrEqualTo_(other)),
+)
 
-CONVENIENCE_METHODS['isLessThan:'] = (('__lt__',
-				       lambda self, other: self.isLessThan_( other ) ),)
+CONVENIENCE_METHODS['isLessThan:'] = (
+    ('__lt__', lambda self, other: self.isLessThan_(other)),
+)
 
-CONVENIENCE_METHODS['isLessThanOrEqualTo:'] = (('__le__',
-						lambda self, other: self.isLessThanOrEqualTo_( other ) ),)
+CONVENIENCE_METHODS['isLessThanOrEqualTo:'] = (
+    ('__le__', lambda self, other: self.isLessThanOrEqualTo_(other)),
+)
 
-CONVENIENCE_METHODS['isNotEqualTo:'] = (('__ne__',
-					 lambda self, other: self.isNotEqualTo_( other ) ),)
+CONVENIENCE_METHODS['isNotEqualTo:'] = (
+    ('__ne__', lambda self, other: self.isNotEqualTo_(other)),
+)
 
-CONVENIENCE_METHODS['length'] = (('__len__',
-				  lambda self: self.length() ),)
+CONVENIENCE_METHODS['length'] = (
+    ('__len__', lambda self: self.length()),
+)
 
 def __getitem__objectAtIndexWithSlice(self, x, y):
-	l = len(self)
-	r = y - x
-	if r < 0:
-		return []
-	if (r - x) > l:
-		r = l - x
-	return self.subarrayWithRange_( (x, r) )
-CONVENIENCE_METHODS['objectAtIndex:'] = (('__getitem__', lambda self, index: self.objectAtIndex_( index )),
-					 ('__getslice__', __getitem__objectAtIndexWithSlice) )
+    l = len(self)
+    r = y - x
+    if r < 0:
+        return []
+    if (r - x) > l:
+        r = l - x
+    return self.subarrayWithRange_( (x, r) )
+
+CONVENIENCE_METHODS['objectAtIndex:'] = (
+    ('__getitem__', lambda self, index: self.objectAtIndex_(index)),
+    ('__getslice__', __getitem__objectAtIndexWithSlice),
+)
 
 def __delslice__removeObjectAtIndex(self, x, y):
-	l = len(self)
-	r = y - x
-	if r < 0:
-		return
-	if (r - x) > l:
-		r = l - x
-	return self.removeObjectsInRange_( (x, r) )
-	
-CONVENIENCE_METHODS['removeObjectAtIndex:'] = (('__delitem__', lambda self, index: self.removeObjectAtIndex_( index )),
-					       ('__delslice__', __delslice__removeObjectAtIndex ) )
+    l = len(self)
+    r = y - x
+    if r < 0:
+        return
+    if (r - x) > l:
+        r = l - x
+    return self.removeObjectsInRange_( (x, r) )
+    
+CONVENIENCE_METHODS['removeObjectAtIndex:'] = (
+    ('__delitem__', lambda self, index: self.removeObjectAtIndex_(index)),
+    ('__delslice__', __delslice__removeObjectAtIndex),
+)
 
-CONVENIENCE_METHODS['replaceObjectAtIndex:withObject:'] = (('__setitem__',
-							    lambda self, index, anObject: self.replaceObjectAtIndex_withObject_( index, anObject) ),)
+CONVENIENCE_METHODS['replaceObjectAtIndex:withObject:'] = (
+    ('__setitem__', lambda self, index, anObject: self.replaceObjectAtIndex_withObject_(index, anObject)),
+)
 
 def __setslice__replaceObjectAtIndex_withObject(self, x, y, v):
-	l = len(self)
-	r = y - x
-	if r < 0:
-		return
-	if (r - x) > l:
-		r = l - x
-	return self.replaceObjectsInRange_withObjectsFromArray_( (x, r), v )
-CONVENIENCE_METHODS['replaceObjectsInRange:withObjectsFromArray:'] = (('__setslice__', __setslice__replaceObjectAtIndex_withObject), )
+    l = len(self)
+    r = y - x
+    if r < 0:
+        return
+    if (r - x) > l:
+        r = l - x
+    return self.replaceObjectsInRange_withObjectsFromArray_( (x, r), v )
+
+CONVENIENCE_METHODS['replaceObjectsInRange:withObjectsFromArray:'] = (
+    ('__setslice__', __setslice__replaceObjectAtIndex_withObject), 
+)
 
 # Mapping protocol
 
 # __str__ would be nice (as obj.description()),
 
 def enumeratorGenerator(anEnumerator):
-	nextObject = anEnumerator.nextObject()
-	while (nextObject):
-		yield nextObject
-		nextObject = anEnumerator.nextObject()
+    nextObject = anEnumerator.nextObject()
+    while (nextObject):
+        yield nextObject
+        nextObject = anEnumerator.nextObject()
 
-CONVENIENCE_METHODS['allKeys'] = (('keys', lambda self: self.allKeys()), )
-CONVENIENCE_METHODS['allValues'] = (('values', lambda self: self.allValues()), )
+CONVENIENCE_METHODS['allKeys'] = (
+    ('keys', lambda self: self.allKeys()),
+)
 
-CONVENIENCE_METHODS['keyEnumerator'] = (('__iter__',
-					 lambda self: enumeratorGenerator( self.keyEnumerator() ) ),
+CONVENIENCE_METHODS['allValues'] = (
+    ('values', lambda self: self.allValues()),
+)
 
-					('iterkeys',
-					 lambda self: enumeratorGenerator( self.keyEnumerator() ) ) )
+CONVENIENCE_METHODS['keyEnumerator'] = (
+    ('__iter__', lambda self: enumeratorGenerator(self.keyEnumerator())),
+    ('iterkeys', lambda self: enumeratorGenerator( self.keyEnumerator())),
+)
 
-CONVENIENCE_METHODS['objectEnumerator'] = (('values', lambda self: self.allValues()),
+CONVENIENCE_METHODS['objectEnumerator'] = (
+    ('values', lambda self: self.allValues()),
+    ('__iter__', lambda self: enumeratorGenerator(self.objectEnumerator())),
+    ('itervalues', lambda self: enumeratorGenerator( self.objectEnumerator())),
+)
 
-					   ('__iter__',
-					    lambda self: enumeratorGenerator( self.objectEnumerator() ) ),
+CONVENIENCE_METHODS['removeAllObjects'] = (
+    ('clear', lambda self: self.removeAllObjects()),
+)
 
-					   ('itervalues',
-					    lambda self: enumeratorGenerator( self.objectEnumerator() ) ) )
-
-CONVENIENCE_METHODS['removeAllObjects'] = (('clear', lambda self: self.removeAllObjects()),)
-CONVENIENCE_METHODS['dictionaryWithDictionary:'] = (('copy', lambda self: type(self).dictionaryWithDictionary_(self)),)
+CONVENIENCE_METHODS['dictionaryWithDictionary:'] = (
+    ('copy', lambda self: type(self).dictionaryWithDictionary_(self)),
+) 

pyobjc/Lib/objc/builder.py

 Utility module that helps with building a module.
 
 Usage:
-	import objc.builder
+    import objc.builder
 
-	objc.builder.build_applet('myapp', 'main.py', ['mod1.py' ... ],
-		[ 'English.lproj', ...])
+    objc.builder.build_applet('myapp', 'main.py', ['mod1.py' ... ],
+        [ 'English.lproj', ...])
 
 TODO: 
 * the same module should contain function for replacing/enhancing the 
 import os
 
 try:
-	getattr(__builtins__, 'True')
+    getattr(__builtins__, 'True')
 except AttributeError:
-	True=1
-	False=0
+    True=1
+    False=0
 
 def build_applet(app_name,
-		main_py, 
-		extra_src = [], 
-		extra_files = [], 
-		raw=False, 
-		resource_file=None,
-		info_plist=None):
-	"""
-	Build an applet. 
-	"""
+        main_py, 
+        extra_src = [], 
+        extra_files = [], 
+        raw=False, 
+        resource_file=None,
+        info_plist=None):
+    """
+    Build an applet. 
+    """
 
-	def dirname(path):
-		r = os.path.split(path)[0]
-		if not r:
-			return '.'
-		else:
-			return r
+    def dirname(path):
+        r = os.path.split(path)[0]
+        if not r:
+            return '.'
+        else:
+            return r
 
-	# Basic argument checks
-	assert isinstance(app_name, str)
-	assert os.path.exists(dirname(app_name))
-	assert isinstance(main_py, str)
-	assert os.path.exists(main_py)
-	assert isinstance(extra_src, (list, tuple))
-	assert reduce(lambda x, y: x and y, 
-		[ os.path.exists(x) for x in extra_src ], True)
-	assert isinstance(extra_files, list) or isinstance(extra_files, tuple)
-	assert reduce(lambda x, y: x and y, 
-		[ os.path.exists(x) for x in extra_files ], True)
-	assert isinstance(raw, int)
-	assert (resource_file is None) or (
-		isinstance(resource_file, str) and 
-		os.path.exists(resource_file))
-	
-	assert (info_plist is None) or isinstance(info_plist, str)
+    # Basic argument checks
+    assert isinstance(app_name, str)
+    assert os.path.exists(dirname(app_name))
+    assert isinstance(main_py, str)
+    assert os.path.exists(main_py)
+    assert isinstance(extra_src, (list, tuple))
+    assert reduce(lambda x, y: x and y, 
+        [ os.path.exists(x) for x in extra_src ], True)
+    assert isinstance(extra_files, list) or isinstance(extra_files, tuple)
+    assert reduce(lambda x, y: x and y, 
+        [ os.path.exists(x) for x in extra_files ], True)
+    assert isinstance(raw, int)
+    assert (resource_file is None) or (
+        isinstance(resource_file, str) and 
+        os.path.exists(resource_file))
+    
+    assert (info_plist is None) or isinstance(info_plist, str)
 
-	template  = buildtools.findtemplate()
-	
-	others = extra_src[:]
-	others.extend(extra_files)
+    template  = buildtools.findtemplate()
+    
+    others = extra_src[:]
+    others.extend(extra_files)
 
-	# remove the output if it already exists
-	if os.path.exists(app_name + '.app'):
-		shutil.rmtree(app_name + '.app')
+    # remove the output if it already exists
+    if os.path.exists(app_name + '.app'):
+        shutil.rmtree(app_name + '.app')
 
-	buildtools.process(template, main_py, app_name, 1,
-		rsrcname = resource_file, others = others,
-		raw = raw, progress = None)
+    buildtools.process(template, main_py, app_name, 1,
+        rsrcname = resource_file, others = others,
+        raw = raw, progress = None)
 
-	if info_plist:
-		shutil.copyfile(info_plist,
-			os.path.join(app_name + '.app', 
-				'Contents', 'Info.plist'))
+    if info_plist:
+        shutil.copyfile(info_plist,
+            os.path.join(app_name + '.app', 
+                'Contents', 'Info.plist'))

pyobjc/Lib/objc/test/test_objc.py

 
 class TestConstants(unittest.TestCase):
     def testBooleans(self):
-        self.assert_( objc.YES, "YES was not true." )
-        self.assert_( not objc.NO, "NO was true." )
+        self.assert_(objc.YES, "YES was not true.")
+        self.assert_(not objc.NO, "NO was true.")
 
     def testNil(self):
         from types import NoneType
-        self.assert_( not objc.nil, "nil is not nil/None." )
+        self.assert_(not objc.nil, "nil is not nil/None.")
     
 class TestClassLookup(unittest.TestCase):
     def testLookupClassNoSuchClassErrorRaised(self):
-        self.assertRaises( objc.nosuchclass_error, objc.lookup_class, "" )
-        self.assertRaises( objc.nosuchclass_error, objc.lookup_class, "ThisClassReallyShouldNotExist" )
-        self.assertRaises( TypeError, objc.lookup_class, 1 )
+        self.assertRaises(objc.nosuchclass_error, objc.lookup_class, "")
+        self.assertRaises(objc.nosuchclass_error, objc.lookup_class, "ThisClassReallyShouldNotExist")
+        self.assertRaises(TypeError, objc.lookup_class, 1)
 
     def testRuntimeNoSuchClassErrorRaised(self):
         try:
             fail("objc.runtime.ThisClassReallyShouldNotExist should have thrown a nosuchclass_error.  It didn't.")
 
     def testRuntimeConsistency(self):
-        self.assert_( objc.lookup_class("NSObject"), "Failed to find NSObject class." )
-        self.assertEqual( objc.lookup_class( "NSObject" ), objc.runtime.NSObject,
-                          "objc.runtime.NSObject and objc.lookup_class('NSObject') were different." )
+        self.assert_(objc.lookup_class("NSObject"), "Failed to find NSObject class.")
+        self.assertEqual(objc.lookup_class( "NSObject" ), objc.runtime.NSObject,
+                          "objc.runtime.NSObject and objc.lookup_class('NSObject') were different.")
 
     def testClassList(self):
         ###! This test should probably be moved down to the Foundation test suite... 
-        self.assert_( objc.runtime.NSObject in objc.class_list(), "class_list() does not appear to contain NSObject class" )
-        self.assert_( objc.runtime.NSException in objc.class_list(), "class_list() does not appear to contain NSException class" )
-        self.assert_( objc.runtime.NSMutableArray in objc.class_list(), "class_list() does not appear to contain NSMutableArray class" )
+        self.assert_(objc.runtime.NSObject in objc.class_list(), "class_list() does not appear to contain NSObject class")
+        self.assert_(objc.runtime.NSException in objc.class_list(), "class_list() does not appear to contain NSException class")
+        self.assert_(objc.runtime.NSMutableArray in objc.class_list(), "class_list() does not appear to contain NSMutableArray class")
 
 class TestMethodInvocation(unittest.TestCase):
     def setUp(self):
         self.NSObjectInstance = objc.runtime.NSObject.alloc()
 
     def testClassInvocation(self):
-        self.assert_( objc.runtime.NSObject.description(objc.runtime.NSObject), "Failed to invoke the +description method." )
+        self.assert_(objc.runtime.NSObject.description(objc.runtime.NSObject), "Failed to invoke the +description method.")
 
     def testInstanceInvocation(self):
-        self.assert_( self.NSObjectInstance.description(), "Failed to invoke the -description method." )
-        self.assertEqual( self.NSObjectInstance.self(), self.NSObjectInstance, "-self did not return same self." )
+        self.assert_(self.NSObjectInstance.description(), "Failed to invoke the -description method.")
+        self.assertEqual(self.NSObjectInstance.self(), self.NSObjectInstance, "-self did not return same self.")
 
     def testVarargsInvocation(self):
-        objc.runtime.NSArray.arrayWithObjects_( "foo", "bar", None )
+        objc.runtime.NSArray.arrayWithObjects_("foo", "bar", None)
         
 
 def suite():
     suite = unittest.TestSuite()
-    suite.addTest( unittest.makeSuite( TestConstants ) )
-    suite.addTest( unittest.makeSuite( TestClassLookup ) )
-    suite.addTest( unittest.makeSuite( TestMethodInvocation ) )
+    suite.addTest(unittest.makeSuite(TestConstants))
+    suite.addTest(unittest.makeSuite(TestClassLookup))
+    suite.addTest(unittest.makeSuite(TestMethodInvocation))
     return suite
 
 if __name__ == '__main__':
-    unittest.main( )
+    unittest.main()

pyobjc/Lib/objc/test/test_subclass.py

 NSObject = objc.lookup_class('NSObject')
 
 class TestSubclassing(unittest.TestCase):
-	def testSubclassOfSubclass(self):
-		import string
-		class Level1Class (NSObject):
-			def hello(self):
-				return "level1"
+    def testSubclassOfSubclass(self):
+        import string
+        class Level1Class (NSObject):
+            def hello(self):
+                return "level1"
 
-		class Level2Class (Level1Class):
-			def hello(self):
-				return "level2"
+        class Level2Class (Level1Class):
+            def hello(self):
+                return "level2"
 
-			def superHello(self):
-				return super(Level2Class, self).hello()
+            def superHello(self):
+                return super(Level2Class, self).hello()
 
-			def description(self):
-				return super(Level2Class, self).description()
+            def description(self):
+                return super(Level2Class, self).description()
 
-		obj = Level1Class.alloc().init()
-		v = obj.hello()
-		self.assertEquals(v, "level1")
+        obj = Level1Class.alloc().init()
+        v = obj.hello()
+        self.assertEquals(v, "level1")
 
-		obj = Level2Class.alloc().init()
-		v = obj.hello()
-		self.assertEquals(v, "level2")
+        obj = Level2Class.alloc().init()
+        v = obj.hello()
+        self.assertEquals(v, "level2")
 
-		v = obj.superHello()
-		self.assertEquals(v, "level1")
+        v = obj.superHello()
+        self.assertEquals(v, "level1")
 
-		v = obj.description()
-		# this may be a bit hardwired for comfort
-		self.assert_( string.index(v, "<Level2Class") == 0 )
-	
-	def testUniqueNames(self):
-		class SomeClass (NSObject): pass
+        v = obj.description()
+        # this may be a bit hardwired for comfort
+        self.assert_(string.index(v, "<Level2Class") == 0)
+    
+    def testUniqueNames(self):
+        class SomeClass (NSObject): pass
 
-		try:
-			class SomeClass (NSObject): pass
+        try:
+            class SomeClass (NSObject): pass
 
-			fail("Should not have been able to redefine the SomeClass class!")
-		except objc.error, msg:
-			self.assertEquals(str(msg), "Class already exists in Objective-C runtime")
+            fail("Should not have been able to redefine the SomeClass class!")
+        except objc.error, msg:
+            self.assertEquals(str(msg), "Class already exists in Objective-C runtime")
 
 def suite():
     suite = unittest.TestSuite()
-    suite.addTest( unittest.makeSuite( TestSubclassing ) )
+    suite.addTest(unittest.makeSuite(TestSubclassing))
     return suite
 
 if __name__ == '__main__':
-    unittest.main( )
+    unittest.main()