static int merge_class_dict(PyObject* dict, PyObject* aclass) { PyObject *classdict; PyObject *bases; assert(PyDict_Check(dict)); assert(aclass); /* Merge in the type's dict (if any). */ classdict = PyObject_GetAttrString(aclass, "__dict__"); if (classdict == NULL) PyErr_Clear(); else { int status = PyDict_Update(dict, classdict); Py_DECREF(classdict); if (status < 0) return -1; } /* Recursively merge in the base types' (if any) dicts. */ bases = PyObject_GetAttrString(aclass, "__bases__"); if (bases == NULL) PyErr_Clear(); else { /* We have no guarantee that bases is a real tuple */ Py_ssize_t i, n; n = PySequence_Size(bases); /* This better be right */ if (n < 0) PyErr_Clear(); else { for (i = 0; i < n; i++) { int status; PyObject *base = PySequence_GetItem(bases, i); if (base == NULL) { Py_DECREF(bases); return -1; } status = merge_class_dict(dict, base); Py_DECREF(base); if (status < 0) { Py_DECREF(bases); return -1; } } } Py_DECREF(bases); } return 0; }
PyObject * PyObject_Dir(PyObject *arg) { /* Set exactly one of these non-NULL before the end. */ PyObject *result = NULL; /* result list */ PyObject *masterdict = NULL; /* result is masterdict.keys() */ /* If NULL arg, return the locals. */ if (arg == NULL) { PyObject *locals = PyEval_GetLocals(); if (locals == NULL) goto error; result = PyDict_Keys(locals); if (result == NULL) goto error; } /* Elif this is some form of module, we only want its dict. */ else if (PyModule_Check(arg)) { masterdict = PyObject_GetAttrString(arg, "__dict__"); if (masterdict == NULL) goto error; if (!PyDict_Check(masterdict)) { PyErr_SetString(PyExc_TypeError, "module.__dict__ is not a dictionary"); goto error; } } /* Elif some form of type or class, grab its dict and its bases. We deliberately don't suck up its __class__, as methods belonging to the metaclass would probably be more confusing than helpful. */ else if (PyType_Check(arg) || PyClass_Check(arg)) { masterdict = PyDict_New(); if (masterdict == NULL) goto error; if (merge_class_dict(masterdict, arg) < 0) goto error; } /* Else look at its dict, and the attrs reachable from its class. */ else { PyObject *itsclass; /* Create a dict to start with. CAUTION: Not everything responding to __dict__ returns a dict! */ masterdict = PyObject_GetAttrString(arg, "__dict__"); if (masterdict == NULL) { PyErr_Clear(); masterdict = PyDict_New(); } else if (!PyDict_Check(masterdict)) { Py_DECREF(masterdict); masterdict = PyDict_New(); } else { /* The object may have returned a reference to its dict, so copy it to avoid mutating it. */ PyObject *temp = PyDict_Copy(masterdict); Py_DECREF(masterdict); masterdict = temp; } if (masterdict == NULL) goto error; /* Merge in __members__ and __methods__ (if any). XXX Would like this to go away someday; for now, it's XXX needed to get at im_self etc of method objects. */ if (merge_list_attr(masterdict, arg, "__members__") < 0) goto error; if (merge_list_attr(masterdict, arg, "__methods__") < 0) goto error; /* Merge in attrs reachable from its class. CAUTION: Not all objects have a __class__ attr. */ itsclass = PyObject_GetAttrString(arg, "__class__"); if (itsclass == NULL) PyErr_Clear(); else { int status = merge_class_dict(masterdict, itsclass); Py_DECREF(itsclass); if (status < 0) goto error; } } assert((result == NULL) ^ (masterdict == NULL)); if (masterdict != NULL) { /* The result comes from its keys. */ assert(result == NULL); result = PyDict_Keys(masterdict); if (result == NULL) goto error; } assert(result); if (PyList_Sort(result) != 0) goto error; else goto normal_return; error: Py_XDECREF(result); result = NULL; /* fall through */ normal_return: Py_XDECREF(masterdict); return result; }