]> granicus.if.org Git - python/commitdiff
#6844: do not emit DeprecationWarnings on access if Exception.message has been set...
authorGeorg Brandl <georg@python.org>
Wed, 16 Sep 2009 20:30:09 +0000 (20:30 +0000)
committerGeorg Brandl <georg@python.org>
Wed, 16 Sep 2009 20:30:09 +0000 (20:30 +0000)
This works by always setting it in __dict__, except when it's implicitly set in __init__.

Lib/test/test_exceptions.py
Misc/NEWS
Objects/exceptions.c

index 6cfbd099660552bd07d4feaf44f001b1cadc9688..f547eb20701a2abfaceaa9b7cb92c64fead92d74 100644 (file)
@@ -303,6 +303,46 @@ class ExceptionTests(unittest.TestCase):
                                                   'pickled "%r", attribute "%s"' %
                                                   (e, checkArgName))
 
+
+    def testDeprecatedMessageAttribute(self):
+        # Accessing BaseException.message and relying on its value set by
+        # BaseException.__init__ triggers a deprecation warning.
+        exc = BaseException("foo")
+        with warnings.catch_warnings(record=True) as w:
+            self.assertEquals(exc.message, "foo")
+        self.assertEquals(len(w), 1)
+        self.assertEquals(w[0].category, DeprecationWarning)
+        self.assertEquals(
+            str(w[0].message),
+            "BaseException.message has been deprecated as of Python 2.6")
+
+
+    def testRegularMessageAttribute(self):
+        # Accessing BaseException.message after explicitly setting a value
+        # for it does not trigger a deprecation warning.
+        exc = BaseException("foo")
+        exc.message = "bar"
+        with warnings.catch_warnings(record=True) as w:
+            self.assertEquals(exc.message, "bar")
+        self.assertEquals(len(w), 0)
+        # Deleting the message is supported, too.
+        del exc.message
+        with self.assertRaises(AttributeError):
+            exc.message
+
+    def testPickleMessageAttribute(self):
+        # Pickling with message attribute must work, as well.
+        e = Exception("foo")
+        f = Exception("foo")
+        f.message = "bar"
+        for p in pickle, cPickle:
+            ep = p.loads(p.dumps(e))
+            with warnings.catch_warnings():
+                ignore_message_warning()
+                self.assertEqual(ep.message, "foo")
+            fp = p.loads(p.dumps(f))
+            self.assertEqual(fp.message, "bar")
+
     def testSlicing(self):
         # Test that you can slice an exception directly instead of requiring
         # going through the 'args' attribute.
index 555d96ea8f31f11ea597ca475717ee318e3932f7..72aa48e108384666f30c0a1984a321ce43db7d5a 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@ What's New in Python 2.7 alpha 1
 Core and Builtins
 -----------------
 
+- Issue #6844: Do not emit DeprecationWarnings when accessing a "message"
+  attribute on exceptions that was set explicitly.
+
 - Issue #6846: Fix bug where bytearray.pop() returns negative integers.
 
 - classmethod no longer checks if its argument is callable.
index fbdc781162ee4bd29b1f0497ff41105a15fa5fca..0a39a6bee95b796a61639e14158799bf3fa8fa2b 100644 (file)
@@ -300,30 +300,51 @@ BaseException_set_args(PyBaseExceptionObject *self, PyObject *val)
 static PyObject *
 BaseException_get_message(PyBaseExceptionObject *self)
 {
-       int ret;
-       ret = PyErr_WarnEx(PyExc_DeprecationWarning,
-                               "BaseException.message has been deprecated as "
-                               "of Python 2.6", 1);
-       if (ret < 0)
-               return NULL;
+    PyObject *msg;
+    
+    /* if "message" is in self->dict, accessing a user-set message attribute */
+    if (self->dict &&
+        (msg = PyDict_GetItemString(self->dict, "message"))) {
+        Py_INCREF(msg);
+        return msg;
+    }
+
+    if (self->message == NULL) {
+        PyErr_SetString(PyExc_AttributeError, "message attribute was deleted");
+        return NULL;
+    }
 
-       Py_INCREF(self->message);
-       return self->message;
+    /* accessing the deprecated "builtin" message attribute of Exception */
+    if (PyErr_WarnEx(PyExc_DeprecationWarning,
+                     "BaseException.message has been deprecated as "
+                     "of Python 2.6", 1) < 0)
+        return NULL;
+
+    Py_INCREF(self->message);
+    return self->message;
 }
 
 static int
 BaseException_set_message(PyBaseExceptionObject *self, PyObject *val)
 {
-       int ret;
-       ret = PyErr_WarnEx(PyExc_DeprecationWarning,
-                               "BaseException.message has been deprecated as "
-                               "of Python 2.6", 1);
-       if (ret < 0)
-               return -1;
-       Py_INCREF(val);
-       Py_DECREF(self->message);
-       self->message = val;
-       return 0;
+    /* if val is NULL, delete the message attribute */
+    if (val == NULL) {
+        if (self->dict && PyDict_GetItemString(self->dict, "message")) {
+            if (PyDict_DelItemString(self->dict, "message") < 0)
+                return -1;
+        }
+        Py_XDECREF(self->message);
+        self->message = NULL;
+        return 0;
+    }
+    
+    /* else set it in __dict__, but may need to create the dict first */
+    if (self->dict == NULL) {
+        self->dict = PyDict_New();
+        if (!self->dict)
+            return -1;
+    }
+    return PyDict_SetItemString(self->dict, "message", val);
 }
 
 static PyGetSetDef BaseException_getset[] = {