]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Merged revisions 77088 via svnmerge from
authorGeorg Brandl <georg@python.org>
Mon, 28 Dec 2009 08:41:01 +0000 (08:41 +0000)
committerGeorg Brandl <georg@python.org>
Mon, 28 Dec 2009 08:41:01 +0000 (08:41 +0000)
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r77088 | georg.brandl | 2009-12-28 09:34:58 +0100 (Mo, 28 Dez 2009) | 1 line

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

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

index 25f7c1152f23ef8a74f0270e80ddc02bcbc7dc7d..dc9d7b182dab072fc2e5339fae085496ada97df4 100644 (file)
@@ -404,6 +404,15 @@ in various ways.  There 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:: 3.2
+
+
 .. cfunction:: void PyErr_WriteUnraisable(PyObject *obj)
 
    This utility function prints a warning message to ``sys.stderr`` when an
index 400cf649777c82ff0adc3a9efe92b48b2d23e770..06e07050cfca7c2596771ae3ade90b7f07f1161a 100644 (file)
@@ -281,6 +281,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:::
index 7556e644696e5dae674ffb6dc9a58addd6a2ea88..a821e392e21c921a6eebed1364d875156d401392 100644 (file)
@@ -210,8 +210,10 @@ PyAPI_FUNC(void) _PyErr_BadInternalCall(const char *filename, int lineno);
 #define PyErr_BadInternalCall() _PyErr_BadInternalCall(__FILE__, __LINE__)
 
 /* Function to create a new exception */
-PyAPI_FUNC(PyObject *) PyErr_NewException(const char *name, PyObject *base,
-                                         PyObject *dict);
+PyAPI_FUNC(PyObject *) PyErr_NewException(
+       const char *name, PyObject *base, PyObject *dict);
+PyAPI_FUNC(PyObject *) PyErr_NewExceptionWithDoc(
+       const char *name, const char *doc, PyObject *base, PyObject *dict);
 PyAPI_FUNC(void) PyErr_WriteUnraisable(PyObject *);
 
 /* In sigcheck.c or signalmodule.c */
index 404b5d15703265447f1c153e05e14227d5a77092..5be67570326d5f8ac233fa71b36601160ddb1d55 100644 (file)
@@ -618,6 +618,46 @@ class ExceptionTests(unittest.TestCase):
         tb2 = raiseMemError()
         self.assertEqual(tb1, tb2)
 
+    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)
 
index ac10bed93156d716d5c341d8351188f0d04de39f..368cec651a2de5e14ef174692efe6fc3b6aefa23 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -136,6 +136,8 @@ Core and Builtins
 C-API
 -----
 
+- Issue #7033: function ``PyErr_NewExceptionWithDoc()`` added.
+
 - Issue #7414: 'C' code wasn't being skipped properly (for keyword arguments)
   in PyArg_ParseTupleAndKeywords.
 
index e549151ec9364e0fc3d8d2c3d9c6b9df613cb464..19afbf283afba6d25cb0f4723e9fd1cf98510235 100644 (file)
@@ -1716,6 +1716,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)
+{
+       const char *name;
+       const 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},
        {"raise_memoryerror",   (PyCFunction)raise_memoryerror,  METH_NOARGS},
@@ -1774,6 +1794,8 @@ static PyMethodDef TestMethods[] = {
        {"exception_print", exception_print,             METH_VARARGS},
        {"argparsing",     argparsing, METH_VARARGS},
        {"code_newempty", code_newempty,                 METH_VARARGS},
+       {"make_exception_with_doc", (PyCFunction)make_exception_with_doc,
+        METH_VARARGS | METH_KEYWORDS},
        {NULL, NULL} /* sentinel */
 };
 
index 2169a1ab7a9bc222e5ffa43436280e249214d7a9..42e0e6f3d5a3a572f9bc581d92284e85da4e3fed 100644 (file)
@@ -693,6 +693,41 @@ PyErr_NewException(const char *name, PyObject *base, PyObject *dict)
        return result;
 }
 
+
+/* Create an exception with docstring */
+PyObject *
+PyErr_NewExceptionWithDoc(const char *name, const 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 = PyUnicode_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