Commits

Ronald Oussoren committed 13a953a

- Add some documentation on how to do releases (thanks to Jack for the idea)
- Make sure the NEWS update will be mostly correct around the time we want
to do the next release
- Add meta-data defintions to setup.py, helps with PyPI registrations. This
needs some more work.
- Add support for (semi-)automatic conversions between Objective-C objects
and CoreFoundation objects (wrapped by Carbon.CF types). This probably
requires MacPython 2.3. I don't like the fact that PyObjC now contains a list
of the CoreFoundation types that are currently wrapped by MacPython, but this
will do for now.

Comments (0)

Files changed (9)

Doc/release-process.txt

+==========================
+The PyObjC release process
+==========================
+
+.. :author: Ronald Oussoren
+
+This document gives an exhaustive overview of what needs to be done when 
+building and releasing a new version of PyObjC. It is meant for the project
+administrators, and not of much use for users of PyObjC.
+
+The timeframe is a guideline only and should be taken with a grain of salt.
+
+Release date -2 weeks
+---------------------
+
+Full feature freeze, documenation updates and critical bugfixes only. At this
+time:
+
+* Check if the NEWS file is up-to-date
+
+* Tests the tutorial(s)
+  Read the tutorial(s) and follow the instructions exactly, the tutorials should
+  be completely bugfree.
+
+* Update the announcement messages.
+
+Release-date -3 days
+---------------------
+
+Build the release tarball and dmg:
+
+* Run Scripts/make_distrib.py
+
+* Create an empty disk image (named ``PyObjC X.Y``) and copy the installer
+  package, License and ReadMe to this disk image. Resize the icons in this
+  folder to largish icons (about 64 pixels) and resize the view to be just
+  large enough to contain the icons.
+
+  NOTE: This should be scripted, and maybe we should add a nice background
+  image to the folder.
+
+Trash you existing PyObjC installation and reinstall from the new release. Test
+that the new release is working correctly. Installing and testing should be done
+both for the binary installer and for the source archive. The latter should be
+done in all supported configurations.
+
+If the package works as expected upload to a convenient location and ask some
+other people (like the other maintainers) to test the new release.
+
+Release-date
+------------
+
+* Upload the release files to sourceforge
+
+* add a news item to the website and update the download page
+
+* announce the new version at ADC news: 
+	http://developer.apple.com/devnews/submit.html
+
+  - Organization: PyObjC Team
+  
+  - Name of Produt... : PyObjC
+
+  - URL: http://pyobjc.sourceforge.net
+
+  - Describe your product... :
+    
+    PyObjC is a bridge between Python and Objective-C and allows development
+    of full-fledged Cocoa programs in pure Python.
+
+
+* update the information at a number of software databases:
+
+  - versiontrack.com (billb knows how)
+
+  - macupdate.com
+
+  - PyPI database at python.org
+
+* send the announcement text to:
+
+  - python-list@python.org
+
+  - python-announce-list@python.org
+  
+  - macosx-dev@omnigroup.com
+
+  - pyobjc-dev@sourceforge.net
+
+  - pythonmac-sig@python.org
+
+  - cocoa-dev@lists.apple.com
+

Lib/Foundation/test/test_nsnumber.py

 import unittest
 import objc
+import re
 
 from Foundation import *
 
+def stripDocType(val):
+    return re.sub('<!DOCTYPE [^>]*>', '<!DOCTYPE>', val)
+  
+
 if 0:
     # NSNumber is proxied into python
 
             data = fd.read()
             fd.close()
 
-            self.assertEquals(data, PLIST)
+            self.assertEquals(stripDocType(data), stripDocType(PLIST))
 
         def testPropertyList1(self):
             d = NSMutableDictionary.dictionary()

Lib/Foundation/test/test_osxcasts.py

