summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2009-12-28 08:34:58 (GMT)
committerGeorg Brandl <georg@python.org>2009-12-28 08:34:58 (GMT)
commit740cdc3a9f9593ee1fe86d751c70b8505d6a19c9 (patch)
tree4c34f7bec409dfb040cba93c2064b37bb71b2b95
parent02e7dfde639498064b137be7cb850c4229f0c8fb (diff)
downloadcpython-740cdc3a9f9593ee1fe86d751c70b8505d6a19c9.zip
cpython-740cdc3a9f9593ee1fe86d751c70b8505d6a19c9.tar.gz
cpython-740cdc3a9f9593ee1fe86d751c70b8505d6a19c9.tar.bz2
#7033: add new API function PyErr_NewExceptionWithDoc, for easily giving new exceptions a docstring.
-rw-r--r--Doc/c-api/exceptions.rst9
-rw-r--r--Doc/data/refcounts.dat6
-rw-r--r--Include/pyerrors.h6
-rw-r--r--Lib/test/test_exceptions.py39
-rw-r--r--Misc/NEWS5
-rw-r--r--Modules/_testcapimodule.c22
-rw-r--r--Python/errors.c34
7 files changed, 119 insertions, 2 deletions
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 @@ is a separate error indicator for each thread.
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:char*:name::
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 @@ PyAPI_FUNC(void) _PyErr_BadInternalCall(char *filename, int lineno);
#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 @@ class TestSameStrAndUnicodeMsg(unittest.TestCase):
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 @@ Library
- 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 @@ code_newempty(PyObject *self, PyObject *args)
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 @@ static PyMethodDef TestMethods[] = {
#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 @@ PyErr_NewException(char *name, PyObject *base, PyObject *dict)
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