[PyObjC-svn] r2605 - in trunk/pyobjc/pyobjc-core: . Lib/PyObjCTools Modules/objc PyObjCTest

[email protected] Tue, 28 Dec 2010 06:06:33 -0600
Newsgroups gmane.comp.python.pyobjc.cvs
Message-ID <[email protected]>
Author: ronaldoussoren
Date: Tue Dec 28 06:06:33 2010
New Revision: 2605

Log:
Add support for 3 Objective-C runtime functions that were introduced in
10.6: objc.setAssociatedObject (wraps objc_setAssociatedObject),
objc.getAssociatedObject and objc.removeAssociatedObjects.

Documentations will follow later, need to restructure the enture docset
anyway.


Added:
   trunk/pyobjc/pyobjc-core/PyObjCTest/test_assocations.py   (contents, props changed)
Modified:
   trunk/pyobjc/pyobjc-core/Lib/PyObjCTools/TestSupport.py
   trunk/pyobjc/pyobjc-core/Modules/objc/module.m
   trunk/pyobjc/pyobjc-core/NEWS.txt
   trunk/pyobjc/pyobjc-core/setup.py

Modified: trunk/pyobjc/pyobjc-core/Lib/PyObjCTools/TestSupport.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/Lib/PyObjCTools/TestSupport.py	(original)
+++ trunk/pyobjc/pyobjc-core/Lib/PyObjCTools/TestSupport.py	Tue Dec 28 06:06:33 2010
@@ -736,3 +736,13 @@
 
         return test
 
+class filterWarnings (object):
+    def __init__(self, kind, category):
+        self._kind = kind
+        self._category = category
+
+    def __enter__(self):
+        warnings.filterwarnings(self._kind, category=self._category)
+
+    def __exit__(self, type, value, tp):
+        del warnings.filters[0]

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/module.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/module.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/module.m	Tue Dec 28 06:06:33 2010
@@ -1671,6 +1671,133 @@
 }
 
 