+import unittest
+
+from objc import *
+from Foundation import *
+
+try:
+    # These tests are only usefull on MacOS X when using MacPython
+    from Carbon.CF import *
+
+
+    class TestTollFreeBridging( unittest.TestCase ):
+        def testExplicitToCF(self):
+            o = NSMutableArray.arrayWithArray_(("a", 1, 1.9))
+            self.assert_(isinstance(o, NSMutableArray))
+
+            c = ObjectToCF(o)
+            self.assert_(isinstance(c, CFMutableArrayRef))
+
+        def testExplictFromCF(self):
+            c = CFArrayCreateMutable(0)
+            self.assert_(isinstance(c, CFMutableArrayRef))
+
+            o = CFToObject(c)
+            self.assert_(isinstance(o, NSMutableArray))
+
+        def testImplicitFromCF(self):
+            c = CFArrayCreateMutable(0)
+            self.assert_(isinstance(c, CFMutableArrayRef))
+
+            nsa = NSMutableArray.array()
+            nsa.addObject_(c)
+
+            o = nsa[0]
+            self.assert_(isinstance(o, NSMutableArray))
+
+except ImportError:
+    pass
+
+if __name__ == '__main__':
+    unittest.main( )
+

Modules/objc/module.m

 static PyObject*
 classAddMethods(PyObject* self, PyObject* args, PyObject* keywds)
 {
-  static 	char* kwlist[] = { "targetClass", "methodsArray", NULL };
-  PyObject* classObject = NULL;
-  PyObject* methodsArray = NULL;
-  Class targetClass;
-  int methodCount;
-  int methodIndex;
-  struct objc_method_list *methodsToAdd;
+	static 	char* kwlist[] = { "targetClass", "methodsArray", NULL };
+	PyObject* classObject = NULL;
+	PyObject* methodsArray = NULL;
+	Class targetClass;
+	int methodCount;
+	int methodIndex;
+	struct objc_method_list *methodsToAdd;
 
-  if (!PyArg_ParseTupleAndKeywords(args, keywds, "OO:classAddMethods", kwlist,
-				   &classObject, &methodsArray)) {
-    return NULL;
-  }
+	if (!PyArg_ParseTupleAndKeywords(args, keywds, 
+			"OO:classAddMethods", kwlist,
+			&classObject, &methodsArray)) {
+		return NULL;
+	}
 
-  targetClass  = PyObjCClass_GetClass(classObject);
-  methodCount  = PyList_Size(methodsArray);
+	targetClass  = PyObjCClass_GetClass(classObject);
+	methodCount  = PyList_Size(methodsArray);
 
-  if (methodCount == 0) {
-    Py_INCREF(Py_None);
-    return Py_None;
-  }
-  
-  methodsToAdd = objc_allocMethodList(methodCount);
-  if (methodsToAdd == NULL) {
-    PyErr_NoMemory();
-    return NULL;
-  }
+	if (methodCount == 0) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
 
-  methodsToAdd->method_count = methodCount;
-  
-  for (methodIndex = 0; methodIndex < methodCount; methodIndex++) {
-    PyObject* aMethod = PyList_GetItem(methodsArray, methodIndex);
-    struct objc_method *objcMethod;
+	methodsToAdd = objc_allocMethodList(methodCount);
+	if (methodsToAdd == NULL) {
+		PyErr_NoMemory();
+		return NULL;
+	}
 
-    // check
-    if (!ObjCSelector_Check(aMethod)) {
-      PyErr_SetString(PyExc_TypeError ,
-		      "All objects in methodArray must be of type <objc.selector>.");
-      goto cleanup_and_return_error;
-    }
+	methodsToAdd->method_count = methodCount;
 
-    // install in methods to add
-    objcMethod = &methodsToAdd->method_list[methodIndex];
-    objcMethod->method_name = ObjCSelector_Selector(aMethod);
+	for (methodIndex = 0; methodIndex < methodCount; methodIndex++) {
+		PyObject* aMethod = PyList_GetItem(methodsArray, methodIndex);
+		struct objc_method *objcMethod;
 
-    objcMethod->method_types = strdup(ObjCSelector_Signature(aMethod));
-    objcMethod->method_imp = ObjC_MakeIMPForObjCSelector((ObjCSelector*)aMethod);
-  }
+		/* check
+		 * FIXME: We should support functions here, just like with
+		 * class definitions.
+		 */
+		if (!ObjCSelector_Check(aMethod)) {
+			PyErr_SetString(PyExc_TypeError ,
+			      "All objects in methodArray must be of type "
+			      "<objc.selector>.");
+			goto cleanup_and_return_error;
+		}
 
-  // add the methods
-  class_addMethods(targetClass, methodsToAdd);
-  
-  Py_INCREF(Py_None);
-  return Py_None;
+		/* install in methods to add */
+		objcMethod = &methodsToAdd->method_list[methodIndex];
+		objcMethod->method_name = ObjCSelector_Selector(aMethod);
 
- cleanup_and_return_error:
-  if (methodsToAdd)
-    free(methodsToAdd);
-  return NULL;
+		objcMethod->method_types = strdup(ObjCSelector_Signature(
+			aMethod));
+		objcMethod->method_imp = ObjC_MakeIMPForObjCSelector(
+			(ObjCSelector*)aMethod);
+	}
+
+	/* add the methods */
+	class_addMethods(targetClass, methodsToAdd);
+
+	Py_INCREF(Py_None);
+	return Py_None;
+
+cleanup_and_return_error:
+	if (methodsToAdd)
+	free(methodsToAdd);
+	return NULL;
 }
 #endif
 
 	return result;
 }
 
