mirror of https://github.com/python/cpython
#6844: do not emit DeprecationWarnings on access if Exception.message has been set by the user.
This works by always setting it in __dict__, except when it's implicitly set in __init__.
This commit is contained in:
parent
4676048b43
commit
0674d3fb5f
|
@ -303,6 +303,46 @@ class ExceptionTests(unittest.TestCase):
|
||||||
'pickled "%r", attribute "%s"' %
|
'pickled "%r", attribute "%s"' %
|
||||||
(e, checkArgName))
|
(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):
|
def testSlicing(self):
|
||||||
# Test that you can slice an exception directly instead of requiring
|
# Test that you can slice an exception directly instead of requiring
|
||||||
# going through the 'args' attribute.
|
# going through the 'args' attribute.
|
||||||
|
|
|
@ -12,6 +12,9 @@ What's New in Python 2.7 alpha 1
|
||||||
Core and Builtins
|
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.
|
- Issue #6846: Fix bug where bytearray.pop() returns negative integers.
|
||||||
|
|
||||||
- classmethod no longer checks if its argument is callable.
|
- classmethod no longer checks if its argument is callable.
|
||||||
|
|
|
@ -300,30 +300,51 @@ BaseException_set_args(PyBaseExceptionObject *self, PyObject *val)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
BaseException_get_message(PyBaseExceptionObject *self)
|
BaseException_get_message(PyBaseExceptionObject *self)
|
||||||
{
|
{
|
||||||
int ret;
|
PyObject *msg;
|
||||||
ret = PyErr_WarnEx(PyExc_DeprecationWarning,
|
|
||||||
"BaseException.message has been deprecated as "
|
|
||||||
"of Python 2.6", 1);
|
|
||||||
if (ret < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
Py_INCREF(self->message);
|
/* if "message" is in self->dict, accessing a user-set message attribute */
|
||||||
return self->message;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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
|
static int
|
||||||
BaseException_set_message(PyBaseExceptionObject *self, PyObject *val)
|
BaseException_set_message(PyBaseExceptionObject *self, PyObject *val)
|
||||||
{
|
{
|
||||||
int ret;
|
/* if val is NULL, delete the message attribute */
|
||||||
ret = PyErr_WarnEx(PyExc_DeprecationWarning,
|
if (val == NULL) {
|
||||||
"BaseException.message has been deprecated as "
|
if (self->dict && PyDict_GetItemString(self->dict, "message")) {
|
||||||
"of Python 2.6", 1);
|
if (PyDict_DelItemString(self->dict, "message") < 0)
|
||||||
if (ret < 0)
|
return -1;
|
||||||
return -1;
|
}
|
||||||
Py_INCREF(val);
|
Py_XDECREF(self->message);
|
||||||
Py_DECREF(self->message);
|
self->message = NULL;
|
||||||
self->message = val;
|
return 0;
|
||||||
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[] = {
|
static PyGetSetDef BaseException_getset[] = {
|
||||||
|
|
Loading…
Reference in New Issue