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 * 18 * NOTE: updated for 3.2, and 2.7 19 * 20 * FIXME: This will require further work when I remove 21 * "PyObjCClass_CheckMethodList". 22 */ 23typedef struct { 24 PyObject_HEAD 25 PyTypeObject *type; 26 PyObject *obj; 27 PyTypeObject *obj_type; 28} superobject; 29 30static PyObject * 31super_getattro(PyObject *self, PyObject *name) 32{ 33 superobject *su = (superobject *)self; 34 int skip = su->obj_type == NULL; 35 36 37 38 if (!skip) { 39 /* We want __class__ to return the class of the super object 40 (i.e. super, or a subclass), not the class of su->obj. */ 41 if (PyUnicode_Check(name)) { 42 skip = (PyUnicode_GET_SIZE(name) && PyObjC_is_ascii_string(name, "__class__")); 43#if PY_MAJOR_VERSION == 2 44 } else if (PyString_Check(name)) { 45 skip = ( 46 PyString_GET_SIZE(name) == 9 && 47 strcmp(PyString_AS_STRING(name), "__class__") == 0); 48#endif 49 } else { 50 skip = 0; 51 } 52 53 } 54 55 if (!skip) { 56 PyObject *mro, *res, *tmp, *dict; 57 PyTypeObject *starttype; 58 descrgetfunc f; 59 Py_ssize_t i, n; 60 61 starttype = su->obj_type; 62 mro = starttype->tp_mro; 63 64 if (mro == NULL) 65 n = 0; 66 else { 67 assert(PyTuple_Check(mro)); 68 n = PyTuple_GET_SIZE(mro); 69 } 70 for (i = 0; i < n; i++) { 71 if ((PyObject *)(su->type) == PyTuple_GET_ITEM(mro, i)) 72 break; 73 } 74 i++; 75 res = NULL; 76 for (; i < n; i++) { 77 tmp = PyTuple_GET_ITEM(mro, i); 78 79 /* PyObjC PATCH: Treat PyObjC class objects specially to maintain 80 * the proper illusion for users. 81 * Also make sure that the method tables are up-to-date. 82 */ 83 if (PyObjCClass_Check(tmp)) { 84 PyObjCClass_CheckMethodList(tmp, NO); 85 } 86 87 if (PyObjCClass_Check(tmp) && PyObjCClass_Check(su->obj)) { 88 dict = Py_TYPE(tmp)->tp_dict; 89 90 } else if (PyType_Check(tmp)) 91 dict = ((PyTypeObject *)tmp)->tp_dict; 92#if PY_MAJOR_VERSION == 2 93 else if (PyClass_Check(tmp)) 94 dict = ((PyClassObject *)tmp)->cl_dict; 95#endif 96 else 97 continue; 98 99 res = PyDict_GetItem(dict, name); 100 if (res != NULL) { 101 Py_INCREF(res); 102 f = Py_TYPE(res)->tp_descr_get; 103 if (f != NULL) { 104 tmp = f(res, 105 /* Only pass 'obj' param if 106 this is instance-mode super 107 (See SF ID #743627) 108 */ 109 (su->obj == (PyObject *) 110 su->obj_type 111 ? (PyObject *)NULL 112 : su->obj), 113 (PyObject *)starttype); 114 Py_DECREF(res); 115 res = tmp; 116 } 117 return res; 118 } 119 } 120 } 121 return PyObject_GenericGetAttr(self, name); 122} 123 124PyTypeObject PyObjCSuper_Type = { 125 PyVarObject_HEAD_INIT(&PyType_Type, 0) 126 "objc.super", 127 sizeof(superobject), 128 0, 129 /* methods */ 130 0, /* tp_dealloc */ 131 0, /* tp_print */ 132 0, /* tp_getattr */ 133 0, /* tp_setattr */ 134 0, /* tp_compare */ 135 0, /* tp_repr */ 136 0, /* tp_as_number */ 137 0, /* tp_as_sequence */ 138 0, /* tp_as_mapping */ 139 0, /* tp_hash */ 140 0, /* tp_call */ 141 0, /* tp_str */ 142 super_getattro, /* tp_getattro */ 143 0, /* tp_setattro */ 144 0, /* tp_as_buffer */ 145 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | 146 Py_TPFLAGS_BASETYPE, /* tp_flags */ 147 0, /* tp_doc */ 148 0, /* tp_traverse */ 149 0, /* tp_clear */ 150 0, /* tp_richcompare */ 151 0, /* tp_weaklistoffset */ 152 0, /* tp_iter */ 153 0, /* tp_iternext */ 154 0, /* tp_methods */ 155 0, /* tp_members */ 156 0, /* tp_getset */ 157 0, /* tp_base */ 158 0, /* tp_dict */ 159 0, /* tp_descr_get */ 160 0, /* tp_descr_set */ 161 0, /* tp_dictoffset */ 162 0, /* tp_init */ 163 PyType_GenericAlloc, /* tp_alloc */ 164 PyType_GenericNew, /* tp_new */ 165 PyObject_GC_Del, /* tp_free */ 166 0, /* tp_is_gc */ 167 0, /* tp_bases */ 168 0, /* tp_mro */ 169 0, /* tp_cache */ 170 0, /* tp_mro */ 171 0, /* tp_weaklist */ 172 0 /* tp_del */ 173#if PY_VERSION_HEX >= 0x02060000 174 , 0 /* tp_version_tag */ 175#endif 176 177}; 178