+#ifdef MACOSX
+
+PyDoc_STRVAR(objc_CFToObject_doc,
+	"CFToObject(cfObject) -> objCObject\n"
+	"\n"
+	"Convert a CoreFoundation object to an Objective-C object. \n"
+	"Raises an exception if the conversion fails"
+);
+static PyObject*
+objc_CFToObject(PyObject* self, PyObject* args, PyObject* kwds)
+{
+	PyObject* result;
+	PyObject* argument;
+	id	  res;
+
+	if (!PyArg_ParseTuple(args, 
+			"O:CFToObject",
+			&argument)) {
+		return NULL;
+	}
+
+	res = PyObjC_CFTypeToID(argument);
+	if (res == 0) {
+		PyErr_SetString(PyExc_TypeError, "not a CoreFoundation object");
+		return NULL;
+	}
+
+	return pythonify_c_value("@", &res);
+}
+
+PyDoc_STRVAR(objc_ObjectToCF_doc,
+	"ObjectToCF(objCObject) -> cfObject\n"
+	"\n"
+	"Convert an Objective-C object to a CoreFoundation object. \n"
+	"Raises an exception if the conversion fails"
+);
+static PyObject*
+objc_ObjectToCF(PyObject* self, PyObject* args, PyObject* kwds)
+{
+	PyObject* result;
+	PyObject* argument;
+	id	  obj;
+
+	if (!PyArg_ParseTuple(args, 
+			"O:ObjectToCF",
+			&argument)) {
+		return NULL;
+	}
+
+	if (!PyObjCObject_Check(argument)) {
+		PyErr_SetString(PyExc_TypeError, "not an Objective-C object");
+		return NULL;
+	}
+
+	return PyObjC_IDToCFType(PyObjCObject_GetObject(argument));
+}
+
+
+#endif /* MACOSX */
+
+	
+
+
 
 static PyMethodDef meta_methods[] = {
 	{
 	{ "getVerbose", (PyCFunction)getVerbose, METH_VARARGS|METH_KEYWORDS, getVerbose_doc },
 	{ "loadBundle", (PyCFunction)loadBundle, METH_VARARGS|METH_KEYWORDS, loadBundle_doc },
 	{ "allocateBuffer", (PyCFunction)allocateBuffer, METH_VARARGS|METH_KEYWORDS, allocateBuffer_doc },
+
+#ifdef MACOSX
+	{ "CFToObject", (PyCFunction)objc_CFToObject, METH_VARARGS, objc_CFToObject_doc },
+	{ "ObjectToCF", (PyCFunction)objc_ObjectToCF, METH_VARARGS, objc_ObjectToCF_doc },
+#endif
+
 	{ 0, 0, 0, 0 } /* sentinel */
 };
 

Modules/objc/objc_support.m

 
 #ifdef MACOSX
 #include <CoreFoundation/CFNumber.h>
-#endif
-
+#endif /* MACOSX */
 
 /*
  * Category on NSObject to make sure that every object supports 
 			*(id *) datum = [OC_PythonDictionary 
 				newWithPythonObject:argument];
 		} else {
+#ifdef MACOSX
+			*(id*) datum = PyObjC_CFTypeToID(argument);
+			if (*(id*)datum != NULL) {
+				return 0;
+			}
+#endif /* MACOSX */
+
 			*(id *) datum = [OC_PythonObject 
 				newWithObject:argument];
 		}

Modules/objc/pyobjc.h

 PyObject* PyObjCUnicode_New(NSString* value);
 NSString* PyObjCUnicode_Extract(PyObject* value);
 
+
+#ifdef MACOSX
+
+/* toll-free-bridging.m */
+id PyObjC_CFTypeToID(PyObject* argument);
+PyObject* PyObjC_IDToCFType(id argument);
+
+#endif
+
 #endif /* META_H */

Modules/objc/toll-free-bridging.m

+/*
+ *  This file defines support for "toll-free briging" between Python wrappers
+ *  for CoreFoundation objecs and native Objective-C objects.
+ *
+ *  NOTE: It would be nice if we could move some of this logic into MacPython,
+ *  keeping the lists of CF-wrappers synchronized is not a very pleasant 
+ *  thought.
+ */
+#include "pyobjc.h"
+#include "objc_support.h"
+#include <unistd.h>
+#include "objc/objc.h"
+
+#ifdef MACOSX
+#import <Foundation/NSURL.h>
+
+#include "pymactoolbox.h"
+
+id PyObjC_CFTypeToID(PyObject* argument)
+{
+	/* Tollfree bridging of CF (some) objects 
+	 * This list of conversion functions is the complete list of such
+	 * functions in Python 2.3b1
+	 */
+	int r;
+	id  val;
+
+	r = CFTypeRefObj_Convert(argument, (CFTypeRef*)&val);
+	if (r) return val;
+
+	r = CFStringRefObj_Convert(argument, (CFStringRef*)&val);
+	if (r) return val;
+
+	r = CFMutableStringRefObj_Convert(argument, (CFMutableStringRef*)&val);
+	if (r) return val;
+
+	r = CFArrayRefObj_Convert(argument, (CFArrayRef*)&val);
+	if (r) return val;
+
+	r = CFMutableArrayRefObj_Convert(argument, (CFMutableArrayRef*)&val);
+	if (r) return val;
+		
+	r = CFDictionaryRefObj_Convert(argument, (CFDictionaryRef*)&val);
+	if (r) return val;
+
+	r = CFMutableDictionaryRefObj_Convert(argument, 
+		(CFMutableDictionaryRef*)&val);
+	if (r) return val;
+
+	r = CFURLRefObj_Convert(argument, (CFURLRef*)&val);
+	if (r) return val;
+
+	PyErr_Clear();
+	return NULL;
+}
+
+PyObject* PyObjC_IDToCFType(id argument)
+{
+	if ([argument isKindOfClass:[NSMutableString class]]) {
+		return CFMutableStringRefObj_New((CFMutableStringRef)argument);
+	}
+
+	if ([argument isKindOfClass:[NSString class]]) {
+		return CFStringRefObj_New((CFStringRef)argument);
+	}
+	
+	if ([argument isKindOfClass:[NSMutableArray class]]) {
+		return CFMutableArrayRefObj_New((CFMutableArrayRef)argument);
+	}
+
+	if ([argument isKindOfClass:[NSArray class]]) {
+		return CFArrayRefObj_New((CFArrayRef)argument);
+	}
+
+	if ([argument isKindOfClass:[NSDictionary class]]) {
+		return CFDictionaryRefObj_New((CFDictionaryRef)argument);
+	}
+
+	if ([argument isKindOfClass:[NSMutableDictionary class]]) {
+		return CFMutableDictionaryRefObj_New(
+				(CFMutableDictionaryRef)argument);
+	}
+
+	if ([argument isKindOfClass:[NSURL class]]) {
+		return CFURLRefObj_New((CFURLRef)argument);
+	}
+
+	/* Apple doesn't say as much, but as NSArray and CFArray are toll-free
+	 * bridged NSObject must also be toll-free bridged to a CoreFoundation
+	 * type.  As is is not document which type this is, we use the most
+	 * generic one.
+	 */
+	return CFTypeRefObj_New((CFTypeRef)argument);
+}
+
+
+#else
+
+static const char dummy; /* Make sure this is valid C on GNUstep */
+
+#endif /* MACOSX */
+
+
+
   It is now possible to build PyObjC on MacOS X 10.1, with full access to 
   the Cocoa API's on that platform.
 
-- TODO: All suppport for non-FFI builds has been removed.
+- All suppport for non-FFI builds has been removed.
+ [ TODO, I'm getting the port to OSX 10.1 stable first. Then:
+   - Remove all code guarded by '#ifndef OC_WITH_LIBFFI'
+   - Remove all code guared by  '#ifndef OC_USE_FFI_SHORTCUTS'
+   - Remove register.m
+   - Rename 'callsuper' methods in AppKit/Foundation/... to 'call' methods,
+     remove existing 'call' methods. 
+   - ObjC_FindSuperCaller -> ObjC_FindCaller and remove ObjC_FindSelfCaller
+   - ObjC_RegisterMethodMapping looses first argument
+   - Remove support code in setup.py
+   ...
+ ] 
 
+- Support for "toll-free bridging" of Carbon.CF types to Objective-C objects.
+  It is now possible to use instances of Carbon.CF types in places where 
+  Objective-C objects are expected.
+  [Partially done, need to add 'CFToObject' and 'ObjectToCF' functions to the
+   objc module]
+
+  Note: this requires Python 2.3.
 
 Version 0.9 (May-02-2003):
 - This version includes numerous bugfixes and improvements.
 import sys
 import os
 
+# Some PiPy stuff
+LONG_DESCRIPTION="""
+PyObjC is a bridge between Python and Objective-C.  It allows full
+featured Cocoa applications to be written in pure Python.  It is also
+easy to use other frameworks containing Objective-C class libraries
+from Python and to mix in Objective-C, C and C++ source.
+
+Python is a highly dynamic programming language with a shallow learning
+curve.  It combines remarkable power with very clear syntax.
+
+The installer package installs a number of Project Builder templates for
+easily creating new Cocoa-Python projects, as well as support for syntax
+coloring of Python files in Project Builder.
+
+PyObjC also supports full introspection of Objective-C classes and
+direct invocation of Objective-C APIs from the interactive interpreter.
+
+PyObjC requires MacOS X 10.2 or later.  PyObjC works both with the Apple
+provided Python installation in MacOS X 10.2 (and later) and with
+MacPython 2.3.  Users of MacPython 2.3 can install PyObjC though the
+PackageManager application.
+"""
+
+if sys.version >= '2.2.3':
+    # This doesn't work. (The documenation says the test should be 
+    # sys.version < 2.2.3, but that doesn't look correct to me)
+    from distutils.dist import DistributionMetadata
+    DistributionMetadata.classifiers = [ 
+        'Development Status :: 5 - Production/Stable',
+        'Environment :: Console',
+        'Environment :: MacOS X :: Cocoa',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: MIT License',
+        'Natural Language :: English',
+        'Operating System :: MacOS :: MacOS X',
+        'Programming Language :: Python',
+        'Programming Language :: Objective C',
+        'Topic :: Software Development :: Libraries :: Python Modules',
+        'Topic :: Software Development :: User Interfaces',
+    ]
+    DistributionMetadata.download_url = 'http://pyobjc.sourceforge.net/software/index.php'
+
 if sys.platform == 'darwin': 
     # Apple has used build options that don't work with a 'normal' system.
     # Remove '-arch i386' from the LDFLAGS.
         "Modules/objc/register.m",
         "Modules/objc/pyobjc-api.m",
         "Modules/objc/alloc_hack.m",
+        "Modules/objc/toll-free-bridging.m",
         "Modules/objc/module.m",
 ]
 
 dist = setup(name = "pyobjc",
 	     version = package_version(),
 	     description = "Python<->ObjC Interoperability Module",
+             long_description = LONG_DESCRIPTION,
 	     author = "bbum, RonaldO, SteveM, LeleG, many others stretching back through the reaches of time...",
 	     author_email = "pyobjc-dev@lists.sourceforge.net",
 	     url = "http://pyobjc.sourceforge.net/",
+             platforms = [ 'MacOS X' ],
 	     ext_modules = (
 			     CoreExtensions 
 			   + CocoaExtensions