Donovan Preston's patch #538395, with some mods by me.

This patch makes inheritance for OSA classes work. The implementation is a
bit convoluted, but I don't immedeately see a simpler way of doing it.

I added calls to ascii() everywhere we output strings that may contain
non-ascii characters (Python has gotten very picky since the encoding
patch:-).

I also removed Donovan's different way of opening resource files: I don't
seem to need it.
diff --git a/Mac/Lib/aepack.py b/Mac/Lib/aepack.py
index f58dd33..dfb2953 100644
--- a/Mac/Lib/aepack.py
+++ b/Mac/Lib/aepack.py
@@ -24,6 +24,7 @@
 import StringIO
 import aetypes
 from aetypes import mkenum, mktype
+import os
 
 # These ones seem to be missing from AppleEvents
 # (they're in AERegistry.h)
@@ -61,6 +62,15 @@
 FSSType = macfs.FSSpecType
 AliasType = macfs.AliasType
 
+def packkey(ae, key, value):
+	if hasattr(key, 'which'):
+		keystr = key.which
+	elif hasattr(key, 'want'):
+		keystr = key.want
+	else:
+		keystr = key
+	ae.AEPutParamDesc(keystr, pack(value))
+
 def pack(x, forcetype = None):
 	"""Pack a python object into an AE descriptor"""
 	
@@ -99,13 +109,18 @@
 	if t == DictionaryType:
 		record = AE.AECreateList('', 1)
 		for key, value in x.items():
-			record.AEPutParamDesc(key, pack(value))
+			packkey(record, key, value)
+			#record.AEPutParamDesc(key, pack(value))
 		return record
 	if t == InstanceType and hasattr(x, '__aepack__'):
 		return x.__aepack__()
+	if hasattr(x, 'which'):
+		return AE.AECreateDesc('TEXT', x.which)
+	if hasattr(x, 'want'):
+		return AE.AECreateDesc('TEXT', x.want)
 	return AE.AECreateDesc('TEXT', repr(x)) # Copout
 
-def unpack(desc):
+def unpack(desc, formodulename=""):
 	"""Unpack an AE descriptor to a python object"""
 	t = desc.type
 	
@@ -117,17 +132,17 @@
 		l = []
 		for i in range(desc.AECountItems()):
 			keyword, item = desc.AEGetNthDesc(i+1, '****')
-			l.append(unpack(item))
+			l.append(unpack(item, formodulename))
 		return l
 	if t == typeAERecord:
 		d = {}
 		for i in range(desc.AECountItems()):
 			keyword, item = desc.AEGetNthDesc(i+1, '****')
-			d[keyword] = unpack(item)
+			d[keyword] = unpack(item, formodulename)
 		return d
 	if t == typeAEText:
 		record = desc.AECoerceDesc('reco')
-		return mkaetext(unpack(record))
+		return mkaetext(unpack(record, formodulename))
 	if t == typeAlias:
 		return macfs.RawAlias(desc.data)
 	# typeAppleEvent returned as unknown
@@ -153,7 +168,7 @@
 		return macfs.RawFSSpec(desc.data)
 	if t == typeInsertionLoc:
 		record = desc.AECoerceDesc('reco')
-		return mkinsertionloc(unpack(record))
+		return mkinsertionloc(unpack(record, formodulename))
 	# typeInteger equal to typeLongInteger
 	if t == typeIntlText:
 		script, language = struct.unpack('hh', desc.data[:4])
@@ -177,7 +192,11 @@
 		return v
 	if t == typeObjectSpecifier:
 		record = desc.AECoerceDesc('reco')
-		return mkobject(unpack(record))
+		# If we have been told the name of the module we are unpacking aedescs for,
+		# we can attempt to create the right type of python object from that module.
+		if formodulename:
+			return mkobjectfrommodule(unpack(record, formodulename), formodulename)
+		return mkobject(unpack(record, formodulename))
 	# typePict returned as unknown
 	# typePixelMap coerced to typeAERecord
 	# typePixelMapMinus returned as unknown
@@ -214,13 +233,13 @@
 	#
 	if t == 'rang':
 		record = desc.AECoerceDesc('reco')
-		return mkrange(unpack(record))
+		return mkrange(unpack(record, formodulename))
 	if t == 'cmpd':
 		record = desc.AECoerceDesc('reco')
-		return mkcomparison(unpack(record))
+		return mkcomparison(unpack(record, formodulename))
 	if t == 'logi':
 		record = desc.AECoerceDesc('reco')
-		return mklogical(unpack(record))
+		return mklogical(unpack(record, formodulename))
 	return mkunknown(desc.type, desc.data)
 	
 def coerce(data, egdata):
@@ -311,6 +330,20 @@
 		return aetypes.Property(seld.type, fr)
 	return aetypes.ObjectSpecifier(want, form, seld, fr)
 
+# Note by Jack: I'm not 100% sure of the following code. This was
+# provided by Donovan Preston, but I wonder whether the assignment
+# to __class__ is safe. Moreover, shouldn't there be a better
+# initializer for the classes in the suites?
+def mkobjectfrommodule(dict, modulename):
+	want = dict['want'].type
+	module = __import__(modulename)
+	codenamemapper = module._classdeclarations
+	classtype = codenamemapper.get(want, None)
+	newobj = mkobject(dict)
+	if classtype:
+		newobj.__class__ = classtype
+	return newobj
+
 def _test():
 	"""Test program. Pack and unpack various things"""
 	objs = [