Commits

Ronald Oussoren committed 43ed41f

Add API for registering an ObjC class with ABC-s

This is primarily meant for use by the metadata system,
and will register classes with the ABC on first use. This
means the new API can be used before the ObjC class is actually
available.

  • Participants
  • Parent commits 576261b

Comments (0)

Files changed (4)

pyobjc-core/Doc/metadata/manual.rst

 
    Register *type* as a dict-like type that will be bridged to Objective-C as an NSDictionary subclass.
 
+.. function:: registerABCForClass(classname, \*abc_class)
+
+   Objective-C *classname* will be registered with the ABC classes in *abc_class*
+   when the Objective-C class gets used from Python.
+
+   .. versionadded: 3.0
 
 .. function:: addConvenienceForClass(classname, method)
 
    Like :func:`addConvenienceForBasicMapping`, but for sequences with
    ``count`` and ``objectAtIndex:`` selectors.
 
-   .. warning:: ``readonly==False`` is not supported at the moment.
-
    .. versionadded:: 3.0
 
 Register proxy types

pyobjc-core/Lib/objc/_convenience.py

 import warnings
 import collections
 
-__all__ = ( 'addConvenienceForClass',)
+__all__ = ( 'addConvenienceForClass', 'registerABCForClass')
 
 CLASS_METHODS = {}
 CLASS_ABC = {}
 
 # XXX: interface is too wide (super_class is not needed, can pass actual class)
 @register
-def add_convenience_methods(super_class, name, type_dict):
+def add_convenience_methods(cls, type_dict):
     """
     Add additional methods to the type-dict of subclass 'name' of
     'super_class'.
 
     Matching entries from both mappings are added to the 'type_dict'.
     """
-    for nm, value in CLASS_METHODS.get(name, ()):
+    for nm, value in CLASS_METHODS.get(cls.__name__, ()):
         type_dict[nm] = value
 
-    # XXX: Work is needed to deal with ABCs (class isn't defined yet)
-
+    try:
+        for cls in CLASS_ABC[cls.__name__]:
+            cls.register(cls)
+        del CLASS_ABC[cls.__name__]
+    except KeyError:
+        pass
 
 def register(f):
     options._make_bundleForClass = f
         return cb
     return selector(bundleForClass, isClassMethod=True)
 
+def registerABCForClass(classname, *abc_class):
+    """
+    Register *classname* with the *abc_class*-es when
+    the class becomes available.
+    """
+    try:
+        CLASS_ABC += tuple(abc_class)
+    except KeyError:
+        CLASS_ABC = tuple(abc_class)
+
+    options._mapping_count += 1
+    _rescanClass(classname)
+
+
 def addConvenienceForClass(classname, methods):
     """
     Add the list with methods to the class with the specified name

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

 static int
 update_convenience_methods(PyObject* cls)
 {
-    PyObject* super_class;
-    PyObject* name;
     PyObject* res;
     PyObject* args;
     Class     objc_cls;
 
     objc_cls = PyObjCClass_GetClass(cls);
 
-    if (class_getSuperclass(objc_cls) == nil) {
-        super_class = Py_None;
-        Py_INCREF(super_class);
-    } else {
-        super_class = PyObjCClass_New(class_getSuperclass(objc_cls));
-        if (super_class == NULL) {
-            return -1;
-        }
-    }
-
-    name = PyText_FromString(class_getName(objc_cls));
-    if (name == NULL) {
-        Py_DECREF(super_class);
+    dict = PyDict_New();
+    if (dict == NULL) {
         return -1;
     }
 
-#if 0
-    dict = /*PyDict_Copy*/(((PyTypeObject*)cls)->tp_dict);
-    Py_INCREF(dict);
-#else
-    dict = PyDict_New();
-#endif
-    if (dict == NULL) {
-        Py_DECREF(super_class);
-        Py_DECREF(name);
-        return -1;
-    }
-
-    args = PyTuple_New(3);
+    args = PyTuple_New(2);
     if (args == NULL) {
-        Py_DECREF(super_class);
-        Py_DECREF(name);
         Py_DECREF(dict);
         return -1;
     }
 
-    PyTuple_SET_ITEM(args, 0, super_class);
-    PyTuple_SET_ITEM(args, 1, name);
-    PyTuple_SET_ITEM(args, 2, dict);
+    PyTuple_SET_ITEM(args, 0, cls);
+    PyTuple_SET_ITEM(args, 1, dict);
+    Py_INCREF(cls);
 
     res = PyObject_Call(PyObjC_ClassExtender, args, NULL);
     if (res == NULL) {
             }
 #endif
         } else {
+            if (PyDict_SetItem(((PyTypeObject*)cls)->tp_dict, k, v) == -1) {
+                PyErr_Clear();
+            }
             continue;
         }
 
         if (PyType_Type.tp_setattro(cls, k, v) == -1) {
-            PyErr_Print();
             PyErr_Clear();
             continue;
         }

pyobjc-core/NEWS.txt

 Version 3.0
 -----------
 
+* Added ``objc.registerABCForClass`` to make it possible to register
+  a class with a number of ABC classes when the class becomes available.
+
 * ``NSDecimalNumber`` can now be instantatiated as a normal Python object::
 
      value = NSDecimalNumber(4)