[Python-checkins] r77088 - in python/trunk: Doc/c-api/exceptions.rst Doc/data/refcounts.dat Include/pyerrors.h Lib/test/test_exceptions.py Misc/NEWS Modules/_testcapimodule.c Python/errors.c

georg.brandl python-checkins at python.org
Mon Dec 28 09:34:58 CET 2009


Author: georg.brandl
Date: Mon Dec 28 09:34:58 2009
New Revision: 77088

Log:
#7033: add new API function PyErr_NewExceptionWithDoc, for easily giving new exceptions a docstring.

Modified:
   python/trunk/Doc/c-api/exceptions.rst
   python/trunk/Doc/data/refcounts.dat
   python/trunk/Include/pyerrors.h
   python/trunk/Lib/test/test_exceptions.py
   python/trunk/Misc/NEWS
   python/trunk/Modules/_testcapimodule.c
   python/trunk/Python/errors.c

Modified: python/trunk/Doc/c-api/exceptions.rst
==============================================================================
--- python/trunk/Doc/c-api/exceptions.rst	(original)
+++ python/trunk/Doc/c-api/exceptions.rst	Mon Dec 28 09:34:58 2009
@@ -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

Modified: python/trunk/Doc/data/refcounts.dat
==============================================================================
--- python/trunk/Doc/data/refcounts.dat	(original)
+++ python/trunk/Doc/data/refcounts.dat	Mon Dec 28 09:34:58 2009
@@ -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:::

Modified: python/trunk/Include/pyerrors.h
==============================================================================
--- python/trunk/Include/pyerrors.h	(original)
+++ python/trunk/Include/pyerrors.h	Mon Dec 28 09:34:58 2009
@@ -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 */

Modified: python/trunk/Lib/test/test_exceptions.py
==============================================================================
--- python/trunk/Lib/test/test_exceptions.py	(original)
+++ python/trunk/Lib/test/test_exceptions.py	Mon Dec 28 09:34:58 2009
@@ -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)

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Mon Dec 28 09:34:58 2009
@@ -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
 -----
 

Modified: python/trunk/Modules/_testcapimodule.c
==============================================================================
--- python/trunk/Modules/_testcapimodule.c	(original)
+++ python/trunk/Modules/_testcapimodule.c	Mon Dec 28 09:34:58 2009
@@ -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 */
 };
 

Modified: python/trunk/Python/errors.c
==============================================================================
--- python/trunk/Python/errors.c	(original)
+++ python/trunk/Python/errors.c	Mon Dec 28 09:34:58 2009
@@ -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


More information about the Python-checkins mailing list