+#if    PyObjC_BUILD_RELEASE >= 1006
+    /* Associated Object support. Functionality is available on OSX 10.6 or later. */
+
+PyDoc_STRVAR(PyObjC_setAssociatedObject_doc,
+	"setAssociatedObject(object, key, value, [policy=objc.OBJC_ASSOCIATION_RETAIN])\n"
+	"\n"
+	"Set the value for an object assiociation. Use 'None' as the\n"
+	"value to clear an association.");
+static PyObject*
+PyObjC_setAssociatedObject(PyObject* self __attribute__((__unused__)),
+	PyObject* args, PyObject* kwds)
+{
+static char* keywords[] = { "object", "key", "value", "policy", NULL };
+	id object;
+	PyObject* key;
+	id value;
+	long	  policy = OBJC_ASSOCIATION_RETAIN;
+
+	if (objc_setAssociatedObject == NULL) {
+		PyErr_SetString(PyObjCExc_Error, "setAssociatedObject not available on this platform");
+		return NULL;
+	}
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&OO&|i",
+		keywords, 
+		PyObjCObject_Convert, &object,
+		&key,
+		PyObjCObject_Convert, &value,
+		&policy
+		)) {
+		
+		return NULL;
+	}
+
+	PyObjC_DURING
+		objc_setAssociatedObject(object, (void*)key, value, policy);
+	PyObjC_HANDLER
+		PyObjCErr_FromObjC(localException);
+	PyObjC_ENDHANDLER
+
+	if (PyErr_Occurred()) return NULL;
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+
+PyDoc_STRVAR(PyObjC_getAssociatedObject_doc,
+	"getAssociatedObject(object, key) -> value\n"
+	"\n"
+	"Get the value for an object assiociation. Returns None \n"
+	"when they association doesn't exist.");
+static PyObject*
+PyObjC_getAssociatedObject(PyObject* self __attribute__((__unused__)),
+	PyObject* args, PyObject* kwds)
+{
+static char* keywords[] = { "object", "key", NULL};
+	id object;
+	PyObject* key;
+	id value;
+
+	if (objc_getAssociatedObject == NULL) {
+		PyErr_SetString(PyObjCExc_Error, "setAssociatedObject not available on this platform");
+		return NULL;
+	}
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O",
+		keywords, 
+		PyObjCObject_Convert, &object,
+		&key
+		)) {
+		
+		return NULL;
+	}
+
+	PyObjC_DURING
+		value = objc_getAssociatedObject(object, (void*)key);
+	PyObjC_HANDLER
+		value = nil;
+		PyObjCErr_FromObjC(localException);
+	PyObjC_ENDHANDLER
+
+	if (PyErr_Occurred()) return NULL;
+
+	return PyObjC_IdToPython(value);
+}
+
+PyDoc_STRVAR(PyObjC_removeAssociatedObjects_doc,
+	"removeAssociatedObjects(object)\n"
+	"\n"
+	"Remove all assocations from an object. This should in general not be used because\n"
+	"it clear all references, including those made from unrelated code.\n");
+
+static PyObject*
+PyObjC_removeAssociatedObjects(PyObject* self __attribute__((__unused__)),
+	PyObject* args, PyObject* kwds)
+{
+static char* keywords[] = { "object", NULL};
+	id object;
+
+	if (objc_removeAssociatedObjects == NULL) {
+		PyErr_SetString(PyObjCExc_Error, "setAssociatedObject not available on this platform");
+		return NULL;
+	}
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&",
+		keywords, 
+		PyObjCObject_Convert, &object
+		)) {
+		
+		return NULL;
+	}
+
+	PyObjC_DURING
+		objc_removeAssociatedObjects(object);
+	PyObjC_HANDLER
+		PyObjCErr_FromObjC(localException);
+	PyObjC_ENDHANDLER
+
+	if (PyErr_Occurred()) return NULL;
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+#endif
+
+
 static PyMethodDef mod_methods[] = {
 	{
 		"_setClassSetUpHook",
@@ -1786,6 +1913,16 @@
 
 	{ "_clear_intern", (PyCFunction)_clear_intern, METH_NOARGS,  NULL },
 
+#if    PyObjC_BUILD_RELEASE >= 1006
+
+	{ "setAssociatedObject", (PyCFunction)PyObjC_setAssociatedObject,
+		METH_VARARGS|METH_KEYWORDS, PyObjC_setAssociatedObject_doc },
+	{ "getAssociatedObject", (PyCFunction)PyObjC_getAssociatedObject,
+		METH_VARARGS|METH_KEYWORDS, PyObjC_getAssociatedObject_doc },
+	{ "removeAssociatedObjects", (PyCFunction)PyObjC_removeAssociatedObjects,
+		METH_VARARGS|METH_KEYWORDS, PyObjC_removeAssociatedObjects_doc },
+
+#endif /* PyObjC_BUILD_RELEASE >= 1006 */
 
 	{ 0, 0, 0, 0 } /* sentinel */
 };
@@ -2068,6 +2205,42 @@
 	PyObjCPointerWrapper_Init();
 	PyObjC_InstallAllocHack();
 
+#if    PyObjC_BUILD_RELEASE >= 1006
+	if (objc_setAssociatedObject != NULL) {
+		if (PyModule_AddIntConstant(m, "OBJC_ASSOCIATION_ASSIGN", OBJC_ASSOCIATION_ASSIGN) < 0) {
+			PyObjC_INITERROR();
+		}
+		if (PyModule_AddIntConstant(m, "OBJC_ASSOCIATION_RETAIN_NONATOMIC", OBJC_ASSOCIATION_RETAIN_NONATOMIC) < 0) {
+			PyObjC_INITERROR();
+		}
+		if (PyModule_AddIntConstant(m, "OBJC_ASSOCIATION_COPY_NONATOMIC", OBJC_ASSOCIATION_COPY_NONATOMIC) < 0) {
+			PyObjC_INITERROR();
+		}
+		if (PyModule_AddIntConstant(m, "OBJC_ASSOCIATION_RETAIN", OBJC_ASSOCIATION_RETAIN) < 0) {
+			PyObjC_INITERROR();
+		}
+		if (PyModule_AddIntConstant(m, "OBJC_ASSOCIATION_COPY", OBJC_ASSOCIATION_COPY) < 0) {
+			PyObjC_INITERROR();
+		}
+	} else {
+		/* Build on a system where object associations are available, running on a platform where they aren't.
+		 * Disable the wrappers.
+		 */
+		if (PyDict_DelItemString(d, "setAssociatedObject") < 0) {
+			PyErr_Clear();
+		}
+		if (PyDict_DelItemString(d, "getAssociatedObject") < 0) {
+			PyErr_Clear();
+		}
+		if (PyDict_DelItemString(d, "removeAssociatedObjects") < 0) {
+			PyErr_Clear();
+		}
+
+	}
+#endif /* PyObjC_BUILD_RELEASE >= 1006 */
+
+
+
 #ifdef MAC_OS_X_VERSION_MAX_ALLOWED
 	/* An easy way to check for the MacOS X version we did build for */
 	if (PyModule_AddIntConstant(m, "MAC_OS_X_VERSION_MAX_ALLOWED", MAC_OS_X_VERSION_MAX_ALLOWED) < 0) {

Modified: trunk/pyobjc/pyobjc-core/NEWS.txt
==============================================================================
--- trunk/pyobjc/pyobjc-core/NEWS.txt	(original)
+++ trunk/pyobjc/pyobjc-core/NEWS.txt	Tue Dec 28 06:06:33 2010
@@ -13,6 +13,15 @@
 - ``objc.FSRef.from_pathname`` actually works instead of always raising
    a TypeError.
 
+- ``objc.getAssociatedObject``, ``objc.setAssociatedObject`` and
+  ``objc.removeAssociatedObjects`` are wrappers for the corresponding
+  functions in the Objective-C runtime API.  These functions are only
+  available when PyObjC was build on a system running OSX 10.6 or later,
+  and the script is also running on such as system.
+
+  The ``policy`` argument for ``objc.setAssociatedObject`` is optional and
+  defaults to ``objc.OBJC_ASSOCIATION_RETAIN``.
+
 Version 2.3
 -----------
 

Modified: trunk/pyobjc/pyobjc-core/setup.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/setup.py	(original)
+++ trunk/pyobjc/pyobjc-core/setup.py	Tue Dec 28 06:06:33 2010
@@ -5,6 +5,7 @@
 import shutil
 import re
 import os
+import plistlib
 
 # We need at least Python 2.5
 MIN_PYTHON = (2, 5)
@@ -41,9 +42,19 @@
     use_2to3 = True,
 )
 
+def get_os_level():
+    pl = plistlib.readPlist('/System/Library/CoreServices/SystemVersion.plist')
+    v = pl['ProductVersion']
+    return '.'.join(v.split('.')[:2])
+
+
+
+
+
 from setuptools.command import build_py
 from setuptools.command import test
 from distutils import log
+
 class oc_build_py (build_py.build_py):
     def run_2to3(self, files, doctests=True):
         files = [ fn for fn in files if not os.path.basename(fn).startswith('test3_') ]
@@ -295,6 +306,7 @@
     "-Wno-long-long",
 
     "-Wno-import",
+    "-DPyObjC_BUILD_RELEASE=%02d%02d"%(tuple(map(int, get_os_level().split('.')))),
     ])
 
 ## Arghh, a stupid compiler flag can cause problems. Don't 

------------------------------------------------------------------------------
Learn how Oracle Real Application Clusters (RAC) One Node allows customers
to consolidate database storage, standardize their database environment, and, 
should the need arise, upgrade to a full multi-node Oracle RAC database 
without downtime or disruption
http://p.sf.net/sfu/oracle-sfdevnl