diff options
author | Georg Brandl <georg@python.org> | 2009-12-28 08:34:58 (GMT) |
---|---|---|
committer | Georg Brandl <georg@python.org> | 2009-12-28 08:34:58 (GMT) |
commit | 740cdc3a9f9593ee1fe86d751c70b8505d6a19c9 (patch) | |
tree | 4c34f7bec409dfb040cba93c2064b37bb71b2b95 | |
parent | 02e7dfde639498064b137be7cb850c4229f0c8fb (diff) | |
download | cpython-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.rst | 9 | ||||
-rw-r--r-- | Doc/data/refcounts.dat | 6 | ||||
-rw-r--r-- | Include/pyerrors.h | 6 | ||||
-rw-r--r-- | Lib/test/test_exceptions.py | 39 | ||||
-rw-r--r-- | Misc/NEWS | 5 | ||||
-rw-r--r-- | Modules/_testcapimodule.c | 22 | ||||
-rw-r--r-- | Python/errors.c | 34 |
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) @@ -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 |