Commits

Ronald Oussoren  committed 3bbd424

CoreWLAN tests pass again

This also fixes a problem in pyobjc-core: it didn't properly
handle exceptions while updating a class's convenience methods
(caught be testing with a debug build of python 3.4 that contains
assertions against python exception at unexpected places)

  • Participants
  • Parent commits c9cbfc6
  • Branches core-cleanup

Comments (0)

Files changed (9)

File pyobjc-core/Lib/PyObjCTools/TestSupport.py

     """
     return onlyIf(os_release() <= release)
 
+def os_level_between(min_release, max_release):
+    """
+    Usage::
+
+        class Tests (unittest.TestCase):
+
+            @os_level_between('10.5', '10.8')
+            def testUntilLeopard(self):
+                pass
+    """
+    return onlyIf(min_release <= os_release() <= max_release)
+
 _poolclass = objc.lookUpClass('NSAutoreleasePool')
 
 # NOTE: On at least OSX 10.8 there are multiple proxy classes for CFTypeRef...

File pyobjc-core/Modules/objc/module.m

     py_cls = objc_class_locate(cls);
     if (py_cls == NULL) goto done;
 
-    PyObjCClass_CheckMethodList(py_cls, NO);
+    if (PyObjCClass_CheckMethodList(py_cls, NO) < 0) {
+        return NULL;
+    }
 
 done:
     Py_INCREF(Py_None);

File pyobjc-core/Modules/objc/objc-class.h

 extern PyObject* PyObjCClass_FindSelector(PyObject* cls, SEL selector, BOOL class_method);
 extern void PyObjCClass_MaybeRescan(PyObject* class);
 extern int ObjC_RegisterClassProxy(Class cls, PyObject* classProxy);
-extern void PyObjCClass_CheckMethodList(PyObject* cls, int recursive);
+extern int PyObjCClass_CheckMethodList(PyObject* cls, int recursive);
 extern Py_ssize_t PyObjCClass_DictOffset(PyObject* cls);
 extern PyObject* PyObjCClass_GetDelMethod(PyObject* cls);
 extern void PyObjCClass_SetDelMethod(PyObject* cls, PyObject* newval);

File pyobjc-core/Modules/objc/objc-class.m

 
     super_class = PyObjCClass_GetClass(py_super_class);
     if (super_class) {
-        PyObjCClass_CheckMethodList(py_super_class, 1);
+        if (PyObjCClass_CheckMethodList(py_super_class, 1) < 0) {
+            return NULL;
+        }
     }
 
     hiddenSelectors = PyDict_New();
             return NULL;
 
         } else {
-            PyObjCClass_CheckMethodList(py_super_class, 1);
+            if (PyObjCClass_CheckMethodList(py_super_class, 1) < 0) {
+                (void)PyObjCClass_UnbuildClass(objc_class);
+                Py_DECREF(protocols);
+                Py_DECREF(real_bases);
+                Py_DECREF(metadict);
+                Py_DECREF(hiddenSelectors);
+                Py_DECREF(hiddenClassSelectors);
+                return NULL;
+            }
+
         }
 
         Py_DECREF(PyList_GET_ITEM(real_bases, 0));
     Py_DECREF(keys);
     Py_DECREF(old_dict);
 
-    PyObjCClass_CheckMethodList(res, 1);
+    if (PyObjCClass_CheckMethodList(res, 1) < 0) {
+        Py_DECREF(res);
+        return NULL;
+    }
 
     /* This is an "extra" ref */
     Py_INCREF(res);
     Py_FatalError(buf);
 }
 
-void
+int
 PyObjCClass_CheckMethodList(PyObject* cls, int recursive)
 {
     PyObjCClassObject* info;
 
     info = (PyObjCClassObject*)cls;
 
-    if (info->class == NULL) return;
+    if (info->class == NULL) return 0;
 
     while (info->class != NULL) {
 
 
             r =  update_convenience_methods(cls);
             if (r < 0) {
-                PyErr_SetString(PyExc_RuntimeError,
-                    "Cannot rescan method table");
-                return;
+                return -1;
             }
             if (info->sel_to_py) {
                 Py_XDECREF(info->sel_to_py);
         Py_DECREF(cls); /* We don't actually need the reference, convert to a borrowed one */
         info = (PyObjCClassObject*)cls;
     }
+    return 0;
 }
 
 
     for (i = 0; i < n; i++) {
         base = PyTuple_GET_ITEM(mro, i);
         if (PyObjCClass_Check(base)) {
-            PyObjCClass_CheckMethodList(base, 0);
+            if (PyObjCClass_CheckMethodList(base, 0) < 0) {
+                return NULL;
+            }
             dict = ((PyTypeObject *)base)->tp_dict;
 
         } else if (PyType_Check(base)) {
                 Py_TYPE(name)->tp_name);
         return NULL;
     }
-    PyObjCClass_CheckMethodList(self, 1);
+    if (PyObjCClass_CheckMethodList(self, 1) < 0) {
+        return NULL;
+    }
 
     descr = _type_lookup(Py_TYPE(self), name
 #ifndef PyObjC_FAST_UNICODE_ASCII
         , name_bytes
 #endif
     );
+    if (descr == NULL && PyErr_Occurred()) {
+        return NULL;
+    }
 
     f = NULL;
     if (descr != NULL
         return NULL;
     }
 
-    PyObjCClass_CheckMethodList(cls, 1);
+    if (PyObjCClass_CheckMethodList(cls, 1) < 0) {
+        return NULL;
+    }
 
     info = (PyObjCClassObject*)cls;
     if (info->sel_to_py == NULL) {

File pyobjc-core/Modules/objc/objc-object.m

             Py_INCREF(tp);
             Py_DECREF(tmp);
 
-            PyObjCClass_CheckMethodList((PyObject*)tp, 0);
+            if (PyObjCClass_CheckMethodList((PyObject*)tp, 0) < 0) {
+                Py_DECREF(tp);
+                return -1;
+            }
         }
         Py_CLEAR(tp);
     }
         base = PyTuple_GET_ITEM(mro, i);
 
         if (PyObjCClass_Check(base)) {
-            PyObjCClass_CheckMethodList(base, 0);
+            if (PyObjCClass_CheckMethodList(base, 0) < 0) {
+                return NULL;
+            }
+
             dict = ((PyTypeObject *)base)->tp_dict;
 
         } else if (PyType_Check(base)) {
             , name_bytes
 #endif
         );
+        if (descr == NULL && PyErr_Occurred()) {
+            return NULL;
+        }
     }
 
     f = NULL;
         , name_bytes
 #endif
     );
+    if (descr == NULL && PyErr_Occurred()) {
+        return -1;
+    }
     f = NULL;
     if (descr != NULL
 #if PY_MAJOR_VERSION == 2
         return NULL;
     }
 
-    PyObjCClass_CheckMethodList((PyObject*)Py_TYPE(res), 1);
+    if (PyObjCClass_CheckMethodList((PyObject*)Py_TYPE(res), 1) < 0) {
+        Py_DECREF(res);
+        return NULL;
+    }
 
     ((PyObjCObject*)res)->objc_object = objc_object;
 
     /* This should be in the tp_alloc for the new class, but
      * adding a tp_alloc to PyObjCClass_Type doesn't seem to help
      */
-    PyObjCClass_CheckMethodList((PyObject*)Py_TYPE(res), 1);
+    if (PyObjCClass_CheckMethodList((PyObject*)Py_TYPE(res), 1) < 0) {
+        Py_DECREF(res);
+        return NULL;
+    }
 
     ((PyObjCObject*)res)->objc_object = objc_object;
 #ifdef Py_HAVE_LOCAL_LOOKUP

File pyobjc-core/Modules/objc/objc_super.m

              * Also make sure that the method tables are up-to-date.
              */
             if (PyObjCClass_Check(tmp)) {
-                PyObjCClass_CheckMethodList(tmp, NO);
+                if (PyObjCClass_CheckMethodList(tmp, NO) < 0) {
+                    return NULL;
+                }
             }
 
             if (PyObjCClass_Check(tmp) && PyObjCClass_Check(su->obj))  {

File pyobjc-framework-CoreWLAN/Lib/CoreWLAN/__init__.py

 
     return not self.isEqualToProfile_(other)
 
-objc.addConvenienceForClass('CW8021XProfile', {
-    '__eq__': _CW8021XProfile__eq__,
-    '__ne__': _CW8021XProfile__ne__,
-})
+objc.addConvenienceForClass('CW8021XProfile', (
+    ('__eq__', _CW8021XProfile__eq__),
+    ('__ne__', _CW8021XProfile__ne__),
+))
 
 
 def _CWChannel__eq__(self, other):
 
     return not self.isEqualToChannel_(other)
 
-objc.addConvenienceForClass('CWChannel', {
-    '__eq__': _CWChannel__eq__,
-    '__ne__': _CWChannel__ne__,
-})
+objc.addConvenienceForClass('CWChannel', (
+    ('__eq__', _CWChannel__eq__),
+    ('__ne__', _CWChannel__ne__),
+))
 
 def _CWConfiguration__eq__(self, other):
     if not isinstance(other, type(self)):
 
     return not self.isEqualToConfiguration_(other)
 
-objc.addConvenienceForClass('CWConfiguration', {
-    '__eq__': _CWConfiguration__eq__,
-    '__ne__': _CWConfiguration__ne__,
-})
+objc.addConvenienceForClass('CWConfiguration', (
+    ('__eq__', _CWConfiguration__eq__),
+    ('__ne__', _CWConfiguration__ne__),
+))
 
 def _CWNetwork__eq__(self, other):
     if not isinstance(other, type(self)):
 
     return not self.isEqualToNetwork_(other)
 
-objc.addConvenienceForClass('CWNetwork', {
-    '__eq__': _CWNetwork__eq__,
-    '__ne__': _CWNetwork__ne__,
-})
+objc.addConvenienceForClass('CWNetwork', (
+    ('__eq__', _CWNetwork__eq__),
+    ('__ne__', _CWNetwork__ne__),
+))
 
 def _CWNetworkProfile__eq__(self, other):
     if not isinstance(other, type(self)):
 
     return not self.isEqualToNetworkProfile_(other)
 
-objc.addConvenienceForClass('CWNetworkProfile', {
-    '__eq__': _CWNetworkProfile__eq__,
-    '__ne__': _CWNetworkProfile__ne__,
-})
+objc.addConvenienceForClass('CWNetworkProfile', (
+    ('__eq__', _CWNetworkProfile__eq__),
+    ('__ne__', _CWNetworkProfile__ne__),
+))
 
 
 sys.modules['CoreWLAN'] = mod = objc.ObjCLazyModule(

File pyobjc-framework-CoreWLAN/PyObjCTest/test_cwconfiguration.py

 import CoreWLAN
 
 class TestCWConfiguration (TestCase):
-    @min_os_level('10.6')
+    @os_level_between('10.6', '10.8')
     def testMethods10_6(self):
-        self.assertResultIsBOOL(CoreWLAN.CWConfiguration.alwaysRememberNetworks)
-        self.assertResultIsBOOL(CoreWLAN.CWConfiguration.disconnectOnLogout)
         self.assertResultIsBOOL(CoreWLAN.CWConfiguration.requireAdminForNetworkChange)
         self.assertResultIsBOOL(CoreWLAN.CWConfiguration.requireAdminForPowerChange)
         self.assertResultIsBOOL(CoreWLAN.CWConfiguration.requireAdminForIBSSCreation)
 
-        self.assertArgIsBOOL(CoreWLAN.CWConfiguration.setAlwaysRememberNetworks_, 0)
-        self.assertArgIsBOOL(CoreWLAN.CWConfiguration.setDisconnectOnLogout_, 0)
         self.assertArgIsBOOL(CoreWLAN.CWConfiguration.setRequireAdminForNetworkChange_, 0)
         self.assertArgIsBOOL(CoreWLAN.CWConfiguration.setRequireAdminForPowerChange_, 0)
         self.assertArgIsBOOL(CoreWLAN.CWConfiguration.setRequireAdminForIBSSCreation_, 0)
 
+        self.assertResultIsBOOL(CoreWLAN.CWConfiguration.alwaysRememberNetworks)
+        self.assertArgIsBOOL(CoreWLAN.CWConfiguration.setAlwaysRememberNetworks_, 0)
+
+        self.assertResultIsBOOL(CoreWLAN.CWConfiguration.disconnectOnLogout)
+        self.assertArgIsBOOL(CoreWLAN.CWConfiguration.setDisconnectOnLogout_, 0)
+
     @min_os_level('10.7')
     def testMethods10_7(self):
         self.assertResultIsBOOL(CoreWLAN.CWConfiguration.requireAdministratorForAssociation)

File pyobjc-framework-CoreWLAN/PyObjCTest/test_cwinterface.py

         self.assertResultIsBOOL(CoreWLAN.CWInterface.commitConfiguration_authorization_error_);
         self.assertArgIsOut(CoreWLAN.CWInterface.commitConfiguration_authorization_error_, 2);
 
-    @min_os_level('10.6')
+    @os_level_between('10.6', '10.8')
     def testMethods10_6(self):
         self.assertResultIsBOOL(CoreWLAN.CWInterface.supportsWoW);
         self.assertResultIsBOOL(CoreWLAN.CWInterface.supportsWEP);