1/* 2 * A subclass of the builtin super type that works correctly when resolving 3 * class methods. 4 * 5 * The problem is that the default ``super`` object walks the class an peeks 6 * inside the class dict instead of using an API. That causes a problem because 7 * the class methods of an ObjC class aren't stored in the class __dict__ but 8 * in the __dict__ of the metaclass, which isn't advertised to Python code. 9 */ 10 11#include "pyobjc.h" 12 13 14/* 15 * NOTE: This is a minor tweak of Python 2.5's super_getattro and is a rather 16 * crude hack. 17 */ 18typedef struct { 19 PyObject_HEAD 20 PyTypeObject *type; 21 PyObject *obj; 22 PyTypeObject *obj_type; 23} superobject; 24 25static PyObject * 26super_getattro(PyObject *self, PyObject *name) 27{ 28 superobject *su = (superobject *)self; 29 int skip = su->obj_type == NULL; 30 31 32 33 if (!skip) { 34 /* We want __class__ to return the class of the super object 35 (i.e. super, or a subclass), not the class of su->obj. */ 36 skip = (PyString_Check(name) && 37 PyString_GET_SIZE(name) == 9 && 38 strcmp(PyString_AS_STRING(name), "__class__") == 0); 39 } 40 41 if (!skip) { 42 PyObject *mro, *res, *tmp, *dict; 43 PyTypeObject *starttype; 44 descrgetfunc f; 45 Py_ssize_t i, n; 46 47 starttype = su->obj_type; 48 mro = starttype->tp_mro; 49 50 if (mro == NULL) 51 n = 0; 52 else { 53 assert(PyTuple_Check(mro)); 54 n = PyTuple_GET_SIZE(mro); 55 } 56 for (i = 0; i < n; i++) { 57 if ((PyObject *)(su->type) == PyTuple_GET_ITEM(mro, i)) 58 break; 59 } 60 i++; 61 res = NULL; 62 for (; i < n; i++) { 63 tmp = PyTuple_GET_ITEM(mro, i); 64 65 /* PyObjC PATCH: Treat PyObjC class objects specially to maintain 66 * the proper illusion for users. 67 * Also make sure that the method tables are up-to-date. 68 */ 69 if (PyObjCClass_Check(tmp)) { 70 PyObjCClass_CheckMethodList(tmp, NO); 71 } 72 73 if (PyObjCClass_Check(tmp) && PyObjCClass_Check(su->obj)) { 74 dict = tmp->ob_type->tp_dict; 75 76 } else if (PyType_Check(tmp)) 77 dict = ((PyTypeObject *)tmp)->tp_dict; 78 else if (PyClass_Check(tmp)) 79 dict = ((PyClassObject *)tmp)->cl_dict; 80 else 81 continue; 82 83 res = PyDict_GetItem(dict, name); 84 if (res != NULL) { 85 Py_INCREF(res); 86 f = res->ob_type->tp_descr_get; 87 if (f != NULL) { 88 tmp = f(res, 89 /* Only pass 'obj' param if 90 this is instance-mode super 91 (See SF ID #743627) 92 */ 93 (su->obj == (PyObject *) 94 su->obj_type 95 ? (PyObject *)NULL 96 : su->obj), 97 (PyObject *)starttype); 98 Py_DECREF(res); 99 res = tmp; 100 } 101 return res; 102 } 103 } 104 } 105 return PyObject_GenericGetAttr(self, name); 106} 107 108PyTypeObject PyObjCSuper_Type = { 109 PyObject_HEAD_INIT(&PyType_Type) 110 0, 111 "objc.super", 112 sizeof(superobject), 113 0, 114 /* methods */ 115 0, /* tp_dealloc */ 116 0, /* tp_print */ 117 0, /* tp_getattr */ 118 0, /* tp_setattr */ 119 0, /* tp_compare */ 120 0, /* tp_repr */ 121 0, /* tp_as_number */ 122 0, /* tp_as_sequence */ 123 0, /* tp_as_mapping */ 124 0, /* tp_hash */ 125 0, /* tp_call */ 126 0, /* tp_str */ 127 super_getattro, /* tp_getattro */ 128 0, /* tp_setattro */ 129 0, /* tp_as_buffer */ 130 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | 131 Py_TPFLAGS_BASETYPE, /* tp_flags */ 132 0, /* tp_doc */ 133 0, /* tp_traverse */ 134 0, /* tp_clear */ 135 0, /* tp_richcompare */ 136 0, /* tp_weaklistoffset */ 137 0, /* tp_iter */ 138 0, /* tp_iternext */ 139 0, /* tp_methods */ 140 0, /* tp_members */ 141 0, /* tp_getset */ 142 0, /* tp_base */ 143 0, /* tp_dict */ 144 0, /* tp_descr_get */ 145 0, /* tp_descr_set */ 146 0, /* tp_dictoffset */ 147 0, /* tp_init */ 148 PyType_GenericAlloc, /* tp_alloc */ 149 PyType_GenericNew, /* tp_new */ 150 PyObject_GC_Del, /* tp_free */ 151 0, /* tp_is_gc */ 152 0, /* tp_bases */ 153 0, /* tp_mro */ 154 0, /* tp_cache */ 155 0, /* tp_mro */ 156 0, /* tp_weaklist */ 157 0 /* tp_del */ 158#if PY_VERSION_HEX >= 0x02060000 159 , 0 /* tp_version_tag */ 160#endif 161 162}; 163