#7033: add new API function PyErr_NewExceptionWithDoc, for easily giving new exceptions a docstring.
diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst
index ba18af1..474478c 100644
--- a/Doc/c-api/exceptions.rst
+++ b/Doc/c-api/exceptions.rst
@@ -433,6 +433,15 @@
    argument can be used to specify a dictionary of class variables and methods.
 
 
+.. cfunction:: PyObject* PyErr_NewExceptionWithDoc(char *name, char *doc, PyObject *base, PyObject *dict)
+
+   Same as :cfunc:`PyErr_NewException`, except that the new exception class can
+   easily be given a docstring: If *doc* is non-*NULL*, it will be used as the
+   docstring for the exception class.
+
+   .. versionadded:: 2.7
+
+
 .. cfunction:: void PyErr_WriteUnraisable(PyObject *obj)
 
    This utility function prints a warning message to ``sys.stderr`` when an
diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat
index c8633c0..58bde91 100644
--- a/Doc/data/refcounts.dat
+++ b/Doc/data/refcounts.dat
@@ -242,6 +242,12 @@
 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_NewExceptionWithDoc:PyObject*:dict:0:
+
 PyErr_NoMemory:PyObject*::null:
 
 PyErr_NormalizeException:void:::
diff --git a/Include/pyerrors.h b/Include/pyerrors.h
index fedf913..432004a 100644
--- a/Include/pyerrors.h
+++ b/Include/pyerrors.h
@@ -220,8 +220,10 @@
 #define PyErr_BadInternalCall() _PyErr_BadInternalCall(__FILE__, __LINE__)
 
 /* Function to create a new exception */
-PyAPI_FUNC(PyObject *) PyErr_NewException(char *name, PyObject *base,
-                                         PyObject *dict);
+PyAPI_FUNC(PyObject *) PyErr_NewException(
+	char *name, PyObject *base, PyObject *dict);
+PyAPI_FUNC(PyObject *) PyErr_NewExceptionWithDoc(
+	char *name, char *doc, PyObject *base, PyObject *dict);
 PyAPI_FUNC(void) PyErr_WriteUnraisable(PyObject *);
 
 /* In sigcheck.c or signalmodule.c */
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index d5ce80b..a30f42b 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -537,6 +537,45 @@
         self.assertRaises(UnicodeEncodeError, str, e)
         self.assertEqual(unicode(e), u'f\xf6\xf6')
 
+    def test_exception_with_doc(self):
+        import _testcapi
+        doc2 = "This is a test docstring."
+        doc4 = "This is another test docstring."
+
+        self.assertRaises(SystemError, _testcapi.make_exception_with_doc,
+                          "error1")
+
+        # test basic usage of PyErr_NewException
+        error1 = _testcapi.make_exception_with_doc("_testcapi.error1")
+        self.assertIs(type(error1), type)
+        self.assertTrue(issubclass(error1, Exception))
+        self.assertIsNone(error1.__doc__)
+
+        # test with given docstring
+        error2 = _testcapi.make_exception_with_doc("_testcapi.error2", doc2)
+        self.assertEqual(error2.__doc__, doc2)
+
+        # test with explicit base (without docstring)
+        error3 = _testcapi.make_exception_with_doc("_testcapi.error3",
+                                                   base=error2)
+        self.assertTrue(issubclass(error3, error2))
+
+        # test with explicit base tuple
+        class C(object):
+            pass
+        error4 = _testcapi.make_exception_with_doc("_testcapi.error4", doc4,
+                                                   (error3, C))
+        self.assertTrue(issubclass(error4, error3))
+        self.assertTrue(issubclass(error4, C))
+        self.assertEqual(error4.__doc__, doc4)
+
+        # test with explicit dictionary
+        error5 = _testcapi.make_exception_with_doc("_testcapi.error5", "",
+                                                   error4, {'a': 1})
+        self.assertTrue(issubclass(error5, error4))
+        self.assertEqual(error5.a, 1)
+        self.assertEqual(error5.__doc__, "")
+
 
 def test_main():
     run_unittest(ExceptionTests, TestSameStrAndUnicodeMsg)
diff --git a/Misc/NEWS b/Misc/NEWS
index 8fbfc50..b23c672 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -70,6 +70,11 @@
 - Issue #7457: added a read_pkg_file method to
   distutils.dist.DistributionMetadata.
 
+C-API
+-----
+
+- Issue #7033: function ``PyErr_NewExceptionWithDoc()`` added.
+
 Build
 -----
 
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index c8f2087..f0dd75e 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -1198,6 +1198,26 @@
 	return (PyObject *)PyCode_NewEmpty(filename, funcname, firstlineno);
 }
 
+/* Test PyErr_NewExceptionWithDoc (also exercise PyErr_NewException).
+   Run via Lib/test/test_exceptions.py */
+static PyObject *
+make_exception_with_doc(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+	char *name;
+	char *doc = NULL;
+	PyObject *base = NULL;
+	PyObject *dict = NULL;
+
+	static char *kwlist[] = {"name", "doc", "base", "dict", NULL};
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+			"s|sOO:make_exception_with_doc", kwlist,
+					 &name, &doc, &base, &dict))
+		return NULL;
+
+	return PyErr_NewExceptionWithDoc(name, doc, base, dict);
+}
+
 static PyMethodDef TestMethods[] = {
 	{"raise_exception",	raise_exception,		 METH_VARARGS},
 	{"test_config",		(PyCFunction)test_config,	 METH_NOARGS},
@@ -1248,6 +1268,8 @@
 #endif
 	{"traceback_print", traceback_print, 	         METH_VARARGS},
 	{"code_newempty", code_newempty, 	         METH_VARARGS},
+	{"make_exception_with_doc", (PyCFunction)make_exception_with_doc,
+	 METH_VARARGS | METH_KEYWORDS},
 	{NULL, NULL} /* sentinel */
 };
 
diff --git a/Python/errors.c b/Python/errors.c
index 9f040ad..2d47779 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -604,6 +604,40 @@
 	return result;
 }
 
+
+/* Create an exception with docstring */
+PyObject *
+PyErr_NewExceptionWithDoc(char *name, char *doc, PyObject *base, PyObject *dict)
+{
+	int result;
+	PyObject *ret = NULL;
+	PyObject *mydict = NULL; /* points to the dict only if we create it */
+	PyObject *docobj;
+
+	if (dict == NULL) {
+		dict = mydict = PyDict_New();
+		if (dict == NULL) {
+			return NULL;
+		}
+	}
+
+	if (doc != NULL) {
+		docobj = PyString_FromString(doc);
+		if (docobj == NULL)
+			goto failure;
+		result = PyDict_SetItemString(dict, "__doc__", docobj);
+		Py_DECREF(docobj);
+		if (result < 0)
+			goto failure;
+	}
+
+	ret = PyErr_NewException(name, base, dict);
+  failure:
+	Py_XDECREF(mydict);
+	return ret;
+}
+
+
 /* Call when an exception has occurred but there is no way for Python
    to handle it.  Examples: exception in __del__ or during GC. */
 void