mirror of
https://github.com/python/cpython.git
synced 2026-01-04 06:22:20 +00:00
Deprecate BaseException.message as per PEP 352.
This commit is contained in:
parent
2ebc4d8054
commit
229cee2d3d
7 changed files with 147 additions and 68 deletions
|
|
@ -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 @@
|
|||
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 @@ def test_keyerror_without_factory(self):
|
|||
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 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,32 +274,34 @@ def testAttributes(self):
|
|||
except NameError:
|
||||
pass
|
||||
|
||||
for exc, args, expected in exceptionList:
|
||||
try:
|
||||
raise exc(*args)
|
||||
except BaseException, e:
|
||||
if type(e) is not exc:
|
||||
raise
|
||||
# Verify module name
|
||||
self.assertEquals(type(e).__module__, 'exceptions')
|
||||
# Verify no ref leaks in Exc_str()
|
||||
s = str(e)
|
||||
for checkArgName in expected:
|
||||
self.assertEquals(repr(getattr(e, checkArgName)),
|
||||
repr(expected[checkArgName]),
|
||||
'exception "%s", attribute "%s"' %
|
||||
(repr(e), checkArgName))
|
||||
with guard_warnings_filter():
|
||||
ignore_message_warning()
|
||||
for exc, args, expected in exceptionList:
|
||||
try:
|
||||
raise exc(*args)
|
||||
except BaseException, e:
|
||||
if type(e) is not exc:
|
||||
raise
|
||||
# Verify module name
|
||||
self.assertEquals(type(e).__module__, 'exceptions')
|
||||
# Verify no ref leaks in Exc_str()
|
||||
s = str(e)
|
||||
for checkArgName in expected:
|
||||
self.assertEquals(repr(getattr(e, checkArgName)),
|
||||
repr(expected[checkArgName]),
|
||||
'exception "%s", attribute "%s"' %
|
||||
(repr(e), checkArgName))
|
||||
|
||||
# test for pickling support
|
||||
for p in pickle, cPickle:
|
||||
for protocol in range(p.HIGHEST_PROTOCOL + 1):
|
||||
new = p.loads(p.dumps(e, protocol))
|
||||
for checkArgName in expected:
|
||||
got = repr(getattr(new, checkArgName))
|
||||
want = repr(expected[checkArgName])
|
||||
self.assertEquals(got, want,
|
||||
'pickled "%r", attribute "%s' %
|
||||
(e, checkArgName))
|
||||
# test for pickling support
|
||||
for p in pickle, cPickle:
|
||||
for protocol in range(p.HIGHEST_PROTOCOL + 1):
|
||||
new = p.loads(p.dumps(e, protocol))
|
||||
for checkArgName in expected:
|
||||
got = repr(getattr(new, checkArgName))
|
||||
want = repr(expected[checkArgName])
|
||||
self.assertEquals(got, want,
|
||||
'pickled "%r", attribute "%s' %
|
||||
(e, checkArgName))
|
||||
|
||||
def testSlicing(self):
|
||||
# Test that you can slice an exception directly instead of requiring
|
||||
|
|
|
|||
|
|
@ -6,6 +6,13 @@
|
|||
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,9 +22,13 @@ def test_builtins_new_style(self):
|
|||
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" %
|
||||
(ins.__class__.__name__, attr))
|
||||
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):
|
||||
# Make sure the inheritance hierarchy matches the documentation
|
||||
|
|
@ -84,30 +95,61 @@ def test_interface_single_arg(self):
|
|||
# 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],
|
||||
[str(exc), str(arg)], [unicode(exc), unicode(arg)],
|
||||
[repr(exc), exc.__class__.__name__ + repr(exc.args)], [exc[0], arg])
|
||||
self.interface_test_driver(results)
|
||||
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])
|
||||
self.interface_test_driver(results)
|
||||
|
||||
def test_interface_multi_arg(self):
|
||||
# Make sure interface correct when multiple arguments given
|
||||
arg_count = 3
|
||||
args = tuple(range(arg_count))
|
||||
exc = Exception(*args)
|
||||
results = ([len(exc.args), arg_count], [exc.args, args],
|
||||
[exc.message, ''], [str(exc), str(args)],
|
||||
[unicode(exc), unicode(args)],
|
||||
[repr(exc), exc.__class__.__name__ + repr(exc.args)],
|
||||
[exc[-1], args[-1]])
|
||||
self.interface_test_driver(results)
|
||||
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)],
|
||||
[repr(exc), exc.__class__.__name__ + repr(exc.args)],
|
||||
[exc[-1], args[-1]])
|
||||
self.interface_test_driver(results)
|
||||
|
||||
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, ''],
|
||||
[str(exc), ''], [unicode(exc), u''],
|
||||
[repr(exc), exc.__class__.__name__ + '()'], [True, True])
|
||||
self.interface_test_driver(results)
|
||||
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):
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue