Commit 229cee2d authored by Brett Cannon's avatar Brett Cannon

Deprecate BaseException.message as per PEP 352.

parent 2ebc4d80
......@@ -23,14 +23,10 @@ an ``associated value'' indicating the detailed cause of the error.
This may be a string or a tuple containing several items of
information (e.g., an error code and a string explaining the code).
The associated value is the second argument to the
\keyword{raise}\stindex{raise} statement. For string exceptions, the
associated value itself will be stored in the variable named as the
second argument of the \keyword{except} clause (if any). For class
exceptions, that variable receives the exception instance. If the
exception class is derived from the standard root class
\exception{BaseException}, the associated value is present as the
exception instance's \member{args} attribute. If there is a single argument
(as is preferred), it is bound to the \member{message} attribute.
\keyword{raise}\stindex{raise} statement. If the exception class is
derived from the standard root class \exception{BaseException}, the
associated value is present as the exception instance's \member{args}
attribute.
User code can raise built-in exceptions. This can be used to test an
exception handler or to report an error condition ``just like'' the
......@@ -56,14 +52,8 @@ The base class for all built-in exceptions. It is not meant to be directly
inherited by user-defined classes (for that use \exception{Exception}). If
\function{str()} or \function{unicode()} is called on an instance of this
class, the representation of the argument(s) to the instance are returned or
the emptry string when there were no arguments. If only a single argument is
passed in, it is stored in the \member{message} attribute. If more than one
argument is passed in, \member{message} is set to the empty string. These
semantics are meant to reflect the fact that \member{message} is to store a
text message explaining why the exception had been raised. If more data needs
to be attached to the exception, attach it through arbitrary attributes on the
instance. All arguments are also stored in \member{args} as a tuple, but it will
eventually be deprecated and thus its use is discouraged.
the emptry string when there were no arguments. All arguments are
stored in \member{args} as a tuple.
\versionadded{2.5}
\end{excdesc}
......
......@@ -106,6 +106,21 @@ MAX_INTERPOLATION_DEPTH = 10
class Error(Exception):
"""Base class for ConfigParser exceptions."""
def _get_message(self):
"""Getter for 'message'; needed only to override deprecation in
BaseException."""
return self.__message
def _set_message(self, value):
"""Setter for 'message'; needed only to override deprecation in
BaseException."""
self.__message = value
# BaseException.message has been deprecated since Python 2.6. To prevent
# DeprecationWarning from popping up over this pre-existing attribute, use
# a new property that takes lookup precedence.
message = property(_get_message, _set_message)
def __init__(self, msg=''):
self.message = msg
Exception.__init__(self, msg)
......
......@@ -137,7 +137,7 @@ class TestDefaultDict(unittest.TestCase):
try:
d1[(1,)]
except KeyError, err:
self.assertEqual(err.message, (1,))
self.assertEqual(err.args[0], (1,))
else:
self.fail("expected KeyError")
......
......@@ -5,7 +5,9 @@ import sys
import unittest
import pickle, cPickle
from test.test_support import TESTFN, unlink, run_unittest
from test.test_support import (TESTFN, unlink, run_unittest,
guard_warnings_filter)
from test.test_pep352 import ignore_message_warning
# XXX This is not really enough, each *operation* should be tested!
......@@ -272,6 +274,8 @@ class ExceptionTests(unittest.TestCase):
except NameError:
pass
with guard_warnings_filter():
ignore_message_warning()
for exc, args, expected in exceptionList:
try:
raise exc(*args)
......
......@@ -6,6 +6,13 @@ from test.test_support import run_unittest, guard_warnings_filter
import os
from platform import system as platform_system
def ignore_message_warning():
"""Ignore the DeprecationWarning for BaseException.message."""
warnings.resetwarnings()
warnings.filterwarnings("ignore", "BaseException.message",
DeprecationWarning)
class ExceptionClassTests(unittest.TestCase):
"""Tests for anything relating to exception objects themselves (e.g.,
......@@ -15,8 +22,12 @@ class ExceptionClassTests(unittest.TestCase):
self.failUnless(issubclass(Exception, object))
def verify_instance_interface(self, ins):
for attr in ("args", "message", "__str__", "__repr__", "__getitem__"):
self.failUnless(hasattr(ins, attr), "%s missing %s attribute" %
with guard_warnings_filter():
ignore_message_warning()
for attr in ("args", "message", "__str__", "__repr__",
"__getitem__"):
self.failUnless(hasattr(ins, attr),
"%s missing %s attribute" %
(ins.__class__.__name__, attr))
def test_inheritance(self):
......@@ -84,9 +95,13 @@ class ExceptionClassTests(unittest.TestCase):
# Make sure interface works properly when given a single argument
arg = "spam"
exc = Exception(arg)
results = ([len(exc.args), 1], [exc.args[0], arg], [exc.message, arg],
with guard_warnings_filter():
ignore_message_warning()
results = ([len(exc.args), 1], [exc.args[0], arg],
[exc.message, arg],
[str(exc), str(arg)], [unicode(exc), unicode(arg)],
[repr(exc), exc.__class__.__name__ + repr(exc.args)], [exc[0], arg])
[repr(exc), exc.__class__.__name__ + repr(exc.args)], [exc[0],
arg])
self.interface_test_driver(results)
def test_interface_multi_arg(self):
......@@ -94,6 +109,8 @@ class ExceptionClassTests(unittest.TestCase):
arg_count = 3
args = tuple(range(arg_count))
exc = Exception(*args)
with guard_warnings_filter():
ignore_message_warning()
results = ([len(exc.args), arg_count], [exc.args, args],
[exc.message, ''], [str(exc), str(args)],
[unicode(exc), unicode(args)],
......@@ -104,11 +121,36 @@ class ExceptionClassTests(unittest.TestCase):
def test_interface_no_arg(self):
# Make sure that with no args that interface is correct
exc = Exception()
results = ([len(exc.args), 0], [exc.args, tuple()], [exc.message, ''],
with guard_warnings_filter():
ignore_message_warning()
results = ([len(exc.args), 0], [exc.args, tuple()],
[exc.message, ''],
[str(exc), ''], [unicode(exc), u''],
[repr(exc), exc.__class__.__name__ + '()'], [True, True])
self.interface_test_driver(results)
def test_message_deprecation(self):
# As of Python 2.6, BaseException.message is deprecated.
with guard_warnings_filter():
warnings.resetwarnings()
warnings.filterwarnings('error')
try:
BaseException().message
except DeprecationWarning:
pass
else:
self.fail("BaseException.message not deprecated")
exc = BaseException()
try:
exc.message = ''
except DeprecationWarning:
pass
else:
self.fail("BaseException.message assignment not deprecated")
class UsageTests(unittest.TestCase):
"""Test usage of exceptions"""
......
......@@ -12,6 +12,8 @@ What's New in Python 2.6 alpha 1?
Core and builtins
-----------------
- Deprecate BaseException.message as per PEP 352.
- Bug #1303614: don't expose object's __dict__ when the dict is
inherited from a builtin base.
......
......@@ -212,13 +212,6 @@ static PySequenceMethods BaseException_as_sequence = {
0 /* sq_inplace_repeat; */
};
static PyMemberDef BaseException_members[] = {
{"message", T_OBJECT, offsetof(PyBaseExceptionObject, message), 0,
PyDoc_STR("exception message")},
{NULL} /* Sentinel */
};
static PyObject *
BaseException_get_dict(PyBaseExceptionObject *self)
{
......@@ -274,9 +267,42 @@ BaseException_set_args(PyBaseExceptionObject *self, PyObject *val)
return 0;
}
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 == -1)
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 == -1)
return -1;
Py_INCREF(val);
Py_DECREF(self->message);
self->message = val;
return 0;
}
static PyGetSetDef BaseException_getset[] = {
{"__dict__", (getter)BaseException_get_dict, (setter)BaseException_set_dict},
{"args", (getter)BaseException_get_args, (setter)BaseException_set_args},
{"message", (getter)BaseException_get_message,
(setter)BaseException_set_message},
{NULL},
};
......@@ -312,7 +338,7 @@ static PyTypeObject _PyExc_BaseException = {
0, /* tp_iter */
0, /* tp_iternext */
BaseException_methods, /* tp_methods */
BaseException_members, /* tp_members */
0, /* tp_members */
BaseException_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment