Commits

Ronald Oussoren committed a063a2a

- Add some documentation
- Adding special methods is now done using python code
- Special proxy objects for python dicts and sequences

Comments (0)

Files changed (18)

 	  contains a reference to the class that defined this method.
 	* Added type objc.informal_protocol, which can be used to eliminate
 	  most existing cases of explicit calls to 'objc.selector'
+	* Adding methods like __getitem__ to Objective-C class proxies is
+	  now done using python code. This should make it easier to change
+	  the implementation (and: less C code ==> good)
 
 2002-10-17  Bill Bumgarner  <bbum@codefab.com>
 	* Fixed a situation where ObjCErr_ToObjC() would crash if the

pyobjc/Doc/users.txt

 Overview
 --------
 
-TODO
+Using PyObjC is pretty simple, as it strives to make the bridge completely
+transparent. On the lowest level you can import the 'objc' module and use that
+to locate classes (objc.lookup_class). For most users it is more usefull to
+just import 'Foundation' and 'AppKit' and use the familiar Cocoa classes
+and functions.
 
+Objective-C classes are make available as new-style classes, and can be queried
+using the normal introspection techniques. 
 
-Variables and Constants
------------------------
+Methodnames for Objective-C classes are constructed as follows: Concatenate all 
+elements of the selector and replace colons by underscores. 
 
-TODO
+The order of arguments is the same as in Objective-C, with one exception: If
+a method as output-only arguments those arguments are not present in the python
+version of the method. If a method has output parameters (either input-output
+or output-only) the values of these parameters are passed back in the return
+value of the python version. The return value of methods with output parameters
+is a tuple where the first element is the return-value of the Objective-C 
+method (or None if it is a method returning 'void') and the other elements are
+the values of output arguments.
 
-
-Functions
----------
-
-TODO
-
-
+The type objc.informal_protocol can be used to specify the selectors used by
+(informal) protocols in Objective-C. Instances of objc.informal_protocol are
+used when defineing subclasses of Objective-C classes and signal that the class
+implements the given protocol. The AppKit and Foundation modules export a 
+number of usefull protocols.
 
 Limitations
 -----------
 pass-by-reference arguments. If there are, the core module needs some help.
 
 For this reason it is best to not use just the core API when your working with
-this module, but to use packages like 'Cocoa' that provide the help needed and
-might also wrap other functionality (constants, functions) in a framework.
+this module, but to use packages like 'Foundation' that provide the help 
+needed and might also wrap other functionality (constants, functions) in a framework.
 
+The current version of the module does not provide support for threading. It
+might be possible to create threads using the 'thread' module if you manually
+create an NSAutoreleasePool for the thread. This has not been tested. The
+Cocoa threading classes should not be used because they don't update the 
+state of the Python interpreter when creating a new thread.
 
 C API
 -----

pyobjc/Lib/objc/__init__.py

 del gl, nm, _objc
 
 
-# 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
-b = lookup_class('NSBundle').mainBundle()
-if b:
-	import sys
-	sys.path.insert(0, '%s/Contents/Resources'%str(b.bundlePath()))
-	try:
-		del sys.path[sys.path.index('')]
-	except ValueError:
-		pass
-	del sys
-del b
 
 
 #
 ALLOCATOR_METHODS['copyWithZone:'] = 1
 ALLOCATOR_METHODS['mutableCopyWithZone:'] = 1
 
-# Some special modules needed to correctly wrap all
-# methods in the Foundation framework. Doing it here
-# is ugly, but it is also something that would be very
-# hard to avoid...
-try:
-	import _FoundationSignatures
-	del _FoundationSignatures
-except ImportError:
-	pass
-
-try:
-	import _FoundationMapping
-	del _FoundationMapping
-except ImportError:
-	pass
 
 
 # Add usefull utility functions below
 NO=0
 nil=None
 
+import _convenience
 
+# Some special modules needed to correctly wrap all
+# methods in the Foundation framework. Doing it here
+# is ugly, but it is also something that would be very
+# hard to avoid...
+try:
+	import _FoundationSignatures
+	del _FoundationSignatures
+except ImportError:
+	pass
 
-#
-# Below here are definitions of convenience methods
-# for Objective-C classes. The C-code uses 'CONVENIENCE_METHODS' to
-# locate methods it should add to newly constructed class-wrappers.
-#
-# This is basically used to map objective-C methodnames to corresponding
-# python method names.
-#
-# TODO: Change interfaces, we sometimes want to add more than one wrapper
-# method if a method is present (like dict.keys and dict.iterkeys)
-#
+try:
+	import _FoundationMapping
+	del _FoundationMapping
+except ImportError:
+	pass
 
-def mapping_keys(self):
-	"""
-	NSDictionary.keys()
-	"""
-	enum = self.keyEnumerator()
-	result = []
-	key = enum.nextObject()
-	while key:
-		result.append(key)
-		key = enum.nextObject()
-	return result
+# 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
+b = lookup_class('NSBundle').mainBundle()
+if b:
+	import sys
+	sys.path.insert(0, '%s/Contents/Resources'%str(b.bundlePath()))
+	try:
+		del sys.path[sys.path.index('')]
+	except ValueError:
+		pass
+	del sys
+del b
 
-def mapping_values(self):
-	"""
-	NSDictionary.values()
-	"""
-	enum = self.objectEnumerator()
-	result = []
-	value = enum.nextObject()
-	while value:
-		result.append(value)
-		value = enum.nextObject()
-	return result
-
-CONVENIENCE_METHODS['description'] = ('__repr__', lambda self: self.description())
-# Mappings (e.g. like dict)
-# TODO (not all are needed or even possible): 
-#   iter*, update, pop, popitem, setdefault
-# __str__ would be nice (as obj.description()),
-CONVENIENCE_METHODS['objectForKey:'] = ('__getitem__', lambda self, arg: self.objectForKey_(arg))
-CONVENIENCE_METHODS['removeObjectForKey:'] = ('__delitem__', lambda self, arg: self.removeObjectForKey_(arg))
-CONVENIENCE_METHODS['setObject:forKey:'] = ('__setitem__', lambda self, key, value: self.setObject_forKey_(value, key))
-CONVENIENCE_METHODS['hash'] = ('__hash__', lambda self: self.hash())
-CONVENIENCE_METHODS['keyEnumerator'] = ('keys', mapping_keys)
-CONVENIENCE_METHODS['objectEnumerator'] = ('values', mapping_values)
-CONVENIENCE_METHODS['removeAllObjects'] = ('clear', lambda self: self.removeAllObjects())
-CONVENIENCE_METHODS['dictionaryWithDictionary:'] = ('copy', lambda self: self.isa.dictionaryWithDictionary_(self))
-
-CONVENIENCE_METHODS['objectAtIndex:'] = ('__getitem__', lambda self, arg: self.objectAtIndex_(arg))
-CONVENIENCE_METHODS['count'] = ('__len__', lambda self: self.count())
-CONVENIENCE_METHODS['lenght'] = ('__len__', lambda self: self.length())
-
-del mapping_keys, mapping_values
-
-
-# From 'ComparisonMethods' protocol
-CONVENIENCE_METHODS['doesContain:'] = ('__contains__', lambda self, elem: self.doesContain_(elem))
-def eq_func(self, other):
-	print "eq_func(%s, %s)"%(self, other)
-	if self is other: return 1
-	return self.isEqualTo_(other)
-
-CONVENIENCE_METHODS['isEqualTo:'] = ('__eq__', eq_func) # lambda self, other: self.isEqualTo_(other))
-CONVENIENCE_METHODS['isGreaterThan:'] = ('__gt__', lambda self, other: self.isGreaterThan(other))
-CONVENIENCE_METHODS['isGreaterThanOrEqualTo:'] = ('__ge__', None)
-CONVENIENCE_METHODS['isLessThan:'] = ('__lt__', None)
-CONVENIENCE_METHODS['isLessThanOrEqualTo:'] = ('__le__', None)
-CONVENIENCE_METHODS['isNotEqualTo:'] = ('__ne__', None)
-
-
-# Extra for strings, we'll probably provide C functions to do this
-# correctly (dealing correctly with Unicode)
-CONVENIENCE_METHODS['cString'] = (
-	'__str__', lambda self: self.cString()
-)
-

pyobjc/Lib/objc/_convenience.py

+
+from objc import set_class_extender, selector
+
+CONVENIENCE_METHODS = {}
+CLASS_METHODS = {}
+
+def add_convenience_methods(super_class, name, 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]
+			type_dict[v[0]] = v[1]
+	
+	if CLASS_METHODS.has_key(name):
+		for name, value in CLASS_METHODS[name]:
+			type_dict[name] = value
+
+set_class_extender(add_convenience_methods)
+
+# NOTE: the '!= 0' in the definition of the comparison function
+# is there to force conversion to type 'bool' on Python releases
+# that have such a type.
+def __contains__(self, elem):
+	return self.doesContain_(elem) != 0
+def __eq__1(self, other):
+	return self.isEqualTo_(other) != 0
+def __eq__2(self, other):
+	return self.isEqual_(other) != 0
+def __ne__(self, other):
+	return self.isNotEqual_(other) != 0
+def __gt__(self, other):
+	return self.isGreaterThan_(other) != 0
+def __ge__(self, other):
+	return self.isGreaterThanOrEqualTo_(other) != 0
+def __lt__(self, other):
+	return self.isLessThan_(other) != 0
+def __le__(self, other):
+	return self.isLessThanOrEqualTo_(other) != 0
+def __repr__(self):
+	return self.description()
+def __len__1(self):
+	return self.count()
+def __len__2(self):
+	return self.length()
+def __getitem__1(self, key):
+	res = self.objectForKey_(self, key)
+	if res == None:
+		raise KeyError, key
+	return res
+def __delitem__1(self, key):
+	self.removeObjectForKey_(key)
+def __setitem__1(self, key, value):
+	self.setObject_forKey_(value, key)
+def __getitem__2(self, idx):
+	res = self.objectAtIndex_(idx)
+	if res == None:
+		raise IndexError, idx
+	return res
+def __delitem__2(self, idx):
+	self.removeObjectAtIndex_(idx)
+def __setitem__2(self, idx, value):
+	self.replaceObjectAtIndex_withObject_(idx, value)
+def __hash__(self):
+	return self.hash()
+		
+
+CONVENIENCE_METHODS['objectForKey:'] = ('__getitem__', __getitem__1)
+CONVENIENCE_METHODS['removeObjectForKey:'] = ('__delitem__', __delitem__1)
+CONVENIENCE_METHODS['setObject:forKey:'] = ('__setitem__', __setitem__1)
+CONVENIENCE_METHODS['count'] = ('__len__', __len__1)
+CONVENIENCE_METHODS['description'] = ('__repr__', __repr__)
+CONVENIENCE_METHODS['doesContain:'] = ('__contains__', __contains__)
+CONVENIENCE_METHODS['hash'] = ('__hash__', __hash__)
+CONVENIENCE_METHODS['isEqualTo:'] = ('__eq__', __eq__1)
+CONVENIENCE_METHODS['isEqual:'] = ('__eq__', __eq__2)
+CONVENIENCE_METHODS['isGreaterThan:'] = ('__gt__', __gt__)
+CONVENIENCE_METHODS['isGreaterThanOrEqualTo:'] = ('__ge__', __ge__)
+CONVENIENCE_METHODS['isLessThan:'] = ('__lt__', __lt__)
+CONVENIENCE_METHODS['isLessThanOrEqualTo:'] = ('__le__', __le__)
+CONVENIENCE_METHODS['isNotEqualTo:'] = ('__ne__', __ne__)
+CONVENIENCE_METHODS['lenght'] = ('__len__', __len__2)
+CONVENIENCE_METHODS['objectAtIndex:'] = ('__getitem__', __getitem__2)
+CONVENIENCE_METHODS['removeObjectAtIndex:'] = ('__detitem__', __delitem__2)
+CONVENIENCE_METHODS['replaceObjectAtIndex:withObject:'] = ('__setitem__', __setitem__2)
+
+
+
+# Mapping protocol
+
+
+def mapping_keys(self):
+	"""
+	NSDictionary.keys()
+	"""
+	enum = self.keyEnumerator()
+	result = []
+	key = enum.nextObject()
+	while key:
+		result.append(key)
+		key = enum.nextObject()
+	return result
+
+def mapping_values(self):
+	"""
+	NSDictionary.values()
+	"""
+	enum = self.objectEnumerator()
+	result = []
+	value = enum.nextObject()
+	while value:
+		result.append(value)
+		value = enum.nextObject()
+	return result
+
+# Mappings (e.g. like dict)
+# TODO (not all are needed or even possible): 
+#   iter*, update, pop, popitem, setdefault
+# __str__ would be nice (as obj.description()),
+CONVENIENCE_METHODS['keyEnumerator'] = ('keys', mapping_keys)
+CONVENIENCE_METHODS['objectEnumerator'] = ('values', mapping_values)
+CONVENIENCE_METHODS['removeAllObjects'] = ('clear', lambda self: self.removeAllObjects())
+CONVENIENCE_METHODS['dictionaryWithDictionary:'] = ('copy', lambda self: type(self).dictionaryWithDictionary_(self))
-./.#BUGS.1.1.1.1
-./.#ChangeLog.1.4
-./.#FIXME.1.1.1.1
-./.#INSTALL.1.2
-./.#NEWS.1.4
-./.#README.1.1.1.1
-./.#setup.py.1.4
-./.cvsignore
-./.gdb_history
 ./BUGS
-./build/lib.darwin-6.1-Power Macintosh-2.2/AddressBook/__init__.py
-./build/lib.darwin-6.1-Power Macintosh-2.2/AppKit/__init__.py
-./build/lib.darwin-6.1-Power Macintosh-2.2/AppKit/_AppKit.so
-./build/lib.darwin-6.1-Power Macintosh-2.2/AppKit/_AppKitSignatures.py
-./build/lib.darwin-6.1-Power Macintosh-2.2/Foundation/__init__.py
-./build/lib.darwin-6.1-Power Macintosh-2.2/Foundation/_Foundation.so
-./build/lib.darwin-6.1-Power Macintosh-2.2/objc/__init__.py
-./build/lib.darwin-6.1-Power Macintosh-2.2/objc/_FoundationMapping.so
-./build/lib.darwin-6.1-Power Macintosh-2.2/objc/_FoundationSignatures.py
-./build/lib.darwin-6.1-Power Macintosh-2.2/objc/_objc.so
-./build/lib.darwin-6.1-Power Macintosh-2.2/objc/builder.py
-./build/lib.darwin-6.1-Power Macintosh-2.2/objc/classnib.py
-./build/temp.darwin-6.1-Power Macintosh-2.2/_AppKit.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/_Foundation.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/_FoundationMapping.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/class-builder.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/class-list.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/instance-var.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/module.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/objc-class.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/objc-object.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/objc_support.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/objc_util.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/ObjCPointer.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/OC_PythonInt.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/OC_PythonObject.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/OC_PythonString.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/pyobjc-api.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/register.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/selector.o
-./build/temp.darwin-6.1-Power Macintosh-2.2/super-call.o
 ./ChangeLog
-./CVS/Entries
-./CVS/Repository
-./CVS/Root
 ./Doc/architecture.txt
-./Doc/CVS/Entries
-./Doc/CVS/Repository
-./Doc/CVS/Root
 ./Doc/structure.txt
 ./Doc/TODO
 ./Doc/users.txt
 ./Doc/warts.txt
-./Examples/.#HelloWorld.py.1.3
-./Examples/.gdb_history
 ./Examples/00ReadMe.txt
 ./Examples/addressbook.py
-./Examples/Cocoa/CVS/Entries
-./Examples/Cocoa/CVS/Repository
-./Examples/Cocoa/CVS/Root
 ./Examples/CurrencyConverter/CurrencyConverter.py
-./Examples/CurrencyConverter/CVS/Entries
-./Examples/CurrencyConverter/CVS/Repository
-./Examples/CurrencyConverter/CVS/Root
-./Examples/CurrencyConverter/English.lproj/CVS/Entries
-./Examples/CurrencyConverter/English.lproj/CVS/Repository
-./Examples/CurrencyConverter/English.lproj/CVS/Root
 ./Examples/CurrencyConverter/English.lproj/InfoPlist.strings
 ./Examples/CurrencyConverter/English.lproj/MainMenu.nib/classes.nib
-./Examples/CurrencyConverter/English.lproj/MainMenu.nib/CVS/Entries
-./Examples/CurrencyConverter/English.lproj/MainMenu.nib/CVS/Repository
-./Examples/CurrencyConverter/English.lproj/MainMenu.nib/CVS/Root
 ./Examples/CurrencyConverter/English.lproj/MainMenu.nib/info.nib
 ./Examples/CurrencyConverter/English.lproj/MainMenu.nib/objects.nib
 ./Examples/CurrencyConverter/setup-app.py
-./Examples/CVS/Entries
-./Examples/CVS/Repository
-./Examples/CVS/Root
 ./Examples/dictionary.py
 ./Examples/HelloWorld.py
-./Examples/iClass/CVS/Entries
-./Examples/iClass/CVS/Repository
-./Examples/iClass/CVS/Root
 ./Examples/iClass/datasource.py
-./Examples/iClass/English.lproj/CVS/Entries
-./Examples/iClass/English.lproj/CVS/Repository
-./Examples/iClass/English.lproj/CVS/Root
 ./Examples/iClass/English.lproj/MainMenu.nib/classes.nib
-./Examples/iClass/English.lproj/MainMenu.nib/CVS/Entries
-./Examples/iClass/English.lproj/MainMenu.nib/CVS/Repository
-./Examples/iClass/English.lproj/MainMenu.nib/CVS/Root
 ./Examples/iClass/English.lproj/MainMenu.nib/info.nib
 ./Examples/iClass/English.lproj/MainMenu.nib/objects.nib
 ./Examples/iClass/main.py
 ./Examples/iClass/setup-app.py
 ./Examples/method-weirdness.py
 ./Examples/objc-vars.py
+./Examples/pydict-to-objcdict.py
 ./Examples/subclassing-objective-c.py
 ./Examples/super-call.py
 ./Examples/TableModel/00ReadMe.txt
-./Examples/TableModel/CVS/Entries
-./Examples/TableModel/CVS/Repository
-./Examples/TableModel/CVS/Root
-./Examples/TableModel/English.lproj/CVS/Entries
-./Examples/TableModel/English.lproj/CVS/Repository
-./Examples/TableModel/English.lproj/CVS/Root
 ./Examples/TableModel/English.lproj/MainMenu.nib/classes.nib
-./Examples/TableModel/English.lproj/MainMenu.nib/CVS/Entries
-./Examples/TableModel/English.lproj/MainMenu.nib/CVS/Repository
-./Examples/TableModel/English.lproj/MainMenu.nib/CVS/Root
 ./Examples/TableModel/English.lproj/MainMenu.nib/info.nib
 ./Examples/TableModel/English.lproj/MainMenu.nib/objects.nib
 ./Examples/TableModel/setup-app.py
 ./Examples/TableModel/TableModel.py
-./Examples/TableModel2/CVS/Entries
-./Examples/TableModel2/CVS/Repository
-./Examples/TableModel2/CVS/Root
-./Examples/TableModel2/English.lproj/CVS/Entries
-./Examples/TableModel2/English.lproj/CVS/Repository
-./Examples/TableModel2/English.lproj/CVS/Root
 ./Examples/TableModel2/English.lproj/InfoPlist.strings
 ./Examples/TableModel2/English.lproj/MainMenu.nib/classes.nib
-./Examples/TableModel2/English.lproj/MainMenu.nib/CVS/Entries
-./Examples/TableModel2/English.lproj/MainMenu.nib/CVS/Repository
-./Examples/TableModel2/English.lproj/MainMenu.nib/CVS/Root
 ./Examples/TableModel2/English.lproj/MainMenu.nib/info.nib
 ./Examples/TableModel2/English.lproj/MainMenu.nib/objects.nib
 ./Examples/TableModel2/main.m
 ./Examples/TableModel2/README.txt
 ./Examples/TableModel2/TableModel.py
-./Examples/TableModel2/TableModel2.pbproj/CVS/Entries
-./Examples/TableModel2/TableModel2.pbproj/CVS/Repository
-./Examples/TableModel2/TableModel2.pbproj/CVS/Root
 ./Examples/TableModel2/TableModel2.pbproj/project.pbxproj
 ./Examples/Todo/00ReadMe.txt
 ./Examples/Todo/buildpyapp.sh
 ./Examples/Todo/CalendarMatrix.py
-./Examples/Todo/CVS/Entries
-./Examples/Todo/CVS/Repository
-./Examples/Todo/CVS/Root
 ./Examples/Todo/English.lproj/Credits.rtf
-./Examples/Todo/English.lproj/CVS/Entries
-./Examples/Todo/English.lproj/CVS/Repository
-./Examples/Todo/English.lproj/CVS/Root
 ./Examples/Todo/English.lproj/InfoPlist.strings
 ./Examples/Todo/English.lproj/MainMenu.nib/classes.nib
-./Examples/Todo/English.lproj/MainMenu.nib/CVS/Entries
-./Examples/Todo/English.lproj/MainMenu.nib/CVS/Repository
-./Examples/Todo/English.lproj/MainMenu.nib/CVS/Root
 ./Examples/Todo/English.lproj/MainMenu.nib/info.nib
 ./Examples/Todo/English.lproj/MainMenu.nib/objects.nib
 ./Examples/Todo/English.lproj/ToDoDocument.nib/classes.nib
-./Examples/Todo/English.lproj/ToDoDocument.nib/CVS/Entries
-./Examples/Todo/English.lproj/ToDoDocument.nib/CVS/Repository
-./Examples/Todo/English.lproj/ToDoDocument.nib/CVS/Root
 ./Examples/Todo/English.lproj/ToDoDocument.nib/info.nib
 ./Examples/Todo/English.lproj/ToDoDocument.nib/objects.nib
 ./Examples/Todo/English.lproj/ToDoInfoWindow.nib/classes.nib
-./Examples/Todo/English.lproj/ToDoInfoWindow.nib/CVS/Entries
-./Examples/Todo/English.lproj/ToDoInfoWindow.nib/CVS/Repository
-./Examples/Todo/English.lproj/ToDoInfoWindow.nib/CVS/Root
 ./Examples/Todo/English.lproj/ToDoInfoWindow.nib/info.nib
 ./Examples/Todo/English.lproj/ToDoInfoWindow.nib/objects.nib
-./Examples/Todo/Icons/CVS/Entries
-./Examples/Todo/Icons/CVS/Repository
-./Examples/Todo/Icons/CVS/Root
 ./Examples/Todo/Icons/ToDoApp.icns
 ./Examples/Todo/Icons/ToDoDoc.icns
-./Examples/Todo/Images/CVS/Entries
-./Examples/Todo/Images/CVS/Repository
-./Examples/Todo/Images/CVS/Root
 ./Examples/Todo/Images/DeferredMark.tiff
 ./Examples/Todo/Images/DoneMark.tiff
 ./Examples/Todo/Images/LeftArrow.tiff
 ./Examples/Todo/ToDoItem.py
 ./Examples/using-nscoder.py
 ./Examples/using-nsscanner.py
-./Examples/WebServicesTool/CVS/Entries
-./Examples/WebServicesTool/CVS/Repository
-./Examples/WebServicesTool/CVS/Root
-./Examples/WebServicesTool/English.lproj/CVS/Entries
-./Examples/WebServicesTool/English.lproj/CVS/Repository
-./Examples/WebServicesTool/English.lproj/CVS/Root
 ./Examples/WebServicesTool/English.lproj/InfoPlist.strings
 ./Examples/WebServicesTool/English.lproj/MainMenu.nib/classes.nib
-./Examples/WebServicesTool/English.lproj/MainMenu.nib/CVS/Entries
-./Examples/WebServicesTool/English.lproj/MainMenu.nib/CVS/Repository
-./Examples/WebServicesTool/English.lproj/MainMenu.nib/CVS/Root
 ./Examples/WebServicesTool/English.lproj/MainMenu.nib/info.nib
 ./Examples/WebServicesTool/English.lproj/MainMenu.nib/keyedobjects.nib
 ./Examples/WebServicesTool/English.lproj/WSTConnection.nib/classes.nib
-./Examples/WebServicesTool/English.lproj/WSTConnection.nib/CVS/Entries
-./Examples/WebServicesTool/English.lproj/WSTConnection.nib/CVS/Repository
-./Examples/WebServicesTool/English.lproj/WSTConnection.nib/CVS/Root
 ./Examples/WebServicesTool/English.lproj/WSTConnection.nib/info.nib
 ./Examples/WebServicesTool/English.lproj/WSTConnection.nib/keyedobjects.nib
-./Examples/WebServicesTool/main.m
+./Examples/WebServicesTool/LICENSE.txt
+./Examples/WebServicesTool/main-bin-python.m
+./Examples/WebServicesTool/main-embedded-interpreter.m
 ./Examples/WebServicesTool/Main.py
 ./Examples/WebServicesTool/Preferences.png
+./Examples/WebServicesTool/README.txt
 ./Examples/WebServicesTool/Reload.png
-./Examples/WebServicesTool/Web Services Tool.pbproj/CVS/Entries
-./Examples/WebServicesTool/Web Services Tool.pbproj/CVS/Repository
-./Examples/WebServicesTool/Web Services Tool.pbproj/CVS/Root
 ./Examples/WebServicesTool/Web Services Tool.pbproj/project.pbxproj
 ./Examples/WebServicesTool/WST.icns
+./Examples/WebServicesTool/WST.png
 ./Examples/WebServicesTool/WSTApplicationDelegateClass.py
 ./Examples/WebServicesTool/WSTConnectionWindowControllerClass.py
 ./FIXME
 ./INSTALL
+./Installer Package/PyObjC.pmsp
+./Installer Package/Resources/Description.plist
+./Installer Package/Resources/License.txt
+./Installer Package/Resources/ReadMe.txt
 ./Lib/AddressBook/__init__.py
-./Lib/AddressBook/CVS/Entries
-./Lib/AddressBook/CVS/Repository
-./Lib/AddressBook/CVS/Root
 ./Lib/AppKit/__init__.py
 ./Lib/AppKit/_AppKitSignatures.py
 ./Lib/AppKit/AppKit.byref
-./Lib/AppKit/CVS/Entries
-./Lib/AppKit/CVS/Repository
-./Lib/AppKit/CVS/Root
-./Lib/CVS/Entries
-./Lib/CVS/Repository
-./Lib/CVS/Root
 ./Lib/Foundation/__init__.py
-./Lib/Foundation/CVS/Entries
-./Lib/Foundation/CVS/Repository
-./Lib/Foundation/CVS/Root
 ./Lib/Foundation/Foundation.byref
 ./Lib/objc/__init__.py
 ./Lib/objc/_FoundationSignatures.py
 ./Lib/objc/builder.py
 ./Lib/objc/classnib.py
-./Lib/objc/CVS/Entries
-./Lib/objc/CVS/Repository
-./Lib/objc/CVS/Root
+./License.txt
 ./MANIFEST
 ./Modules/Cocoa/00ReadMe.txt
 ./Modules/Cocoa/_App_Enum.inc
 ./Modules/Cocoa/_FoundationMapping.m
 ./Modules/Cocoa/AppKit.prototypes
 ./Modules/Cocoa/const-table.h
-./Modules/Cocoa/CVS/Entries
-./Modules/Cocoa/CVS/Repository
-./Modules/Cocoa/CVS/Root
 ./Modules/Cocoa/Foundation.prototypes
 ./Modules/Cocoa/func_builder.err
 ./Modules/Cocoa/func_builder.out
 ./Modules/Cocoa/scripts/cocoa_generator.py
-./Modules/Cocoa/scripts/CVS/Entries
-./Modules/Cocoa/scripts/CVS/Repository
-./Modules/Cocoa/scripts/CVS/Root
 ./Modules/Cocoa/scripts/enum_generator.py
 ./Modules/Cocoa/scripts/func_builder.py
 ./Modules/Cocoa/scripts/func_collector.py
 ./Modules/Cocoa/scripts/strconst_generator.py
 ./Modules/Cocoa/scripts/var_generator.py
-./Modules/CVS/Entries
-./Modules/CVS/Repository
-./Modules/CVS/Root
-./Modules/objc/.objc_util.m.swp
 ./Modules/objc/class-builder.h
 ./Modules/objc/class-builder.m
 ./Modules/objc/class-list.m
 ./Modules/objc/CocoaSignatures.lst
-./Modules/objc/CVS/Entries
-./Modules/objc/CVS/Repository
-./Modules/objc/CVS/Root
+./Modules/objc/informal-protocol.m
 ./Modules/objc/instance-var.h
 ./Modules/objc/instance-var.m
 ./Modules/objc/module.m
 ./Modules/objc/super-call.h
 ./Modules/objc/super-call.m
 ./NEWS
-./README
-./Scripts/CVS/Entries
-./Scripts/CVS/Repository
-./Scripts/CVS/Root
+./Project Templates/00README.txt
+./Project Templates/Cocoa-Python Application/bin-python-main.m
+./Project Templates/Cocoa-Python Application/CocoaApp.pbproj/project.pbxproj
+./Project Templates/Cocoa-Python Application/CocoaApp.pbproj/TemplateInfo.plist
+./Project Templates/Cocoa-Python Application/English.lproj/InfoPlist.strings
+./Project Templates/Cocoa-Python Application/English.lproj/MainMenu.nib/classes.nib
+./Project Templates/Cocoa-Python Application/English.lproj/MainMenu.nib/info.nib
+./Project Templates/Cocoa-Python Application/English.lproj/MainMenu.nib/keyedobjects.nib
+./Project Templates/Cocoa-Python Application/Main.py
+./Project Templates/Cocoa-Python Application/MyAppDelegate.py
+./Project Templates/install.sh
+./README-OLD.txt
+./ReadMe.txt
 ./Scripts/extract_byref_signatures.py
 ./Scripts/generate-stubs.py
 ./Scripts/README
 ./setup.py
-./Tools/CVS/Entries
-./Tools/CVS/Repository
-./Tools/CVS/Root
 ./Tools/README

pyobjc/Modules/objc/OC_PythonArray.h

+/*
+ * This file contains an implementation for a proxy class for python
+ * objects that conform to the 'sequence' protocol.
+ */
+#ifndef OC_PythonArray_h
+#define OC_PythonArray_h
+
+#import <Foundation/NSArray.h>
+#include "Python.h"
+
+@interface OC_PythonArray : NSMutableArray
+{
+	PyObject* value;
+}
++newWithPythonObject:(PyObject*)value;
+-initWithPythonObject:(PyObject*)value;
+-(PyObject*)pyObject;
+-(void)dealloc;
+
+-(int)count;
+-objectAtIndex:(int)idx;
+-(void)replaceObjectAtIndex:(int)idx withObject:newValue;
+
+@end /* OC_PythonArray class interface */
+
+#endif /* OC_PythonArray_h */

pyobjc/Modules/objc/OC_PythonArray.m

+#include "OC_PythonArray.h"
+#include "pyobjc.h"
+#include "objc_support.h"
+
+@implementation OC_PythonArray 
+
++newWithPythonObject:(PyObject*)v;
+{
+	OC_PythonArray* res = 
+		[[OC_PythonArray alloc] initWithPythonObject:v];
+	[res autorelease];
+	return res;
+}
+
+-initWithPythonObject:(PyObject*)v;
+{
+	value = v;
+	Py_INCREF(value);
+	return self;
+}
+
+-(void)dealloc
+{
+	Py_XDECREF(value);
+}
+
+-(PyObject*)pyObject
+{
+	return value;
+}
+
+
+-(int)count
+{
+	return PySequence_Length([self pyObject]);
+}
+
+-objectAtIndex:(int)idx
+{
+	PyObject* v;
+	id         result;
+	const char* err;
+
+	v = PySequence_GetItem([self pyObject], idx);
+	if (v == NULL) {
+		ObjCErr_ToObjC();
+		return nil;
+	}
+
+	err = depythonify_c_value("@", v, &result);
+	Py_DECREF(v);
+	if (err != NULL) {
+		ObjCErr_Set(PyExc_TypeError, "Cannot convert result: %s",
+			err);
+		ObjCErr_ToObjC();
+		return nil;
+	}
+
+	return result;
+}
+
+
+-(void)replaceObjectAtIndex:(int)idx withObject:newValue;
+{
+	PyObject* v;
+
+	v = pythonify_c_value("@", &newValue);
+	if (v == NULL) {
+		ObjCErr_ToObjC();
+		return;
+	}
+
+	if (PySequence_SetItem([self pyObject], idx, v) < 0) {
+		Py_DECREF(v);
+		ObjCErr_ToObjC();
+		return;
+	}
+	Py_DECREF(v);
+}
+
+@end 

pyobjc/Modules/objc/OC_PythonDictionary.h

+/*
+ * This file contains an implementation for a proxy class for python
+ * objects that conform to the 'mapping' protocol.
+ */
+#ifndef OC_PythonDictionary_h
+#define OC_PythonDictionary_h
+
+#import <Foundation/NSDictionary.h>
+#include "Python.h"
+
+@interface OC_PythonDictionary : NSMutableDictionary
+{
+	PyObject* value;
+}
++newWithPythonObject:(PyObject*)value;
+-initWithPythonObject:(PyObject*)value;
+-(PyObject*)pyObject;
+-(void)dealloc;
+
+-(int)count;
+-keyEnumerator;
+-(void)setObject:o forKey:k;
+-(void)removeObjectForKey:k;
+-objectForKey:k;
+
+@end /* OC_PythonDictionary class interface */
+
+#endif /* OC_PythonDictionary_h */

pyobjc/Modules/objc/OC_PythonDictionary.m

+#include "OC_PythonDictionary.h"
+#include "OC_PythonArray.h"
+#include "pyobjc.h"
+#include "objc_support.h"
+
+#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION == 2 && PY_MICRO_VERSION == 0
+
+/* Python 2.2.0 contains incorrect definitions for PyMapping_DelItem
+ * and PyMapping_DelItemString
+ */
+#   undef PyMapping_DelItem
+#   undef PyMapping_DelItemString
+
+#   define PyMapping_DelItem(O,K) PyDict_DelItem((O),(K))
+#   define PyMapping_DelItemString(O,K) PyDict_DelItemString((O),(K))
+
+#endif /* Python 2.2.0 */
+
+
+@implementation OC_PythonDictionary 
+
++newWithPythonObject:(PyObject*)v;
+{
+	OC_PythonArray* res = 
+		[[OC_PythonDictionary alloc] initWithPythonObject:v];
+	[res autorelease];
+	return res;
+}
+
+-initWithPythonObject:(PyObject*)v;
+{
+	value = v;
+	Py_INCREF(v);
+	return self;
+}
+
+-dealloc
+{
+	Py_XDECREF(value);
+}
+
+-(PyObject*)pyObject
+{
+	return value;
+}
+
+
+-(int)count
+{
+	return PyMapping_Length([self pyObject]);
+}
+
+-objectForKey:key
+{
+	PyObject* v;
+	PyObject* k;
+	id         result;
+	const char* err;
+
+	k = pythonify_c_value("@", &key);
+	if (k == NULL) {
+		ObjCErr_ToObjC();
+		return nil;
+	}
+
+#if 0
+	v = PyMapping_GetItem([self pyObject], k);
+#else
+	v = PyDict_GetItem([self pyObject], k);
+#endif
+
+	err = depythonify_c_value("@", v, &result);
+	Py_DECREF(v);
+	Py_DECREF(k);
+	if (err != NULL) {
+		ObjCErr_Set(PyExc_TypeError, "Cannot convert result: %s",
+			err);
+		ObjCErr_ToObjC();
+		return nil;
+	}
+	return result;
+}
+
+
+-(void)setObject:val forKey:key
+{
+	PyObject* v;
+	PyObject* k;
+
+	v = pythonify_c_value("@", &val);
+	if (v == NULL) {
+		ObjCErr_ToObjC();
+		return;
+	}
+
+	k = pythonify_c_value("@", &key);
+	if (k == NULL) {
+		Py_DECREF(v);
+		ObjCErr_ToObjC();
+		return;
+	}
+
+	if (PyDict_SetItem([self pyObject], k, v) < 0) {
+		Py_DECREF(v);
+		Py_DECREF(k);
+		ObjCErr_ToObjC();
+		return;
+	}
+	Py_DECREF(v);
+	Py_DECREF(k);
+}
+
+-(void)removeObjectForKey:key
+{
+	PyObject* k;
+
+	k = pythonify_c_value("@", &key);
+	if (k == NULL) {
+		ObjCErr_ToObjC();
+		return;
+	}
+
+	if (PyMapping_DelItem([self pyObject], k) < 0) {
+		Py_DECREF(k);
+		ObjCErr_ToObjC();
+		return;
+	}
+	Py_DECREF(k);
+}
+
+-keyEnumerator
+{
+	PyObject* keys = PyMapping_Keys([self pyObject]);
+	id result = [OC_PythonArray newWithPythonObject:keys];
+	Py_DECREF(keys);
+	[result retain];
+
+	return [result objectEnumerator];
+}
+
+@end 

pyobjc/Modules/objc/OC_PythonObject.h

 /*#M Return the wrapped Python object. */
 - (PyObject *) pyObject;
 
+
 /*#M Print the PythonObject on file @var{fp}.  Returns -1 on
   error.  The @var{flags} argument is used to enable certain printing
   options. The only option currently supported is @code{Py_Print_RAW}. */

pyobjc/Modules/objc/OC_PythonObject.m

 	return PyObject_DelItem([self pyObject], [key pyObject]);
 }
 
-
 @end /* OC_PythonObject class implementation */

pyobjc/Modules/objc/module.m

 	return Py_None;
 }
 
+static PyObject*
+objc_set_class_extender(PyObject* self, PyObject* args, PyObject* kwds)
+{
+static 	char* keywords[] = { "callback", NULL };
+	PyObject* callback;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:set_class_extender",
+			keywords, &callback)) {
+		return NULL;
+	}
+
+	if (!PyCallable_Check(callback)) {
+		PyErr_SetString(PyExc_TypeError, "Expecting callable");
+		return NULL;
+	}
+	
+	Py_XDECREF(ObjC_class_extender);
+	ObjC_class_extender = callback;
+	Py_INCREF(ObjC_class_extender);
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
 
 
 static PyObject* 
 static PyMethodDef meta_methods[] = {
 	{ "lookup_class", (PyCFunction)objc_lookup_class, METH_VARARGS|METH_KEYWORDS, objc_lookup_class_doc },
 	{ "class_list", (PyCFunction)objc_class_list, METH_NOARGS, ""},
+	{ "set_class_extender", (PyCFunction)objc_set_class_extender, METH_VARARGS|METH_KEYWORDS, ""},
 	{ "set_signature_for_selector", (PyCFunction)objc_set_signature_for_selector, METH_VARARGS|METH_KEYWORDS, "" },
 	{ "recycle_autorelease_pool", (PyCFunction)objc_recycle_autorelease_pool, METH_VARARGS|METH_KEYWORDS, objc_recycle_autorelease_pool_doc },
 	{ 0, 0, 0, 0 } /* sentinel */
 	PyDict_SetItemString(d, "ivar", (PyObject*)&ObjCIvar_Type);
 	PyDict_SetItemString(d, "informal_protocol", (PyObject*)&ObjCInformalProtocol_Type);
 
-	convenience_dict = PyDict_New();
-	if (convenience_dict == NULL) return;
-
-	Py_INCREF(convenience_dict);
-	PyDict_SetItemString(d, "CONVENIENCE_METHODS", convenience_dict);
-
 	allocator_dict = PyDict_New();
 	if (allocator_dict == NULL) return;
 
 	}
 
 	PyDict_SetItemString(d, "__version__", 
-		PyString_FromString(PYOBJC_VERSION));
+		PyString_FromString(OBJC_VERSION));
 
 }

pyobjc/Modules/objc/objc-class.m

 	struct class_info* info;
 	int                magic;
 
-	/* Try to get rid of MaybeRescan... */
 	info = get_class_info(self);
 	if (info->method_magic != (magic = objc_methodlist_magic(info->class))){
 		int r;
 		r = ObjC_AddConvenienceMethods(info->class, 
 			((PyTypeObject*)self)->tp_dict);
 		if (r < 0) {
+			PyErr_Print();
 			PyErr_SetString(PyExc_RuntimeError,
 				"Cannot rescan method table");
 			return NULL;

pyobjc/Modules/objc/objc_support.m

           }
         else 
           {
-            if ([obj conformsToProtocol:@protocol (PythonObject)])
-              {
-                retobject = [(OC_PythonObject *) obj pyObject];
-                Py_INCREF(retobject);
-              }
-
+            if ([obj isKindOfClass:[OC_PythonArray class]]) 
+	      {
+	        retobject = [(OC_PythonArray *)obj pyObject];
+		Py_INCREF(retobject);
+	      }
+            else if ([obj isKindOfClass:[OC_PythonDictionary class]]) 
+	      {
+	        retobject = [(OC_PythonDictionary *)obj pyObject];
+		Py_INCREF(retobject);
+	      }
             else if ([obj isKindOfClass:[NSString class]]) 
 	      {
 	        /* All string classes seem to be subclasses of NSString.
 				[data bytes], [data length]);
 		}
 	      }
+	    else if ([obj conformsToProtocol:@protocol (PythonObject)])
+              {
+                retobject = [(OC_PythonObject *) obj pyObject];
+                Py_INCREF(retobject);
+              }
 
 	    else if (ObjC_HasPythonImplementation(obj)) 
 		{
 	}
       else if (PyInt_Check (argument))
 	*(id *) datum = [NSNumber numberWithLong:PyInt_AS_LONG (argument)];
+      else if (PySequence_Check(argument))  
+	*(id *) datum = [OC_PythonArray newWithPythonObject:argument];
+      else if (PyMapping_Check(argument))  
+	*(id *) datum = [OC_PythonDictionary newWithPythonObject:argument];
       else
         *(id *) datum = [OC_PythonObject newWithObject:argument];
       break;

pyobjc/Modules/objc/objc_util.h

 
 int ObjCUtil_Init(PyObject* module);
 
-extern PyObject* convenience_dict;
+extern PyObject* ObjC_class_extender;
 int ObjC_AddConvenienceMethods(Class cls, PyObject* type_dict);
 
 void ObjCErr_Set(PyObject* exc, char* fmt, ...);

pyobjc/Modules/objc/objc_util.m

 	[val raise];
 }
 
-PyObject* convenience_dict = NULL;
+PyObject* ObjC_class_extender = NULL;
 
 int ObjC_AddConvenienceMethods(Class cls, PyObject* type_dict)
 {
-	PyObject* values = NULL;
-	int       i, len;
+	PyObject* super_class;
+	PyObject* name;
+	PyObject* res;
+	PyObject* args;
 
-	values = PyDict_Values(type_dict);
-	if (values == NULL) return -1;
+	if (ObjC_class_extender == NULL || cls == nil) return 0;
 
-	len = PySequence_Length(values);
-	for (i = 0; i < len; i++) {
-		PyObject* value;
-		PyObject* mapping;
-
-		value = PySequence_GetItem(values, i);
-		if (value == NULL) {
-			Py_DECREF(values);
+	if (cls->super_class == nil) {
+		super_class = Py_None;
+		Py_INCREF(super_class);
+	} else {
+		super_class = ObjCClass_New(cls->super_class);
+		if (super_class == NULL) {
 			return -1;
 		}
-
-		if (!ObjCSelector_Check(value)) {
-			Py_DECREF(value);
-			continue;
-		}
-
-		mapping = PyDict_GetItemString(convenience_dict, 
-			(char*)SELNAME(((ObjCSelector*)value)->sel_selector));
-		if (mapping == NULL) {
-			PyErr_Clear();
-			Py_DECREF(value);
-			continue;
-		}
-		Py_DECREF(value);
-
-		if (PyString_Check(mapping)) {
-			/* Default mapping */
-			int r;
-			r = PyDict_SetItem(type_dict, mapping, value);
-			if (r < 0) return -1;
-
-			Py_INCREF(mapping);
-		} else if (!PySequence_Check(mapping) || PySequence_Length(mapping) != 2) {
-			PyErr_SetString(PyExc_RuntimeError,
-				"objc.CONVENIENCE_METHODS must contain 2-tuples");
-		} else {
-			/* (name, imp) */
-			PyObject* name;
-			PyObject* imp;
-			int r;
-
-			name = PySequence_GetItem(mapping, 0);
-			imp = PySequence_GetItem(mapping, 1);
-
-			if (name == NULL || imp == NULL) return -1;
-
-			if (imp == Py_None) {
-				/* Default mapping */
-				r = PyDict_SetItem(type_dict, name, value);
-
-				if (r < 0) return -1;
-				Py_DECREF(imp);
-			} else {
-				r = PyDict_SetItem(type_dict, name, imp);
-
-				if (r < 0) return -1;
-
-				Py_DECREF(imp);
-			}
-		}
 	}
 
-	Py_DECREF(values);
+	name = PyString_FromString(cls->name);
+	if (name == NULL) {
+		Py_DECREF(super_class);
+		return -1;
+	}
+
+	args = PyTuple_New(3);
+	if (args == NULL) {
+		Py_DECREF(super_class);
+		Py_DECREF(name);
+		return -1;
+	}
+
+	PyTuple_SET_ITEM(args, 0, super_class);
+	PyTuple_SET_ITEM(args, 1, name);
+	PyTuple_SET_ITEM(args, 2, type_dict);
+	Py_INCREF(type_dict);
+
+	res = PyObject_CallObject(ObjC_class_extender, args);
+	if (res == NULL) {
+		Py_DECREF(args);
+		return -1;
+	}
+	Py_DECREF(args);
+	Py_DECREF(super_class);
+
 	return 0;
 }
 

pyobjc/Modules/objc/pyobjc.h

 #include <Python.h>
 #include <objc/objc-runtime.h>
 #include "OC_PythonObject.h"
+#include "OC_PythonArray.h"
+#include "OC_PythonDictionary.h"
 #include "super-call.h"
 
-#define PYOBJC_VERSION "0.7.1"
+#define OBJC_VERSION "0.7.1"
 
 #ifdef MACOSX
 
 	"Modules/objc/OC_PythonInt.m",
 	"Modules/objc/OC_PythonObject.m",
 	"Modules/objc/OC_PythonString.m",
+	"Modules/objc/OC_PythonArray.m",
+	"Modules/objc/OC_PythonDictionary.m",
 	"Modules/objc/register.m",
 	"Modules/objc/pyobjc-api.m",
 	"Modules/objc/module.m",
 AddressBookPackages, AddressBookExtensions = \
 	IfFrameWork('AddressBook.framework', [ 'AddressBook' ], [])
 
+
+def package_version():
+	fp = open('Modules/objc/pyobjc.h', 'r')
+	for ln in fp.readlines():
+		if ln.startswith('#define OBJC_VERSION'):
+			fp.close()
+			return ln.split()[-1][1:-1]
+	
+	raise ValueError, "Version not found"
+
+
 try:
+
     setup (name = "pyobjc",
-           version = "0.7.0",
+           version = package_version(),
            description = "Python<->ObjC Interoperability Module",
-           author = "bbum, SteveM, many others stretching back through the reachtes of time...",
+           author = "bbum, RonaldO, SteveM, many others stretching back through the reachtes of time...",
            author_email = "pyobjc-dev@lists.sourceforge.net",
 	   url = "http://pyobjc.sourceforge.net/",
            ext_modules = (