mirror of https://github.com/python/cpython
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:
parent
a05153683c
commit
129bd52146
|
@ -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}
|
provided in the built-in namespace as well as the \module{exceptions}
|
||||||
module.
|
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
|
For class exceptions, in a \keyword{try}\stindex{try} statement with
|
||||||
an \keyword{except}\stindex{except} clause that mentions a particular
|
an \keyword{except}\stindex{except} clause that mentions a particular
|
||||||
class, that clause also handles any exception classes derived from
|
class, that clause also handles any exception classes derived from
|
||||||
|
|
|
@ -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
|
value can be raised along with the identifying string which can be
|
||||||
passed to the handler.
|
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]
|
\begin{notice}[warning]
|
||||||
Messages to exceptions are not part of the Python API. Their contents may
|
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
|
change from one version of Python to the next without warning and should not
|
||||||
|
|
|
@ -2,7 +2,7 @@ import unittest
|
||||||
import __builtin__
|
import __builtin__
|
||||||
import exceptions
|
import exceptions
|
||||||
import warnings
|
import warnings
|
||||||
from test.test_support import run_unittest
|
from test.test_support import run_unittest, guard_warnings_filter
|
||||||
import os
|
import os
|
||||||
from platform import system as platform_system
|
from platform import system as platform_system
|
||||||
|
|
||||||
|
@ -113,13 +113,8 @@ class UsageTests(unittest.TestCase):
|
||||||
|
|
||||||
"""Test usage of exceptions"""
|
"""Test usage of exceptions"""
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self._filters = warnings.filters[:]
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
warnings.filters = self._filters[:]
|
|
||||||
|
|
||||||
def test_raise_classic(self):
|
def test_raise_classic(self):
|
||||||
|
# Raising a classic class is okay (for now).
|
||||||
class ClassicClass:
|
class ClassicClass:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
|
@ -136,6 +131,10 @@ class UsageTests(unittest.TestCase):
|
||||||
self.fail("unable to raise class class instance")
|
self.fail("unable to raise class class instance")
|
||||||
|
|
||||||
def test_raise_new_style_non_exception(self):
|
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):
|
class NewStyleClass(object):
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
|
@ -143,35 +142,52 @@ class UsageTests(unittest.TestCase):
|
||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
except:
|
except:
|
||||||
self.fail("unable to raise new-style class")
|
self.fail("able to raise new-style class")
|
||||||
try:
|
try:
|
||||||
raise NewStyleClass()
|
raise NewStyleClass()
|
||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
except:
|
except:
|
||||||
self.fail("unable to raise new-style class instance")
|
self.fail("able to raise new-style class instance")
|
||||||
|
|
||||||
def test_raise_string(self):
|
def test_raise_string(self):
|
||||||
warnings.resetwarnings()
|
# Raising a string raises TypeError.
|
||||||
warnings.filterwarnings("error")
|
|
||||||
try:
|
try:
|
||||||
raise "spam"
|
raise "spam"
|
||||||
except DeprecationWarning:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
except:
|
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):
|
def test_catch_string(self):
|
||||||
# Test will be pertinent when catching exceptions raises a
|
# Catching a string should trigger a DeprecationWarning.
|
||||||
# DeprecationWarning
|
with guard_warnings_filter():
|
||||||
warnings.filterwarnings("ignore", "raising")
|
warnings.resetwarnings()
|
||||||
str_exc = "spam"
|
warnings.filterwarnings("error")
|
||||||
try:
|
str_exc = "spam"
|
||||||
raise str_exc
|
try:
|
||||||
except str_exc:
|
try:
|
||||||
pass
|
raise StandardError
|
||||||
except:
|
except str_exc:
|
||||||
self.fail("catching a string exception failed")
|
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():
|
def test_main():
|
||||||
run_unittest(ExceptionClassTests, UsageTests)
|
run_unittest(ExceptionClassTests, UsageTests)
|
||||||
|
|
|
@ -12,6 +12,9 @@ What's New in Python 2.6 alpha 1?
|
||||||
Core and builtins
|
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
|
- 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
|
a weakref on itself during a __del__ call for new-style classes (classic
|
||||||
classes still have the bug).
|
classes still have the bug).
|
||||||
|
|
|
@ -2206,8 +2206,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
|
||||||
case SETUP_LOOP:
|
case SETUP_LOOP:
|
||||||
case SETUP_EXCEPT:
|
case SETUP_EXCEPT:
|
||||||
case SETUP_FINALLY:
|
case SETUP_FINALLY:
|
||||||
/* NOTE: If you add any new block-setup opcodes that are not try/except/finally
|
/* NOTE: If you add any new block-setup opcodes that are
|
||||||
handlers, you may need to update the PyGen_NeedsFinalizing() function. */
|
not try/except/finally handlers, you may need to
|
||||||
|
update the PyGen_NeedsFinalizing() function. */
|
||||||
|
|
||||||
PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg,
|
PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg,
|
||||||
STACK_LEVEL());
|
STACK_LEVEL());
|
||||||
|
@ -3069,15 +3070,7 @@ do_raise(PyObject *type, PyObject *value, PyObject *tb)
|
||||||
Py_DECREF(tmp);
|
Py_DECREF(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyString_CheckExact(type)) {
|
if (PyExceptionClass_Check(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))
|
|
||||||
PyErr_NormalizeException(&type, &value, &tb);
|
PyErr_NormalizeException(&type, &value, &tb);
|
||||||
|
|
||||||
else if (PyExceptionInstance_Check(type)) {
|
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
|
/* Not something you can raise. You get an exception
|
||||||
anyway, just not what you specified :-) */
|
anyway, just not what you specified :-) */
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"exceptions must be classes, instances, or "
|
"exceptions must be classes or instances, not %s",
|
||||||
"strings (deprecated), not %s",
|
|
||||||
type->ob_type->tp_name);
|
type->ob_type->tp_name);
|
||||||
goto raise_error;
|
goto raise_error;
|
||||||
}
|
}
|
||||||
|
@ -3985,6 +3977,35 @@ cmp_outcome(int op, register PyObject *v, register PyObject *w)
|
||||||
res = !res;
|
res = !res;
|
||||||
break;
|
break;
|
||||||
case PyCmp_EXC_MATCH:
|
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);
|
res = PyErr_GivenExceptionMatches(v, w);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Reference in New Issue