diff -r 89f6abc2e115 Objects/object.c --- a/Objects/object.c Wed Oct 16 19:09:31 2013 -0700 +++ b/Objects/object.c Wed Oct 16 21:08:29 2013 -0700 @@ -1140,20 +1140,45 @@ PyObject * _PyObject_NextNotImplemented(PyObject *self) { PyErr_Format(PyExc_TypeError, "'%.200s' object is not iterable", Py_TYPE(self)->tp_name); return NULL; } /* Generic GetAttr functions - put these in your tp_[gs]etattro slot */ +/* XXX Add generic from_current_raise() and chain_exception()? */ +void +from_current_raise(PyObject *name) +{ + PyObject *cause_tp, *cause_exc, *cause_tb, *exc, *msg; + + msg = PyUnicode_FromFormat("getter failed for descriptor '%U'", name); + if (!msg) + return; + PyErr_Fetch(&cause_tp, &cause_exc, &cause_tb); + exc = PyObject_CallFunctionObjArgs(PyExc_TypeError, msg, NULL); + PyErr_Restore(cause_tp, cause_exc, cause_tb); + Py_XINCREF(cause_tp); + Py_XINCREF(cause_exc); + Py_DECREF(msg); + if (!exc) + return; + + /* PyException_SetContext steals this reference */ + PyException_SetContext(exc, cause_exc); + /* PyErr_SetObject(PyExceptionInstance_Class(exc), exc); */ + PyErr_SetObject(PyExc_AttributeError, exc); + /* Py_DECREF(exc); */ +} + PyObject * _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict) { PyTypeObject *tp = Py_TYPE(obj); PyObject *descr = NULL; PyObject *res = NULL; descrgetfunc f; Py_ssize_t dictoffset; PyObject **dictptr; @@ -1172,20 +1197,23 @@ PyObject * } descr = _PyType_Lookup(tp, name); Py_XINCREF(descr); f = NULL; if (descr != NULL) { f = descr->ob_type->tp_descr_get; if (f != NULL && PyDescr_IsData(descr)) { res = f(descr, obj, (PyObject *)obj->ob_type); + if (!res && PyErr_ExceptionMatches(PyExc_AttributeError)) { + from_current_raise(name); + } goto done; } } if (dict == NULL) { /* Inline _PyObject_GetDictPtr */ dictoffset = tp->tp_dictoffset; if (dictoffset != 0) { if (dictoffset < 0) { Py_ssize_t tsize; @@ -1210,20 +1238,23 @@ PyObject * if (res != NULL) { Py_INCREF(res); Py_DECREF(dict); goto done; } Py_DECREF(dict); } if (f != NULL) { res = f(descr, obj, (PyObject *)Py_TYPE(obj)); + if (!res && PyErr_ExceptionMatches(PyExc_AttributeError)) { + from_current_raise(name); + } goto done; } if (descr != NULL) { res = descr; descr = NULL; goto done; } PyErr_Format(PyExc_AttributeError,