No more raising of string exceptions!

The next step of PEP 352 (for 2.6) causes raising a string exception to trigger
a TypeError.  Trying to catch a string exception raises a DeprecationWarning.
References to string exceptions has been removed from the docs since they are
now just an error.
This commit is contained in:
Brett Cannon 2007-01-30 21:34:36 +00:00
parent a05153683c
commit 129bd52146
5 changed files with 76 additions and 56 deletions

View File

@ -10,22 +10,6 @@ module never needs to be imported explicitly: the exceptions are
provided in the built-in namespace as well as the \module{exceptions}
module.
\begin{notice}
In past versions of Python string exceptions were supported. In
Python 1.5 and newer versions, all standard exceptions have been
converted to class objects and users are encouraged to do the same.
String exceptions will raise a \code{DeprecationWarning} in Python 2.5 and
newer.
In future versions, support for string exceptions will be removed.
Two distinct string objects with the same value are considered different
exceptions. This is done to force programmers to use exception names
rather than their string value when specifying exception handlers.
The string value of all built-in exceptions is their name, but this is
not a requirement for user-defined exceptions or exceptions defined by
library modules.
\end{notice}
For class exceptions, in a \keyword{try}\stindex{try} statement with
an \keyword{except}\stindex{except} clause that mentions a particular
class, that clause also handles any exception classes derived from

View File

@ -203,10 +203,6 @@ Exceptions can also be identified by strings, in which case the
value can be raised along with the identifying string which can be
passed to the handler.
\deprecated{2.5}{String exceptions should not be used in new code.
They will not be supported in a future version of Python. Old code
should be rewritten to use class exceptions instead.}
\begin{notice}[warning]
Messages to exceptions are not part of the Python API. Their contents may
change from one version of Python to the next without warning and should not

View File

@ -2,7 +2,7 @@ import unittest
import __builtin__
import exceptions
import warnings
from test.test_support import run_unittest
from test.test_support import run_unittest, guard_warnings_filter
import os
from platform import system as platform_system
@ -113,13 +113,8 @@ class UsageTests(unittest.TestCase):
"""Test usage of exceptions"""
def setUp(self):
self._filters = warnings.filters[:]
def tearDown(self):
warnings.filters = self._filters[:]
def test_raise_classic(self):
# Raising a classic class is okay (for now).
class ClassicClass:
pass
try:
@ -136,6 +131,10 @@ class UsageTests(unittest.TestCase):
self.fail("unable to raise class class instance")
def test_raise_new_style_non_exception(self):
# You cannot raise a new-style class that does not inherit from
# BaseException; the ability was not possible until BaseException's
# introduction so no need to support new-style objects that do not
# inherit from it.
class NewStyleClass(object):
pass
try:
@ -143,35 +142,52 @@ class UsageTests(unittest.TestCase):
except TypeError:
pass
except:
self.fail("unable to raise new-style class")
self.fail("able to raise new-style class")
try:
raise NewStyleClass()
except TypeError:
pass
except:
self.fail("unable to raise new-style class instance")
self.fail("able to raise new-style class instance")
def test_raise_string(self):
warnings.resetwarnings()
warnings.filterwarnings("error")
# Raising a string raises TypeError.
try:
raise "spam"
except DeprecationWarning:
except TypeError:
pass
except:
self.fail("raising a string did not cause a DeprecationWarning")
self.fail("was able to raise a string exception")
def test_catch_string(self):
# Test will be pertinent when catching exceptions raises a
# DeprecationWarning
warnings.filterwarnings("ignore", "raising")
str_exc = "spam"
try:
raise str_exc
except str_exc:
pass
except:
self.fail("catching a string exception failed")
# Catching a string should trigger a DeprecationWarning.
with guard_warnings_filter():
warnings.resetwarnings()
warnings.filterwarnings("error")
str_exc = "spam"
try:
try:
raise StandardError
except str_exc:
pass
except DeprecationWarning:
pass
except StandardError:
self.fail("catching a string exception did not raise "
"DeprecationWarning")
# Make sure that even if the string exception is listed in a tuple
# that a warning is raised.
try:
try:
raise StandardError
except (AssertionError, str_exc):
pass
except DeprecationWarning:
pass
except StandardError:
self.fail("catching a string exception specified in a tuple did "
"not raise DeprecationWarning")
def test_main():
run_unittest(ExceptionClassTests, UsageTests)

View File

@ -12,6 +12,9 @@ What's New in Python 2.6 alpha 1?
Core and builtins
-----------------
- PEP 352: Raising a string exception now triggers a TypeError. Attempting to
catch a string exception raises DeprecationWarning.
- Bug #1377858: Fix the segfaulting of the interpreter when an object created
a weakref on itself during a __del__ call for new-style classes (classic
classes still have the bug).

View File

@ -2206,8 +2206,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
case SETUP_LOOP:
case SETUP_EXCEPT:
case SETUP_FINALLY:
/* NOTE: If you add any new block-setup opcodes that are not try/except/finally
handlers, you may need to update the PyGen_NeedsFinalizing() function. */
/* NOTE: If you add any new block-setup opcodes that are
not try/except/finally handlers, you may need to
update the PyGen_NeedsFinalizing() function. */
PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg,
STACK_LEVEL());
@ -3069,15 +3070,7 @@ do_raise(PyObject *type, PyObject *value, PyObject *tb)
Py_DECREF(tmp);
}
if (PyString_CheckExact(type)) {
/* Raising builtin string is deprecated but still allowed --
* do nothing. Raising an instance of a new-style str
* subclass is right out. */
if (PyErr_Warn(PyExc_DeprecationWarning,
"raising a string exception is deprecated"))
goto raise_error;
}
else if (PyExceptionClass_Check(type))
if (PyExceptionClass_Check(type))
PyErr_NormalizeException(&type, &value, &tb);
else if (PyExceptionInstance_Check(type)) {
@ -3099,8 +3092,7 @@ do_raise(PyObject *type, PyObject *value, PyObject *tb)
/* Not something you can raise. You get an exception
anyway, just not what you specified :-) */
PyErr_Format(PyExc_TypeError,
"exceptions must be classes, instances, or "
"strings (deprecated), not %s",
"exceptions must be classes or instances, not %s",
type->ob_type->tp_name);
goto raise_error;
}
@ -3985,6 +3977,35 @@ cmp_outcome(int op, register PyObject *v, register PyObject *w)
res = !res;
break;
case PyCmp_EXC_MATCH:
if (PyTuple_Check(w)) {
Py_ssize_t i, length;
length = PyTuple_Size(w);
for (i = 0; i < length; i += 1) {
PyObject *exc = PyTuple_GET_ITEM(w, i);
if (PyString_Check(exc)) {
int ret_val;
ret_val = PyErr_WarnEx(
PyExc_DeprecationWarning,
"catching of string "
"exceptions is "
"deprecated", 1);
if (ret_val == -1)
return NULL;
}
}
}
else {
if (PyString_Check(w)) {
int ret_val;
ret_val = PyErr_WarnEx(
PyExc_DeprecationWarning,
"catching of string "
"exceptions is deprecated",
1);
if (ret_val == -1)
return NULL;
}
}
res = PyErr_GivenExceptionMatches(v, w);
break;
default: