Index: Python/errors.c =================================================================== --- Python/errors.c (revision 76959) +++ Python/errors.c (working copy) @@ -604,6 +604,30 @@ return result; } +/* Create and document an exception */ +PyObject * +PyErr_NewExceptionWithDoc(char *name, const char *doc, PyObject *base) +{ + PyObject *dict = NULL; + PyObject *_doc; + + if (doc != NULL) { + dict = PyDict_New(); + if (dict == NULL) { + return NULL; + } + _doc = PyString_FromString(doc); + if (_doc == NULL || PyDict_SetItemString(dict, "__doc__", _doc) != 0) { + Py_XDECREF(_doc); + Py_DECREF(dict); + return NULL; + } + Py_DECREF(_doc); + } + + return PyErr_NewException(name, base, dict); +} + /* Call when an exception has occurred but there is no way for Python to handle it. Examples: exception in __del__ or during GC. */ void Index: Include/pyerrors.h =================================================================== --- Include/pyerrors.h (revision 76959) +++ Include/pyerrors.h (working copy) @@ -222,6 +222,8 @@ /* Function to create a new exception */ PyAPI_FUNC(PyObject *) PyErr_NewException(char *name, PyObject *base, PyObject *dict); +PyAPI_FUNC(PyObject *) PyErr_NewExceptionWithDoc(char *name, const char *doc, + PyObject *base); PyAPI_FUNC(void) PyErr_WriteUnraisable(PyObject *); /* In sigcheck.c or signalmodule.c */ Index: Doc/c-api/exceptions.rst =================================================================== --- Doc/c-api/exceptions.rst (revision 76959) +++ Doc/c-api/exceptions.rst (working copy) @@ -433,6 +433,18 @@ argument can be used to specify a dictionary of class variables and methods. +.. cfunction:: PyObject* PyErr_NewExceptionWithDoc(char *name, const char *doc, PyObject *base) + + Creates and returns a new exception object. The *name* argument must be the + name of the new exception, a C string of the form ``module.class``. If *doc* + is non-*NULL*, it will be used to define the docstring for the exception. + If *base* is NULL, it creates a class object derived from :exc:`Exception` + (accessible in C as :cdata:`PyExc_Exception`). See :cfunc:`PyErr_NewException` + for more information about *name* and *base*. + + .. versionadded:: 2.7 + + .. cfunction:: void PyErr_WriteUnraisable(PyObject *obj) This utility function prints a warning message to ``sys.stderr`` when an Index: Doc/data/refcounts.dat =================================================================== --- Doc/data/refcounts.dat (revision 76959) +++ Doc/data/refcounts.dat (working copy) @@ -242,6 +242,11 @@ PyErr_NewException:PyObject*:base:0: PyErr_NewException:PyObject*:dict:0: +PyErr_NewExceptionWithDoc:PyObject*::+1: +PyErr_NewExceptionWithDoc:char*:name:: +PyErr_NewExceptionWithDoc:char*:doc:: +PyErr_NewExceptionWithDoc:PyObject*:base:0: + PyErr_NoMemory:PyObject*::null: PyErr_NormalizeException:void::: Index: Lib/test/test_exceptions.py =================================================================== --- Lib/test/test_exceptions.py (revision 76959) +++ Lib/test/test_exceptions.py (working copy) @@ -428,6 +428,12 @@ e, v, tb = g() self.assertTrue(e is RuntimeError, e) self.assertTrue("maximum recursion depth exceeded" in str(v), v) + + def test_exception_with_doc(self): + import _testcapi + self.assertTrue(issubclass(_testcapi.error_with_doc, _testcapi.error)) + self.assertEqual(_testcapi.error_with_doc.__doc__, + "This is an exception docstring") def test_main(): Index: Modules/_testcapimodule.c =================================================================== --- Modules/_testcapimodule.c (revision 76959) +++ Modules/_testcapimodule.c (working copy) @@ -15,6 +15,9 @@ #endif /* WITH_THREAD */ static PyObject *TestError; /* set to exception object in init */ +static PyObject *TestErrorWithDoc; /* set to exception object in init */ +PyDoc_STRVAR(TestErrorWithDoc_doc, "This is an exception docstring"); + /* Raise TestError with test_name + ": " + msg, and return NULL. */ static PyObject * @@ -1262,4 +1265,9 @@ TestError = PyErr_NewException("_testcapi.error", NULL, NULL); Py_INCREF(TestError); PyModule_AddObject(m, "error", TestError); + + TestErrorWithDoc = PyErr_NewExceptionWithDoc("_testcapi.error_with_doc", + TestErrorWithDoc_doc, TestError); + Py_INCREF(TestErrorWithDoc); + PyModule_AddObject(m, "error_with_doc", TestErrorWithDoc); }