diff -r 6d278f426417 Include/pyerrors.h --- a/Include/pyerrors.h Fri Jul 05 18:05:29 2013 -1000 +++ b/Include/pyerrors.h Sat Jul 06 18:52:16 2013 +0200 @@ -36,6 +36,11 @@ typedef struct { PyException_HEAD + PyObject *attr; +} PyAttributeErrorObject; + +typedef struct { + PyException_HEAD PyObject *encoding; PyObject *object; Py_ssize_t start; @@ -269,6 +274,8 @@ PyObject *); PyAPI_FUNC(PyObject *) PyErr_SetImportError(PyObject *, PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyErr_SetAttributeError(PyObject *, PyObject *, + PyObject *); /* Export the old function so that the existing API remains available: */ PyAPI_FUNC(void) PyErr_BadInternalCall(void); diff -r 6d278f426417 Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py Fri Jul 05 18:05:29 2013 -1000 +++ b/Lib/test/test_exceptions.py Sat Jul 06 18:52:16 2013 +0200 @@ -952,6 +952,15 @@ exc = ImportError(arg) self.assertEqual(str(arg), str(exc)) +class AttributeErrorTests(unittest.TestCase): + def test_attributes(self): + # Setting 'attr' should not be a problem. + exc = AttributeError('coconut carrying') + self.assertIsNone(exc.attr) + + exc = AttributeError('coconut carrying', attr='carry') + self.assertEqual(exc.attr, 'carry') + if __name__ == '__main__': unittest.main() diff -r 6d278f426417 Objects/exceptions.c --- a/Objects/exceptions.c Fri Jul 05 18:05:29 2013 -1000 +++ b/Objects/exceptions.c Sat Jul 06 18:52:16 2013 +0200 @@ -1194,10 +1194,73 @@ /* * AttributeError extends Exception */ -SimpleExtendsException(PyExc_Exception, AttributeError, +static int +AttributeError_init(PyAttributeErrorObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *attr = NULL; + + if (kwds) { + GET_KWD(attr); + } + + if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) + return -1; + + if (PyTuple_GET_SIZE(args) != 1) + return 0; + + + return 0; +} + +static int +AttributeError_clear(PyAttributeErrorObject *self) +{ + Py_CLEAR(self->attr); + return BaseException_clear((PyBaseExceptionObject *)self); +} + +static void +AttributeError_dealloc(PyAttributeErrorObject *self) +{ + _PyObject_GC_UNTRACK(self); + AttributeError_clear(self); + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static int +AttributeError_traverse(PyAttributeErrorObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->attr); + return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); +} + +static PyObject * +AttributeError_str(PyAttributeErrorObject *self) +{ + return BaseException_str((PyBaseExceptionObject *)self); +} + +static PyMemberDef AttributeError_members[] = { + {"attr", T_OBJECT, offsetof(PyAttributeErrorObject, attr), 0, + PyDoc_STR("attribute name")}, + {NULL} /* Sentinel */ +}; + +static PyMethodDef AttributeError_methods[] = { + {NULL} +}; + + +ComplexExtendsException(PyExc_Exception, AttributeError, + AttributeError, 0, + AttributeError_methods, AttributeError_members, + 0, AttributeError_str, "Attribute not found."); + + /* * SyntaxError extends Exception */