Ronald Oussoren avatar Ronald Oussoren committed 050d6d2

Getting there. This is basicly it, unless last minute
testing reveals show-stopper bugs this will be PyObjC 2.3
when I'm back home.

I will have to update all pyobjc-framework-* packages
though, that will happen after running tests (and that
takes a while for the core packages because I run them
with a number of python versions and builds)

Comments (0)

Files changed (11)

pyobjc-core/Lib/objc/_bridgesupport.py

 from objc import function, registerMetaDataForSelector
 
 
-# Import ElementTree from one of the various locations where
-# it might be found
-try:
-        # Python 2.5
-        import xml.etree.cElementTree as ET
-except ImportError:
-        # And earlier (with separate install)
-        try:
-            import cElementTree as ET
-        
-        except ImportError:
-            import elementtree.ElementTree as ET
-
-
 # Are we in a 64-bit build:
 is64Bit = (sys.maxint > 2147483647)
 # Are we in a little-endian build:
         path = os.path.join(dn, fn)
         if os.path.exists(path):
             data = open(path, 'rb').read()
-            doc = ET.fromstring(data)
 
             dylib_path = os.path.join(dn, frameworkName + '.dylib')
             if os.path.exists(dylib_path):

pyobjc-core/Modules/objc/module.m

 
 
 
-
-
+static PyObject*
+_clear_intern(PyObject* self __attribute__((__unused__)))
+{
+	PyObjC_ClearIntern();
+	Py_INCREF(Py_None);
+	return Py_None;
+}
 
 
 static PyMethodDef mod_methods[] = {
 	{ "_typestr2typestr", (PyCFunction)typestr2typestr, 
 		METH_O, "private function" },
 
+	{ "_clear_intern", (PyCFunction)_clear_intern, METH_NOARGS,  NULL },
+
 
 	{ 0, 0, 0, 0 } /* sentinel */
 };

pyobjc-core/Modules/objc/parsexml.m

 	s = attribute_string(node, "c_array_of_fixed_length", NULL);
 	if (s && *s) {
 		char* end;
-		v = PyInt_FromString(s, &end, 10);
+		v = PyObjC_IntFromString(s, &end, 10);
 		if (v == NULL) {
 			xmlFree(s);
 			Py_DECREF(result);
 			}
 
 			if (isMethod) {
-				v = PyInt_FromLong(input + 2);
+				v = PyObjC_IntFromLong(input + 2);
 			} else {
-				v = PyInt_FromLong(input);
+				v = PyObjC_IntFromLong(input);
 			}
 			if (v == NULL) {
 				Py_DECREF(result);
 			PyDict_SetItemString(a, "type", av);
 			Py_DECREF(av);
 
-			av = PyInt_FromLong(idx++);
+			av = PyObjC_IntFromLong(idx++);
 			if (av == NULL) {
 				Py_DECREF(a);
 				Py_DECREF(av);
 				continue;
 			}
 			if (strcmp((char*)al->name, "arg") == 0) {
-				PyObject* d = xmlToArgMeta(al, NO, NULL);
+				PyObject* d = PyObjC_InternValue(xmlToArgMeta(al, NO, NULL));
 				if (d == NULL) {
 					Py_DECREF(result);
 					return NULL;
 				}
-				v = PyInt_FromLong(idx++);
+				v = PyObjC_IntFromLong(idx++);
 				if (v == NULL) {
 					Py_DECREF(d);
 					Py_DECREF(v);
 					return NULL;
 				}
 			} else if (strcmp((char*)al->name, "retval") == 0) {
-				PyObject* d = xmlToArgMeta(al, NO, NULL);
+				PyObject* d = PyObjC_InternValue(xmlToArgMeta(al, NO, NULL));
 				if (d == NULL) {
 					Py_DECREF(result);
 					return NULL;
 				}
+
 				r = PyDict_SetItemString(meta, "retval", d);
 				Py_DECREF(d);
 				if (r == -1) {
 				return -1;
 			}
 
+			v = PyObjC_InternValue(v);
+			if (v == NULL) {
+				if (name) xmlFree(name);
+				if (type) xmlFree(type);
+				return -1;
+			}
+
 			int r = PyDict_SetItemString(globalDict, name, v);
 			if (r == -1) {
 				if (name) xmlFree(name);
 
 		if (strchr(value, '.') != NULL) {
 			/* floating point literal */
-			PyObject* s = PyText_InternFromString(value);
+			PyObject* s = PyText_FromString(value);
 			if (s == NULL) {
 				v = NULL;
 
 			}
 		} else {
 			/* integer literal */
-			v = PyInt_FromString(value, &end, 10);
+			v = PyObjC_IntFromString(value, &end, 10);
 		}
 
 		if (v == NULL) {
 		} else {
 			CFTypeID typeid = getfunc();
 
-			v = PyInt_FromLong(typeid);
+			v = PyObjC_IntFromLong(typeid);
 			if (v == NULL) {
 				goto end;
 			}
 			if (c_length != NULL) {
 				long cnt = strtol(c_length, NULL, 10);
 
-				v = PyInt_FromLong(cnt);
+				v = PyObjC_IntFromLong(cnt);
 				if (v == NULL) {
 					Py_DECREF(metadata);
 					Py_XDECREF(pyClassname);
 
 			if (strcmp((char*)al->name, "arg") == 0) {
 				int argIdx;
-				PyObject* d = xmlToArgMeta(al, YES, &argIdx);
+				PyObject* d = PyObjC_InternValue(xmlToArgMeta(al, YES, &argIdx));
 				if (d == NULL) {
 					Py_DECREF(metadata);
 					Py_XDECREF(pyClassname);
 					return -1;
 				}
 				
-				PyObject* idx = PyInt_FromLong(argIdx+2);
+				PyObject* idx = PyObjC_IntFromLong(argIdx+2);
 				if (idx == NULL) {
 					Py_DECREF(d);
 					Py_DECREF(metadata);
 				}
 
 			} else if (strcmp((char*)al->name, "retval") == 0) {
-				PyObject* d = xmlToArgMeta(al, YES, NULL);
+				PyObject* d = PyObjC_InternValue(xmlToArgMeta(al, YES, NULL));
 				if (d == NULL) {
 					Py_DECREF(metadata);
 					Py_XDECREF(pyClassname);
 			return -1;
 		}
 
+		metadata = PyObjC_InternValue(metadata);
+		if (metadata == NULL) {
+			Py_DECREF(pyClassname);
+			Py_DECREF(pySelector);
+			return -1;
+		}
+
 
 		r = PyObjC_registerMetaData(pyClassname, pySelector, metadata);
 		Py_DECREF(pySelector);
 		char* ch = attribute_string(cur_node, "c_array_length_in_arg", NULL);
 		if (ch) {
 			long count = strtol(ch, NULL, 10);
-			v = PyInt_FromLong(count);
+			v = PyObjC_IntFromLong(count);
 			if (v == NULL) {
 				xmlFree(name);
 				Py_DECREF(metadata);
 		}
 
 		if (strcmp((char*)al->name, "arg") == 0) {
-			PyObject* d = xmlToArgMeta(al, NO, NULL);
+			PyObject* d = PyObjC_InternValue(xmlToArgMeta(al, NO, NULL));
 			if (d == NULL) {
 				goto error;
 			}
 				goto error;
 			}
 
-			PyObject* argIdx = PyInt_FromLong(PyList_Size(siglist)-2);
+			PyObject* argIdx = PyObjC_IntFromLong(PyList_Size(siglist)-2);
 			if (argIdx == NULL) {
 				Py_DECREF(d);
 				goto error;
 
 		} else if (strcmp((char*)al->name, "retval") == 0) {
 
-			PyObject* d = xmlToArgMeta(al, NO, NULL);
+			PyObject* d = PyObjC_InternValue(xmlToArgMeta(al, NO, NULL));
 			if (d == NULL) {
 				goto error;
 			}
 
 
 	/* We have the complete metadata, now build the proxy object for it */
-	PyObject* signature = PyObject_CallMethod(empty_bytes, "join", "O", siglist);
+	PyObject* signature = PyObjC_InternValue(PyObject_CallMethod(empty_bytes, "join", "O", siglist));
 	if (signature == NULL) {
 		goto error;
 	}
 	if (nm == NULL) {
 		goto error;
 	}
+
+	metadata = PyObjC_InternValue(metadata);
+	if (metadata == NULL) {
+		Py_DECREF(nm);
+		Py_DECREF(metadata);
+		Py_DECREF(arguments);
+		Py_DECREF(siglist);
+	}
+
 	v = PyObjCFunc_New(nm, function, PyBytes_AsString(signature), Py_None, metadata);
 
 	Py_DECREF(nm);

pyobjc-core/Modules/objc/pyobjc-compat.h

 extern PyObject* PyBytes_InternFromStringAndSize(const char* v, Py_ssize_t l);
 #endif
 
+extern void      PyObjC_ClearIntern(void);
+extern PyObject* PyObjC_InternValue(PyObject* orig);
+extern PyObject* PyObjC_IntFromString(char* v, char**pend, int base);
+extern PyObject* PyObjC_IntFromLong(long v);
 
 #endif /* PyObjC_COMPAT_H */

pyobjc-core/Modules/objc/pyobjc-compat.m

 
 
 #endif /* Py3K */
+
+/* 
+ * Helper function for making sure that we don't store duplicate data
+ * for the metadata bridges.
+ *
+ * Interface: call on value, don't update value afterwards. Steals
+ * reference to argument and returns a new reference.
+ */
+static	PyObject* intern_mapping = NULL;
+
+void	  PyObjC_ClearIntern(void)
+{
+	Py_CLEAR(intern_mapping);
+}
+
+PyObject* PyObjC_InternValue(PyObject* orig)
+{
+
+	PyObject* v;
+	PyObject* key;
+	
+	if (orig == NULL) {
+		return NULL;
+	}
+
+	if (intern_mapping == NULL) {
+		intern_mapping = PyDict_New();
+		if (intern_mapping == NULL) {
+			Py_DECREF(orig);
+			return NULL;
+		}
+	}
+
+	if (PyList_Check(orig)) {
+		key = PyList_AsTuple(orig);
+		if (key == NULL) {
+			Py_DECREF(orig);
+			return NULL;
+		}
+	} else if (PyDict_Check(orig)) {
+		/* This is not ideal, but should help reduce the amount of noise */
+		key = PyObject_Repr(orig);
+		if (key == NULL) {
+			Py_DECREF(orig);
+			return NULL;
+		}
+
+	} else {
+		key = orig;
+		Py_INCREF(key);
+	}
+
+	v = PyDict_GetItem(intern_mapping, key);
+	if (v == NULL) {
+		int r = PyDict_SetItem(intern_mapping, key, orig);
+		Py_DECREF(key);
+		if (r == -1) {
+			Py_DECREF(orig);
+			return NULL;
+		}
+		v = orig;
+	} else {
+		Py_DECREF(key);
+		Py_INCREF(v);
+		Py_DECREF(orig);
+	}
+	return v;
+}
+
+PyObject* PyObjC_IntFromString(char* v, char**pend, int base)
+{
+	PyObject* r = PyInt_FromString(v, pend, base);
+	if (r == NULL) {
+		return NULL;
+	}
+	return PyObjC_InternValue(r);
+}
+
+
+PyObject* PyObjC_IntFromLong(long v)
+{
+	PyObject* r = PyInt_FromLong(v);
+	if (r == NULL) {
+		return NULL;
+	}
+	return PyObjC_InternValue(r);
+}

pyobjc-core/Modules/objc/pyobjc.h

  * Central include file for PyObjC. 
  */
 
-#define OBJC_VERSION "2.3b1"
+#define OBJC_VERSION "2.3"
 
 // Loading in AppKit on Mac OS X 10.3 results in
 // a bit less than 1500 classes.

pyobjc-core/NEWS.txt

 
 An overview of the relevant changes in new, and older, releases.
 
-Version 2.3b1
--------------
+Version 2.3
+-----------
+
+- Add some experimental code that slightly reduces the amount of
+  memory used when loading bridgesupport files.
+
+  Futher work is needed to investigate what causes the memory
+  usage to increase as much as it does, sadly enough Instruments
+  doesn't play nice with ``--with-pymalloc`` and for some reason
+  'import Foundation' crashes with ``--without-pymalloc``.
 
 - "<struct>" definitions in the bridgesupport files can now have
   an alias attribute containing the name of Python type that should

pyobjc-core/PyObjCTest/test_archive_python.py

         # format such tests are irrelevant to archiving support)
 
         @onlyIf(0, "python unittest not relevant for archiving")
+        def test_load_classic_instance(self): pass
+
+        @onlyIf(0, "python unittest not relevant for archiving")
         def test_insecure_strings(self): pass
 
         @onlyIf(0, "python unittest not relevant for archiving")

pyobjc-core/PyObjCTest/test_ctests.py

     """
     result = { 'meth': getattr(ctests, name) }
 
-    if sys.platform == 'darwin' and name == 'CheckNSInvoke' and platform.machine() == 'Power Macintosh':
+    if sys.platform == 'darwin' and name == 'CheckNSInvoke' and platform.machine() == 'Power Macintosh' and map(int, platform.mac_ver()[0].split('.')) < [10, 6]:
         # There is a bug in Apple's implementation of NSInvocation
         # surpress the test failure until Apple fixes the class.
         # Don't change the C-code, the same function is used to disable

pyobjc-core/Tools/pyobjc_setup.py

             sys.path.remove(dirname)
 
         # Actually run the tests
+        if sys.version_info[0] == 2:
+            sys.path.insert(0, rootdir)
+    
+        print ("XXXXX" + str(sys.path))
+        print ("XXXXX" + str(rootdir))
         import PyObjCTest
         import unittest
         from pkg_resources import EntryPoint

pyobjc-core/setup.py

 ## on i386 systems when a method returns a struct that isn't returned
 ## in registers. 
 if '-O0' in get_config_var('CFLAGS'):
-    print "Change -O0 to -O1"
+    print ("Change -O0 to -O1")
     CFLAGS.append('-O1')
 
 OBJC_LDFLAGS = frameworks('CoreFoundation', 'Foundation', 'Carbon')
 Natural Language :: English
 Operating System :: MacOS :: MacOS X
 Programming Language :: Python
+Programming Language :: Python :: 2
+Programming Language :: Python :: 2.6
+Programming Language :: Python :: 2.7
 Programming Language :: Python :: 3
+Programming Language :: Python :: 3.1
+Programming Language :: Python :: 3.2
 Programming Language :: Objective C
 Topic :: Software Development :: Libraries :: Python Modules
 Topic :: Software Development :: User Interfaces
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.