support new style classes - allowing a python xpcom class to inherit
authorTodd Whiteman <toddw@activestate.com>
Sun, 10 Oct 2010 13:55:55 -0700
changeset 39 b6fce9508c70dd478ea5dfa329c32a60546957a3
parent 38 61ea3c46b078a8157f9a9a6c829d29385cc38668
child 40 02169131860948fbe1408d5f3f2d67edbf3eac1b
push id20
push usertoddw@activestate.com
push dateSun, 10 Oct 2010 21:45:08 +0000
support new style classes - allowing a python xpcom class to inherit from "object"
xpcom/server/loader.py
xpcom/src/PyGBase.cpp
xpcom/src/PyIID.cpp
xpcom/src/PyISupports.cpp
--- a/xpcom/server/loader.py
+++ b/xpcom/server/loader.py
@@ -67,21 +67,26 @@ def FindCOMComponents(py_module):
             return comps
         else:
             sys.stderr.write("PYXPCOM_CLASSES should be a list, "
                              "not %s. File: %s" % (type(pyxpcom_classes),
                                                    py_module.__file__))
 
     # Else, run over all top-level objects looking for likely candidates.
     for name, obj in py_module.__dict__.items():
-        if type(obj)==types.ClassType and \
-           _has_good_attr(obj, "_com_interfaces_") and \
-           _has_good_attr(obj, "_reg_clsid_") and \
-           _has_good_attr(obj, "_reg_contractid_"):
-            comps.append(obj)
+        try:
+            # Examine class types or new style classes that inherit from object.
+            if (type(obj) == types.ClassType or issubclass(obj, object)) and \
+               _has_good_attr(obj, "_com_interfaces_") and \
+               _has_good_attr(obj, "_reg_clsid_") and \
+               _has_good_attr(obj, "_reg_contractid_"):
+                comps.append(obj)
+        except TypeError:
+            # The issubclass call raises TypeError when the obj is not a class.
+            pass
     return comps
 
 def register_self(klass, compMgr, location, registryLocation, componentType):
     pcl = ModuleLoader
     from xpcom import _xpcom
     svc = _xpcom.GetServiceManager().getServiceByContractID("@mozilla.org/categorymanager;1", components.interfaces.nsICategoryManager)
     # The category 'module-loader' is special - the component manager uses it
     # to create the nsIModuleLoader for a given component type.
--- a/xpcom/src/PyGBase.cpp
+++ b/xpcom/src/PyGBase.cpp
@@ -197,17 +197,18 @@ void *PyG_Base::ThisAsIID( const nsIID &
 }
 
 // Call back into Python, passing a Python instance, and get back
 // an interface object that wraps the instance.
 /*static*/ PRBool 
 PyG_Base::AutoWrapPythonInstance(PyObject *ob, const nsIID &iid, nsISupports **ppret)
 {
 	NS_PRECONDITION(ppret!=NULL, "null pointer when wrapping a Python instance!");
-	NS_PRECONDITION(ob && PyInstance_Check(ob), "AutoWrapPythonInstance is expecting an non-NULL instance!");
+	NS_PRECONDITION(ob && PyObject_HasAttrString(ob, "__class__"),
+			"AutoWrapPythonInstance is expecting a non-NULL instance!");
 	PRBool ok = PR_FALSE;
 	if (PR_LOG_TEST(nsPyxpcomLog, PR_LOG_DEBUG)) {
 		PyObject *r = PyObject_Repr(ob);
 		if (r!=NULL) {
 			char idstr[NSID_LENGTH];
 			iid.ToProvidedString(idstr);
 			LOG(PR_LOG_DEBUG, ("PyG_Base::AutoWrapPythonInstance: ob: '%s' to iid: %s", PyString_AsString(r), idstr));
 			Py_DECREF(r);
--- a/xpcom/src/PyIID.cpp
+++ b/xpcom/src/PyIID.cpp
@@ -105,17 +105,17 @@ Py_nsIID::IIDFromPyObject(PyObject *ob, 
 	if (PyString_Check(ob)) {
 		ok = iid.Parse(PyString_AsString(ob));
 		if (!ok) {
 			PyErr_SetString(PyExc_ValueError, "The string is formatted as a valid nsID");
 			return PR_FALSE;
 		}
 	} else if (ob->ob_type == &type) {
 		iid = ((Py_nsIID *)ob)->m_iid;
-	} else if (PyInstance_Check(ob)) {
+	} else if (PyObject_HasAttrString(ob, "__class__")) {
 		// Get the _iidobj_ attribute
 		PyObject *use_ob = PyObject_GetAttrString(ob, "_iidobj_");
 		if (use_ob==NULL) {
 			PyErr_SetString(PyExc_TypeError, "Only instances with _iidobj_ attributes can be used as IID objects");
 			return PR_FALSE;
 		}
 		if (use_ob->ob_type != &type) {
 			Py_DECREF(use_ob);
--- a/xpcom/src/PyISupports.cpp
+++ b/xpcom/src/PyISupports.cpp
@@ -241,17 +241,17 @@ Py_nsISupports::InterfaceFromPyObject(Py
 			PyErr_SetString(PyExc_TypeError, "None is not a invalid interface object in this context");
 			return PR_FALSE;
 		}
 	}
 
 	// support nsIVariant
 	if (iid.Equals(NS_GET_IID(nsIVariant)) || iid.Equals(NS_GET_IID(nsIWritableVariant))) {
 		// Check it is not already nsIVariant
-		if (PyInstance_Check(ob)) {
+		if (PyObject_HasAttrString(ob, "__class__")) {
 			PyObject *sub_ob = PyObject_GetAttrString(ob, "_comobj_");
 			if (sub_ob==NULL) {
 				PyErr_Clear();
 			} else {
 				if (InterfaceFromPyISupports(sub_ob, iid, ppv)) {
 					Py_DECREF(sub_ob);
 					return PR_TRUE;
 				}
@@ -264,17 +264,17 @@ Py_nsISupports::InterfaceFromPyObject(Py
 			PyXPCOM_BuildPyException(nr);
 			return PR_FALSE;
 		}
 		NS_ASSERTION(ppv != nsnull, "PyObject_AsVariant worked but gave null!");
 		return PR_TRUE;
 	}
 	// end of variant support.
 
-	if (PyInstance_Check(ob)) {
+	if (PyObject_HasAttrString(ob, "__class__")) {
 		// Get the _comobj_ attribute
 		PyObject *use_ob = PyObject_GetAttrString(ob, "_comobj_");
 		if (use_ob==NULL) {
 			PyErr_Clear();
 			if (bTryAutoWrap)
 				// Try and auto-wrap it - errors will leave Py exception set,
 				return PyXPCOM_XPTStub::AutoWrapPythonInstance(ob, iid, ppv);
 			PyErr_SetString(PyExc_TypeError, "The Python instance can not be converted to an XPCOM object");