summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCollin Winter <collinw@gmail.com>2007-08-31 00:04:24 (GMT)
committerCollin Winter <collinw@gmail.com>2007-08-31 00:04:24 (GMT)
commit828f04ac3f0dd3b68b4dbf42a79ebb846d1de568 (patch)
tree21e25d3d969ce636c32539e4d4b5255dc4c85702
parent150b7d7d02eca6970d792f3e6887f957a36b6ca2 (diff)
downloadcpython-828f04ac3f0dd3b68b4dbf42a79ebb846d1de568.zip
cpython-828f04ac3f0dd3b68b4dbf42a79ebb846d1de568.tar.gz
cpython-828f04ac3f0dd3b68b4dbf42a79ebb846d1de568.tar.bz2
Issue #1066: implement PEP 3109, 2/3 of PEP 3134.
-rw-r--r--Grammar/Grammar2
-rw-r--r--Include/Python-ast.h11
-rw-r--r--Include/pyerrors.h46
-rw-r--r--Lib/contextlib.py2
-rw-r--r--Lib/doctest.py4
-rw-r--r--Lib/os.py8
-rw-r--r--Lib/test/test_ast.py4
-rw-r--r--Lib/test/test_exceptions.py60
-rw-r--r--Lib/test/test_grammar.py2
-rw-r--r--Lib/test/test_opcodes.py12
-rw-r--r--Lib/test/test_raise.py417
-rw-r--r--Lib/test/test_syntax.py10
-rw-r--r--Lib/test/test_sys.py5
-rw-r--r--Lib/test/test_with.py2
-rw-r--r--Lib/test/test_zipimport.py2
-rw-r--r--Lib/urllib.py8
-rw-r--r--Lib/urllib2.py2
-rw-r--r--Lib/wsgiref/handlers.py2
-rwxr-xr-xMac/BuildScript/build-installer.py10
-rw-r--r--Mac/Tools/Doc/setup.py5
-rw-r--r--Mac/scripts/buildpkg.py2
-rw-r--r--Mac/scripts/mkestrres.py2
-rw-r--r--Objects/exceptions.c98
-rw-r--r--Parser/Python.asdl3
-rw-r--r--Python/Python-ast.c32
-rw-r--r--Python/ast.c39
-rw-r--r--Python/ceval.c134
-rw-r--r--Python/compile.c22
-rw-r--r--Python/graminit.c51
-rw-r--r--Python/import.c1
-rw-r--r--Python/symtable.c12
-rwxr-xr-xTools/webchecker/webchecker.py4
32 files changed, 761 insertions, 253 deletions
diff --git a/Grammar/Grammar b/Grammar/Grammar
index 17a0148..6111fae 100644
--- a/Grammar/Grammar
+++ b/Grammar/Grammar
@@ -49,7 +49,7 @@ break_stmt: 'break'
continue_stmt: 'continue'
return_stmt: 'return' [testlist]
yield_stmt: yield_expr
-raise_stmt: 'raise' [test [',' test [',' test]]]
+raise_stmt: 'raise' [test ['from' test]]
import_stmt: import_name | import_from
import_name: 'import' dotted_as_names
# note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS
diff --git a/Include/Python-ast.h b/Include/Python-ast.h
index 174a841..51e5298 100644
--- a/Include/Python-ast.h
+++ b/Include/Python-ast.h
@@ -134,9 +134,8 @@ struct _stmt {
} With;
struct {
- expr_ty type;
- expr_ty inst;
- expr_ty tback;
+ expr_ty exc;
+ expr_ty cause;
} Raise;
struct {
@@ -418,9 +417,9 @@ stmt_ty _Py_If(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno,
#define With(a0, a1, a2, a3, a4, a5) _Py_With(a0, a1, a2, a3, a4, a5)
stmt_ty _Py_With(expr_ty context_expr, expr_ty optional_vars, asdl_seq * body,
int lineno, int col_offset, PyArena *arena);
-#define Raise(a0, a1, a2, a3, a4, a5) _Py_Raise(a0, a1, a2, a3, a4, a5)
-stmt_ty _Py_Raise(expr_ty type, expr_ty inst, expr_ty tback, int lineno, int
- col_offset, PyArena *arena);
+#define Raise(a0, a1, a2, a3, a4) _Py_Raise(a0, a1, a2, a3, a4)
+stmt_ty _Py_Raise(expr_ty exc, expr_ty cause, int lineno, int col_offset,
+ PyArena *arena);
#define TryExcept(a0, a1, a2, a3, a4, a5) _Py_TryExcept(a0, a1, a2, a3, a4, a5)
stmt_ty _Py_TryExcept(asdl_seq * body, asdl_seq * handlers, asdl_seq * orelse,
int lineno, int col_offset, PyArena *arena);
diff --git a/Include/pyerrors.h b/Include/pyerrors.h
index ca187e4..8d676d9 100644
--- a/Include/pyerrors.h
+++ b/Include/pyerrors.h
@@ -6,16 +6,17 @@ extern "C" {
/* Error objects */
+/* PyException_HEAD defines the initial segment of every exception class. */
+#define PyException_HEAD PyObject_HEAD; PyObject *dict;\
+ PyObject *args; PyObject *traceback;\
+ PyObject *context; PyObject *cause;
+
typedef struct {
- PyObject_HEAD
- PyObject *dict;
- PyObject *args;
+ PyException_HEAD
} PyBaseExceptionObject;
typedef struct {
- PyObject_HEAD
- PyObject *dict;
- PyObject *args;
+ PyException_HEAD
PyObject *msg;
PyObject *filename;
PyObject *lineno;
@@ -25,9 +26,7 @@ typedef struct {
} PySyntaxErrorObject;
typedef struct {
- PyObject_HEAD
- PyObject *dict;
- PyObject *args;
+ PyException_HEAD
PyObject *encoding;
PyObject *object;
Py_ssize_t start;
@@ -36,16 +35,12 @@ typedef struct {
} PyUnicodeErrorObject;
typedef struct {
- PyObject_HEAD
- PyObject *dict;
- PyObject *args;
+ PyException_HEAD
PyObject *code;
} PySystemExitObject;
typedef struct {
- PyObject_HEAD
- PyObject *dict;
- PyObject *args;
+ PyException_HEAD
PyObject *myerrno;
PyObject *strerror;
PyObject *filename;
@@ -53,9 +48,7 @@ typedef struct {
#ifdef MS_WINDOWS
typedef struct {
- PyObject_HEAD
- PyObject *dict;
- PyObject *args;
+ PyException_HEAD
PyObject *myerrno;
PyObject *strerror;
PyObject *filename;
@@ -84,6 +77,19 @@ PyAPI_FUNC(int) PyErr_GivenExceptionMatches(PyObject *, PyObject *);
PyAPI_FUNC(int) PyErr_ExceptionMatches(PyObject *);
PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**);
+/* Traceback manipulation (PEP 3134) */
+PyAPI_FUNC(int) PyException_SetTraceback(PyObject *, PyObject *);
+PyAPI_FUNC(PyObject *) PyException_GetTraceback(PyObject *);
+
+/* Cause manipulation (PEP 3134) */
+PyAPI_FUNC(PyObject *) PyException_GetCause(PyObject *);
+PyAPI_FUNC(void) PyException_SetCause(PyObject *, PyObject *);
+
+/* Context manipulation (PEP 3134) */
+PyAPI_FUNC(PyObject *) PyException_GetContext(PyObject *);
+PyAPI_FUNC(void) PyException_SetContext(PyObject *, PyObject *);
+
+
/* */
#define PyExceptionClass_Check(x) \
@@ -98,7 +104,7 @@ PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**);
#define PyExceptionInstance_Class(x) ((PyObject*)((x)->ob_type))
-
+
/* Predefined exceptions */
PyAPI_DATA(PyObject *) PyExc_BaseException;
@@ -212,7 +218,7 @@ PyAPI_FUNC(void) PyErr_WriteUnraisable(PyObject *);
PyAPI_FUNC(int) PyErr_WarnEx(PyObject *category, const char *msg,
Py_ssize_t stack_level);
PyAPI_FUNC(int) PyErr_WarnExplicit(PyObject *, const char *,
- const char *, int,
+ const char *, int,
const char *, PyObject *);
/* In sigcheck.c or signalmodule.c */
diff --git a/Lib/contextlib.py b/Lib/contextlib.py
index bc810b0..38ec577 100644
--- a/Lib/contextlib.py
+++ b/Lib/contextlib.py
@@ -125,7 +125,7 @@ def nested(*managers):
# Don't rely on sys.exc_info() still containing
# the right information. Another exception may
# have been raised and caught by an exit method
- raise exc[0], exc[1], exc[2]
+ raise exc[0](exc[1]).with_traceback(exc[2])
class closing(object):
diff --git a/Lib/doctest.py b/Lib/doctest.py
index 2374d44..395f8b6 100644
--- a/Lib/doctest.py
+++ b/Lib/doctest.py
@@ -1608,7 +1608,7 @@ class DebugRunner(DocTestRunner):
'42\n'
>>> exc_info = failure.exc_info
- >>> raise exc_info[0], exc_info[1], exc_info[2]
+ >>> raise exc_info[1] # Already has the traceback
Traceback (most recent call last):
...
KeyError
@@ -2146,7 +2146,7 @@ class DocTestCase(unittest.TestCase):
'42\n'
>>> exc_info = failure.exc_info
- >>> raise exc_info[0], exc_info[1], exc_info[2]
+ >>> raise exc_info[1] # Already has the traceback
Traceback (most recent call last):
...
KeyError
diff --git a/Lib/os.py b/Lib/os.py
index b8d7a0f..727d0cb 100644
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -113,7 +113,7 @@ elif 'ce' in _names:
del ce
else:
- raise ImportError, 'no os specific module found'
+ raise ImportError('no os specific module found')
sys.modules['os.path'] = path
from os.path import curdir, pardir, sep, pathsep, defpath, altsep, devnull
@@ -386,8 +386,8 @@ def _execvpe(file, args, env=None):
saved_exc = e
saved_tb = tb
if saved_exc:
- raise error, saved_exc, saved_tb
- raise error, last_exc, tb
+ raise error(saved_exc).with_traceback(saved_tb)
+ raise error(last_exc).with_traceback(tb)
# Change environ to automatically call putenv(), unsetenv if they exist.
@@ -492,7 +492,7 @@ if _exists("fork") and not _exists("spawnv") and _exists("execv"):
elif WIFEXITED(sts):
return WEXITSTATUS(sts)
else:
- raise error, "Not stopped, signaled or exited???"
+ raise error("Not stopped, signaled or exited???")
def spawnv(mode, file, args):
"""spawnv(mode, file, args) -> integer
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index b8c1ed9..6299123 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -37,7 +37,7 @@ exec_tests = [
# If
"if v:pass",
# Raise
- "raise Exception, 'string'",
+ "raise Exception('string')",
# TryExcept
"try:\n pass\nexcept Exception:\n pass",
# TryFinally
@@ -160,7 +160,7 @@ exec_results = [
('Module', [('For', (1, 0), ('Name', (1, 4), 'v', ('Store',)), ('Name', (1, 9), 'v', ('Load',)), [('Pass', (1, 11))], [])]),
('Module', [('While', (1, 0), ('Name', (1, 6), 'v', ('Load',)), [('Pass', (1, 8))], [])]),
('Module', [('If', (1, 0), ('Name', (1, 3), 'v', ('Load',)), [('Pass', (1, 5))], [])]),
-('Module', [('Raise', (1, 0), ('Name', (1, 6), 'Exception', ('Load',)), ('Str', (1, 17), 'string'), None)]),
+('Module', [('Raise', (1, 0), ('Call', (1, 6), ('Name', (1, 6), 'Exception', ('Load',)), [('Str', (1, 16), 'string')], [], None, None), None)]),
('Module', [('TryExcept', (1, 0), [('Pass', (2, 2))], [('excepthandler', (3, 0), ('Name', (3, 7), 'Exception', ('Load',)), None, [('Pass', (4, 2))], 3, 0)], [])]),
('Module', [('TryFinally', (1, 0), [('Pass', (2, 2))], [('Pass', (4, 2))])]),
('Module', [('Assert', (1, 0), ('Name', (1, 7), 'v', ('Load',)), None)]),
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index 90f6ae7..d2a2191 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -13,7 +13,7 @@ class ExceptionTests(unittest.TestCase):
def raise_catch(self, exc, excname):
try:
- raise exc, "spam"
+ raise exc("spam")
except exc as err:
buf1 = str(err)
try:
@@ -141,7 +141,7 @@ class ExceptionTests(unittest.TestCase):
class BadException(Exception):
def __init__(self_):
- raise RuntimeError, "can't instantiate BadException"
+ raise RuntimeError("can't instantiate BadException")
class InvalidException:
pass
@@ -305,6 +305,62 @@ class ExceptionTests(unittest.TestCase):
'pickled "%r", attribute "%s' %
(e, checkArgName))
+ def testWithTraceback(self):
+ try:
+ raise IndexError(4)
+ except:
+ tb = sys.exc_info()[2]
+
+ e = BaseException().with_traceback(tb)
+ self.failUnless(isinstance(e, BaseException))
+ self.assertEqual(e.__traceback__, tb)
+
+ e = IndexError(5).with_traceback(tb)
+ self.failUnless(isinstance(e, IndexError))
+ self.assertEqual(e.__traceback__, tb)
+
+ class MyException(Exception):
+ pass
+
+ e = MyException().with_traceback(tb)
+ self.failUnless(isinstance(e, MyException))
+ self.assertEqual(e.__traceback__, tb)
+
+ def testInvalidTraceback(self):
+ try:
+ Exception().__traceback__ = 5
+ except TypeError as e:
+ self.failUnless("__traceback__ must be a traceback" in str(e))
+ else:
+ self.fail("No exception raised")
+
+ def testNoneClearsTracebackAttr(self):
+ try:
+ raise IndexError(4)
+ except:
+ tb = sys.exc_info()[2]
+
+ e = Exception()
+ e.__traceback__ = tb
+ e.__traceback__ = None
+ self.assertEqual(e.__traceback__, None)
+
+ def testChainingAttrs(self):
+ e = Exception()
+ self.assertEqual(e.__context__, None)
+ self.assertEqual(e.__cause__, None)
+
+ e = TypeError()
+ self.assertEqual(e.__context__, None)
+ self.assertEqual(e.__cause__, None)
+
+ class MyException(EnvironmentError):
+ pass
+
+ e = MyException()
+ self.assertEqual(e.__context__, None)
+ self.assertEqual(e.__cause__, None)
+
def testKeywordArgs(self):
# test that builtin exception don't take keyword args,
# but user-defined subclasses can if they want
diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py
index bfc77fe..ee3ffc7 100644
--- a/Lib/test/test_grammar.py
+++ b/Lib/test/test_grammar.py
@@ -438,7 +438,7 @@ class GrammarTests(unittest.TestCase):
def testRaise(self):
# 'raise' test [',' test]
- try: raise RuntimeError, 'just testing'
+ try: raise RuntimeError('just testing')
except RuntimeError: pass
try: raise KeyboardInterrupt
except KeyboardInterrupt: pass
diff --git a/Lib/test/test_opcodes.py b/Lib/test/test_opcodes.py
index 0ee51a8..d65c5cc 100644
--- a/Lib/test/test_opcodes.py
+++ b/Lib/test/test_opcodes.py
@@ -46,14 +46,10 @@ class OpcodeTest(unittest.TestCase):
a = AClass()
b = BClass()
- try: raise AClass, b
- except BClass as v:
- if v != b: self.fail("v!=b")
- else: self.fail("no exception")
-
- try: raise b
+ try:
+ raise b
except AClass as v:
- if v != b: self.fail("v!=b AClass")
+ self.assertEqual(v, b)
else:
self.fail("no exception")
@@ -62,7 +58,7 @@ class OpcodeTest(unittest.TestCase):
##except TypeError: pass
##else: self.fail("no exception")
- try: raise DClass, a
+ try: raise DClass(a)
except DClass as v:
self.assert_(isinstance(v, DClass))
else:
diff --git a/Lib/test/test_raise.py b/Lib/test/test_raise.py
new file mode 100644
index 0000000..ac0a32b
--- /dev/null
+++ b/Lib/test/test_raise.py
@@ -0,0 +1,417 @@
+# Copyright 2007 Google, Inc. All Rights Reserved.
+# Licensed to PSF under a Contributor Agreement.
+
+"""Tests for the raise statement."""
+
+from test import test_support
+import sys
+import types
+import unittest
+
+
+def get_tb():
+ try:
+ raise OSError()
+ except:
+ return sys.exc_info()[2]
+
+
+class TestRaise(unittest.TestCase):
+ def test_invalid_reraise(self):
+ try:
+ raise
+ except RuntimeError as e:
+ self.failUnless("No active exception" in str(e))
+ else:
+ self.fail("No exception raised")
+
+ def test_reraise(self):
+ try:
+ try:
+ raise IndexError()
+ except IndexError as e:
+ exc1 = e
+ raise
+ except IndexError as exc2:
+ self.failUnless(exc1 is exc2)
+ else:
+ self.fail("No exception raised")
+
+
+class TestCause(unittest.TestCase):
+ def test_invalid_cause(self):
+ try:
+ raise IndexError from 5
+ except TypeError as e:
+ self.failUnless("exception cause" in str(e))
+ else:
+ self.fail("No exception raised")
+
+ def test_class_cause(self):
+ try:
+ raise IndexError from KeyError
+ except IndexError as e:
+ self.failUnless(isinstance(e.__cause__, KeyError))
+ else:
+ self.fail("No exception raised")
+
+ def test_instance_cause(self):
+ cause = KeyError()
+ try:
+ raise IndexError from cause
+ except IndexError as e:
+ self.failUnless(e.__cause__ is cause)
+ else:
+ self.fail("No exception raised")
+
+
+class TestTraceback(unittest.TestCase):
+ def test_sets_traceback(self):
+ try:
+ raise IndexError()
+ except IndexError as e:
+ self.failUnless(isinstance(e.__traceback__, types.TracebackType))
+ else:
+ self.fail("No exception raised")
+
+ def test_accepts_traceback(self):
+ tb = get_tb()
+ try:
+ raise IndexError().with_traceback(tb)
+ except IndexError as e:
+ self.assertNotEqual(e.__traceback__, tb)
+ self.assertEqual(e.__traceback__.tb_next, tb)
+ else:
+ self.fail("No exception raised")
+
+
+# Disabled until context is implemented
+# class TestContext(object):
+# def test_instance_context_bare_raise(self):
+# context = IndexError()
+# try:
+# try:
+# raise context
+# except:
+# raise OSError()
+# except OSError as e:
+# self.assertEqual(e.__context__, context)
+# else:
+# self.fail("No exception raised")
+#
+# def test_class_context_bare_raise(self):
+# context = IndexError
+# try:
+# try:
+# raise context
+# except:
+# raise OSError()
+# except OSError as e:
+# self.assertNotEqual(e.__context__, context)
+# self.failUnless(isinstance(e.__context__, context))
+# else:
+# self.fail("No exception raised")
+
+
+class TestRemovedFunctionality(unittest.TestCase):
+ def test_tuples(self):
+ try:
+ raise (IndexError, KeyError) # This should be a tuple!
+ except TypeError:
+ pass
+ else:
+ self.fail("No exception raised")
+
+ def test_strings(self):
+ try:
+ raise "foo"
+ except TypeError:
+ pass
+ else:
+ self.fail("No exception raised")
+
+
+def test_main():
+ test_support.run_unittest(__name__)
+
+
+if __name__ == "__main__":
+ unittest.main()
+# Copyright 2007 Google, Inc. All Rights Reserved.
+# Licensed to PSF under a Contributor Agreement.
+
+"""Tests for the raise statement."""
+
+from test import test_support
+import sys
+import types
+import unittest
+
+
+def get_tb():
+ try:
+ raise OSError()
+ except:
+ return sys.exc_info()[2]
+
+
+class TestRaise(unittest.TestCase):
+ def test_invalid_reraise(self):
+ try:
+ raise
+ except RuntimeError as e:
+ self.failUnless("No active exception" in str(e))
+ else:
+ self.fail("No exception raised")
+
+ def test_reraise(self):
+ try:
+ try:
+ raise IndexError()
+ except IndexError as e:
+ exc1 = e
+ raise
+ except IndexError as exc2:
+ self.failUnless(exc1 is exc2)
+ else:
+ self.fail("No exception raised")
+
+
+class TestCause(unittest.TestCase):
+ def test_invalid_cause(self):
+ try:
+ raise IndexError from 5
+ except TypeError as e:
+ self.failUnless("exception cause" in str(e))
+ else:
+ self.fail("No exception raised")
+
+ def test_class_cause(self):
+ try:
+ raise IndexError from KeyError
+ except IndexError as e:
+ self.failUnless(isinstance(e.__cause__, KeyError))
+ else:
+ self.fail("No exception raised")
+
+ def test_instance_cause(self):
+ cause = KeyError()
+ try:
+ raise IndexError from cause
+ except IndexError as e:
+ self.failUnless(e.__cause__ is cause)
+ else:
+ self.fail("No exception raised")
+
+
+class TestTraceback(unittest.TestCase):
+ def test_sets_traceback(self):
+ try:
+ raise IndexError()
+ except IndexError as e:
+ self.failUnless(isinstance(e.__traceback__, types.TracebackType))
+ else:
+ self.fail("No exception raised")
+
+ def test_accepts_traceback(self):
+ tb = get_tb()
+ try:
+ raise IndexError().with_traceback(tb)
+ except IndexError as e:
+ self.assertNotEqual(e.__traceback__, tb)
+ self.assertEqual(e.__traceback__.tb_next, tb)
+ else:
+ self.fail("No exception raised")
+
+
+# Disabled until context is implemented
+# class TestContext(object):
+# def test_instance_context_bare_raise(self):
+# context = IndexError()
+# try:
+# try:
+# raise context
+# except:
+# raise OSError()
+# except OSError as e:
+# self.assertEqual(e.__context__, context)
+# else:
+# self.fail("No exception raised")
+#
+# def test_class_context_bare_raise(self):
+# context = IndexError
+# try:
+# try:
+# raise context
+# except:
+# raise OSError()
+# except OSError as e:
+# self.assertNotEqual(e.__context__, context)
+# self.failUnless(isinstance(e.__context__, context))
+# else:
+# self.fail("No exception raised")
+
+
+class TestRemovedFunctionality(unittest.TestCase):
+ def test_tuples(self):
+ try:
+ raise (IndexError, KeyError) # This should be a tuple!
+ except TypeError:
+ pass
+ else:
+ self.fail("No exception raised")
+
+ def test_strings(self):
+ try:
+ raise "foo"
+ except TypeError:
+ pass
+ else:
+ self.fail("No exception raised")
+
+
+def test_main():
+ test_support.run_unittest(__name__)
+
+
+if __name__ == "__main__":
+ unittest.main()
+# Copyright 2007 Google, Inc. All Rights Reserved.
+# Licensed to PSF under a Contributor Agreement.
+
+"""Tests for the raise statement."""
+
+from test import test_support
+import sys
+import types
+import unittest
+
+
+def get_tb():
+ try:
+ raise OSError()
+ except:
+ return sys.exc_info()[2]
+
+
+class TestRaise(unittest.TestCase):
+ def test_invalid_reraise(self):
+ try:
+ raise
+ except RuntimeError as e:
+ self.failUnless("No active exception" in str(e))
+ else:
+ self.fail("No exception raised")
+
+ def test_reraise(self):
+ try:
+ try:
+ raise IndexError()
+ except IndexError as e:
+ exc1 = e
+ raise
+ except IndexError as exc2:
+ self.failUnless(exc1 is exc2)
+ else:
+ self.fail("No exception raised")
+
+
+class TestCause(unittest.TestCase):
+ def test_invalid_cause(self):
+ try:
+ raise IndexError from 5
+ except TypeError as e:
+ self.failUnless("exception cause" in str(e))
+ else:
+ self.fail("No exception raised")
+
+ def test_class_cause(self):
+ try:
+ raise IndexError from KeyError
+ except IndexError as e:
+ self.failUnless(isinstance(e.__cause__, KeyError))
+ else:
+ self.fail("No exception raised")
+
+ def test_instance_cause(self):
+ cause = KeyError()
+ try:
+ raise IndexError from cause
+ except IndexError as e:
+ self.failUnless(e.__cause__ is cause)
+ else:
+ self.fail("No exception raised")
+
+
+class TestTraceback(unittest.TestCase):
+ def test_sets_traceback(self):
+ try:
+ raise IndexError()
+ except IndexError as e:
+ self.failUnless(isinstance(e.__traceback__, types.TracebackType))
+ else:
+ self.fail("No exception raised")
+
+ def test_accepts_traceback(self):
+ tb = get_tb()
+ try:
+ raise IndexError().with_traceback(tb)
+ except IndexError as e:
+ self.assertNotEqual(e.__traceback__, tb)
+ self.assertEqual(e.__traceback__.tb_next, tb)
+ else:
+ self.fail("No exception raised")
+
+
+# Disabled until context is implemented
+# class TestContext(object):
+# def test_instance_context_bare_raise(self):
+# context = IndexError()
+# try:
+# try:
+# raise context
+# except:
+# raise OSError()
+# except OSError as e:
+# self.assertEqual(e.__context__, context)
+# else:
+# self.fail("No exception raised")
+#
+# def test_class_context_bare_raise(self):
+# context = IndexError
+# try:
+# try:
+# raise context
+# except:
+# raise OSError()
+# except OSError as e:
+# self.assertNotEqual(e.__context__, context)
+# self.failUnless(isinstance(e.__context__, context))
+# else:
+# self.fail("No exception raised")
+
+
+class TestRemovedFunctionality(unittest.TestCase):
+ def test_tuples(self):
+ try:
+ raise (IndexError, KeyError) # This should be a tuple!
+ except TypeError:
+ pass
+ else:
+ self.fail("No exception raised")
+
+ def test_strings(self):
+ try:
+ raise "foo"
+ except TypeError:
+ pass
+ else:
+ self.fail("No exception raised")
+
+
+def test_main():
+ test_support.run_unittest(__name__)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py
index 4297d22..546f7a8 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -460,6 +460,16 @@ leading to spurious errors.
...
SyntaxError: can't assign to function call
+Make sure that the old "raise X, Y[, Z]" form is gone:
+ >>> raise X, Y
+ Traceback (most recent call last):
+ ...
+ SyntaxError: invalid syntax
+ >>> raise X, Y, Z
+ Traceback (most recent call last):
+ ...
+ SyntaxError: invalid syntax
+
"""
import re
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index d9adf02..e737047 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -119,11 +119,6 @@ class SysModuleTest(unittest.TestCase):
# test that the exit machinery handles SystemExits properly
import subprocess
- # both unnormalized...
- rc = subprocess.call([sys.executable, "-c",
- "raise SystemExit, 46"])
- self.assertEqual(rc, 46)
- # ... and normalized
rc = subprocess.call([sys.executable, "-c",
"raise SystemExit(47)"])
self.assertEqual(rc, 47)
diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py
index 3f1d358..4fc8fe9 100644
--- a/Lib/test/test_with.py
+++ b/Lib/test/test_with.py
@@ -87,7 +87,7 @@ class Nested(object):
ex = sys.exc_info()
self.entered = None
if ex is not exc_info:
- raise ex[0], ex[1], ex[2]
+ raise ex[0](ex[1]).with_traceback(ex[2])
class MockNested(Nested):
diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py
index f38983f..58935b7 100644
--- a/Lib/test/test_zipimport.py
+++ b/Lib/test/test_zipimport.py
@@ -244,7 +244,7 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase):
def get_file():
return __file__
if __loader__.get_data("some.data") != b"some data":
- raise AssertionError, "bad data"\n"""
+ raise AssertionError("bad data")\n"""
pyc = make_pyc(compile(src, "<???>", "exec"), NOW)
files = {TESTMOD + pyc_ext: (NOW, pyc),
"some.data": (NOW, "some data")}
diff --git a/Lib/urllib.py b/Lib/urllib.py
index 67f457d..a1e26f0 100644
--- a/Lib/urllib.py
+++ b/Lib/urllib.py
@@ -199,7 +199,7 @@ class URLopener:
else:
return getattr(self, name)(url, data)
except socket.error as msg:
- raise IOError, ('socket error', msg), sys.exc_info()[2]
+ raise IOError('socket error', msg).with_traceback(sys.exc_info()[2])
def open_unknown(self, fullurl, data=None):
"""Overridable interface to open unknown URL type."""
@@ -498,7 +498,7 @@ class URLopener:
headers = mimetools.Message(StringIO(headers))
return addinfourl(fp, headers, "ftp:" + url)
except ftperrors() as msg:
- raise IOError, ('ftp error', msg), sys.exc_info()[2]
+ raise IOError('ftp error', msg).with_traceback(sys.exc_info()[2])
def open_data(self, url, data=None):
"""Use "data" URL."""
@@ -809,7 +809,7 @@ class ftpwrapper:
conn = self.ftp.ntransfercmd(cmd)
except ftplib.error_perm as reason:
if str(reason)[:3] != '550':
- raise IOError, ('ftp error', reason), sys.exc_info()[2]
+ raise IOError('ftp error', reason).with_traceback(sys.exc_info()[2])
if not conn:
# Set transfer mode to ASCII!
self.ftp.voidcmd('TYPE A')
@@ -1186,7 +1186,7 @@ def urlencode(query,doseq=0):
# preserved for consistency
except TypeError:
ty,va,tb = sys.exc_info()
- raise TypeError, "not a valid non-string sequence or mapping object", tb
+ raise TypeError("not a valid non-string sequence or mapping object").with_traceback(tb)
l = []
if not doseq:
diff --git a/Lib/urllib2.py b/Lib/urllib2.py
index 72e2899..58e0153 100644
--- a/Lib/urllib2.py
+++ b/Lib/urllib2.py
@@ -1286,7 +1286,7 @@ class FTPHandler(BaseHandler):
headers = mimetools.Message(sf)
return addinfourl(fp, headers, req.get_full_url())
except ftplib.all_errors as msg:
- raise IOError, ('ftp error', msg), sys.exc_info()[2]
+ raise IOError('ftp error', msg).with_traceback(sys.exc_info()[2])
def connect_ftp(self, user, passwd, host, port, dirs, timeout):
fw = ftpwrapper(user, passwd, host, port, dirs, timeout)
diff --git a/Lib/wsgiref/handlers.py b/Lib/wsgiref/handlers.py
index d9347e5..8231620 100644
--- a/Lib/wsgiref/handlers.py
+++ b/Lib/wsgiref/handlers.py
@@ -151,7 +151,7 @@ class BaseHandler:
try:
if self.headers_sent:
# Re-raise original exception if headers sent
- raise exc_info[0], exc_info[1], exc_info[2]
+ raise exc_info[0](exc_info[1]).with_traceback(exc_info[2])
finally:
exc_info = None # avoid dangling circular ref
elif self.headers is not None:
diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py
index c7ebce8..0b62ea6 100755
--- a/Mac/BuildScript/build-installer.py
+++ b/Mac/BuildScript/build-installer.py
@@ -54,7 +54,7 @@ def getFullVersion():
if 'PY_VERSION' in ln:
return ln.split()[-1][1:-1]
- raise RuntimeError, "Cannot find full version??"
+ raise RuntimeError("Cannot find full version??")
# The directory we'll use to create the build (will be erased and recreated)
WORKDIR = "/tmp/_py"
@@ -291,7 +291,7 @@ def runCommand(commandline):
xit = fd.close()
if xit != None:
sys.stdout.write(data)
- raise RuntimeError, "command failed: %s"%(commandline,)
+ raise RuntimeError("command failed: %s"%(commandline,))
if VERBOSE:
sys.stdout.write(data); sys.stdout.flush()
@@ -302,7 +302,7 @@ def captureCommand(commandline):
xit = fd.close()
if xit != None:
sys.stdout.write(data)
- raise RuntimeError, "command failed: %s"%(commandline,)
+ raise RuntimeError("command failed: %s"%(commandline,))
return data
@@ -361,7 +361,7 @@ def parseOptions(args=None):
SRCDIR=v
else:
- raise NotImplementedError, k
+ raise NotImplementedError(k)
SRCDIR=os.path.abspath(SRCDIR)
WORKDIR=os.path.abspath(WORKDIR)
@@ -418,7 +418,7 @@ def extractArchive(builddir, archiveName):
xit = fp.close()
if xit is not None:
sys.stdout.write(data)
- raise RuntimeError, "Cannot extract %s"%(archiveName,)
+ raise RuntimeError("Cannot extract %s"%(archiveName,))
return os.path.join(builddir, retval)
diff --git a/Mac/Tools/Doc/setup.py b/Mac/Tools/Doc/setup.py
index 5f60c51..e1d8fb1 100644
--- a/Mac/Tools/Doc/setup.py
+++ b/Mac/Tools/Doc/setup.py
@@ -59,7 +59,7 @@ class DocBuild(build):
dirname = 'Python-Docs-%s' % self.doc_version
if os.path.exists(self.build_html):
- raise RuntimeError, '%s: already exists, please remove and try again' % self.build_html
+ raise RuntimeError('%s: already exists, please remove and try again' % self.build_html)
os.chdir(self.build_base)
self.spawn('curl','-O', url)
self.spawn('tar', '-xjf', tarfile)
@@ -146,8 +146,7 @@ class DocBuild(build):
self.mkpath(self.build_base)
self.ensureHtml()
if not os.path.isdir(self.build_html):
- raise RuntimeError, \
- "Can't find source folder for documentation."
+ raise RuntimeError("Can't find source folder for documentation.")
self.mkpath(self.build_dest)
if dep_util.newer(os.path.join(self.build_html,'index.html'), os.path.join(self.build_dest,'index.html')):
self.mkpath(self.build_dest)
diff --git a/Mac/scripts/buildpkg.py b/Mac/scripts/buildpkg.py
index 73dd4b6..ad0afe4 100644
--- a/Mac/scripts/buildpkg.py
+++ b/Mac/scripts/buildpkg.py
@@ -194,7 +194,7 @@ class PackageMaker:
if k in fields:
self.packageInfo[k] = v
elif not k in ["OutputDir"]:
- raise Error, "Unknown package option: %s" % k
+ raise Error("Unknown package option: %s" % k)
# Check where we should leave the output. Default is current directory
outputdir = options.get("OutputDir", os.getcwd())
diff --git a/Mac/scripts/mkestrres.py b/Mac/scripts/mkestrres.py
index d423892..93af56e 100644
--- a/Mac/scripts/mkestrres.py
+++ b/Mac/scripts/mkestrres.py
@@ -33,7 +33,7 @@ ERRORS_PROG_2="[ \t]*" \
def Pstring(str):
if len(str) > 255:
- raise ValueError, 'String too large'
+ raise ValueError('String too large')
return chr(len(str))+str
def writeestr(dst, edict):
diff --git a/Objects/exceptions.c b/Objects/exceptions.c
index e900243..cbc41e8 100644
--- a/Objects/exceptions.c
+++ b/Objects/exceptions.c
@@ -28,6 +28,7 @@ BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
/* the dict is created on the fly in PyObject_GenericSetAttr */
self->dict = NULL;
+ self->traceback = NULL;
self->args = PyTuple_New(0);
if (!self->args) {
@@ -56,6 +57,7 @@ BaseException_clear(PyBaseExceptionObject *self)
{
Py_CLEAR(self->dict);
Py_CLEAR(self->args);
+ Py_CLEAR(self->traceback);
return 0;
}
@@ -72,6 +74,7 @@ BaseException_traverse(PyBaseExceptionObject *self, visitproc visit, void *arg)
{
Py_VISIT(self->dict);
Py_VISIT(self->args);
+ Py_VISIT(self->traceback);
return 0;
}
@@ -135,10 +138,20 @@ BaseException_setstate(PyObject *self, PyObject *state)
Py_RETURN_NONE;
}
+static PyObject *
+BaseException_with_traceback(PyObject *self, PyObject *tb) {
+ if (PyException_SetTraceback(self, tb))
+ return NULL;
+
+ Py_INCREF(self);
+ return self;
+}
+
static PyMethodDef BaseException_methods[] = {
{"__reduce__", (PyCFunction)BaseException_reduce, METH_NOARGS },
{"__setstate__", (PyCFunction)BaseException_setstate, METH_O },
+ {"with_traceback", (PyCFunction)BaseException_with_traceback, METH_O },
{NULL, NULL, 0, NULL},
};
@@ -198,14 +211,97 @@ BaseException_set_args(PyBaseExceptionObject *self, PyObject *val)
return 0;
}
+static PyObject *
+BaseException_get_tb(PyBaseExceptionObject *self)
+{
+ if (self->traceback == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ Py_INCREF(self->traceback);
+ return self->traceback;
+}
+
+static int
+BaseException_set_tb(PyBaseExceptionObject *self, PyObject *tb)
+{
+ if (tb == NULL) {
+ PyErr_SetString(PyExc_TypeError, "__traceback__ may not be deleted");
+ return -1;
+ }
+ else if (!(tb == Py_None || PyTraceBack_Check(tb))) {
+ PyErr_SetString(PyExc_TypeError,
+ "__traceback__ must be a traceback or None");
+ return -1;
+ }
+
+ Py_XINCREF(tb);
+ Py_XDECREF(self->traceback);
+ self->traceback = tb;
+ return 0;
+}
+
static PyGetSetDef BaseException_getset[] = {
{"__dict__", (getter)BaseException_get_dict, (setter)BaseException_set_dict},
{"args", (getter)BaseException_get_args, (setter)BaseException_set_args},
+ {"__traceback__", (getter)BaseException_get_tb, (setter)BaseException_set_tb},
{NULL},
};
+PyObject *
+PyException_GetTraceback(PyObject *self) {
+ PyBaseExceptionObject *base_self = (PyBaseExceptionObject *)self;
+ Py_XINCREF(base_self->traceback);
+ return base_self->traceback;
+}
+
+
+int
+PyException_SetTraceback(PyObject *self, PyObject *tb) {
+ return BaseException_set_tb((PyBaseExceptionObject *)self, tb);
+}
+
+PyObject *
+PyException_GetCause(PyObject *self) {
+ PyObject *cause = ((PyBaseExceptionObject *)self)->cause;
+ Py_XINCREF(cause);
+ return cause;
+}
+
+/* Steals a reference to cause */
+void
+PyException_SetCause(PyObject *self, PyObject *cause) {
+ PyObject *old_cause = ((PyBaseExceptionObject *)self)->cause;
+ ((PyBaseExceptionObject *)self)->cause = cause;
+ Py_XDECREF(old_cause);
+}
+
+PyObject *
+PyException_GetContext(PyObject *self) {
+ PyObject *context = ((PyBaseExceptionObject *)self)->context;
+ Py_XINCREF(context);
+ return context;
+}
+
+/* Steals a reference to context */
+void
+PyException_SetContext(PyObject *self, PyObject *context) {
+ PyObject *old_context = ((PyBaseExceptionObject *)self)->context;
+ ((PyBaseExceptionObject *)self)->context = context;
+ Py_XDECREF(old_context);
+}
+
+
+static PyMemberDef BaseException_members[] = {
+ {"__context__", T_OBJECT, offsetof(PyBaseExceptionObject, context), 0,
+ PyDoc_STR("exception context")},
+ {"__cause__", T_OBJECT, offsetof(PyBaseExceptionObject, cause), 0,
+ PyDoc_STR("exception cause")},
+ {NULL} /* Sentinel */
+};
+
static PyTypeObject _PyExc_BaseException = {
PyVarObject_HEAD_INIT(NULL, 0)
"BaseException", /*tp_name*/
@@ -236,7 +332,7 @@ static PyTypeObject _PyExc_BaseException = {
0, /* tp_iter */
0, /* tp_iternext */
BaseException_methods, /* tp_methods */
- 0, /* tp_members */
+ BaseException_members, /* tp_members */
BaseException_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
diff --git a/Parser/Python.asdl b/Parser/Python.asdl
index ea9f502..8686709 100644
--- a/Parser/Python.asdl
+++ b/Parser/Python.asdl
@@ -30,8 +30,7 @@ module Python version "$Revision$"
| If(expr test, stmt* body, stmt* orelse)
| With(expr context_expr, expr? optional_vars, stmt* body)
- -- 'type' is a bad name
- | Raise(expr? type, expr? inst, expr? tback)
+ | Raise(expr? exc, expr? cause)
| TryExcept(stmt* body, excepthandler* handlers, stmt* orelse)
| TryFinally(stmt* body, stmt* finalbody)
| Assert(expr test, expr? msg)
diff --git a/Python/Python-ast.c b/Python/Python-ast.c
index 605a152..9089b9a 100644
--- a/Python/Python-ast.c
+++ b/Python/Python-ast.c
@@ -2,7 +2,7 @@
/*
- __version__ 56266.
+ __version__ 465.
This module must be committed separately after each AST grammar change;
The __version__ number is set to the revision number of the commit
@@ -101,9 +101,8 @@ static char *With_fields[]={
};
static PyTypeObject *Raise_type;
static char *Raise_fields[]={
- "type",
- "inst",
- "tback",
+ "exc",
+ "cause",
};
static PyTypeObject *TryExcept_type;
static char *TryExcept_fields[]={
@@ -510,7 +509,7 @@ static int init_types(void)
if (!If_type) return 0;
With_type = make_type("With", stmt_type, With_fields, 3);
if (!With_type) return 0;
- Raise_type = make_type("Raise", stmt_type, Raise_fields, 3);
+ Raise_type = make_type("Raise", stmt_type, Raise_fields, 2);
if (!Raise_type) return 0;
TryExcept_type = make_type("TryExcept", stmt_type, TryExcept_fields, 3);
if (!TryExcept_type) return 0;
@@ -1052,17 +1051,15 @@ With(expr_ty context_expr, expr_ty optional_vars, asdl_seq * body, int lineno,
}
stmt_ty
-Raise(expr_ty type, expr_ty inst, expr_ty tback, int lineno, int col_offset,
- PyArena *arena)
+Raise(expr_ty exc, expr_ty cause, int lineno, int col_offset, PyArena *arena)
{
stmt_ty p;
p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = Raise_kind;
- p->v.Raise.type = type;
- p->v.Raise.inst = inst;
- p->v.Raise.tback = tback;
+ p->v.Raise.exc = exc;
+ p->v.Raise.cause = cause;
p->lineno = lineno;
p->col_offset = col_offset;
return p;
@@ -2221,19 +2218,14 @@ ast2obj_stmt(void* _o)
case Raise_kind:
result = PyType_GenericNew(Raise_type, NULL, NULL);
if (!result) goto failed;
- value = ast2obj_expr(o->v.Raise.type);
- if (!value) goto failed;
- if (PyObject_SetAttrString(result, "type", value) == -1)
- goto failed;
- Py_DECREF(value);
- value = ast2obj_expr(o->v.Raise.inst);
+ value = ast2obj_expr(o->v.Raise.exc);
if (!value) goto failed;
- if (PyObject_SetAttrString(result, "inst", value) == -1)
+ if (PyObject_SetAttrString(result, "exc", value) == -1)
goto failed;
Py_DECREF(value);
- value = ast2obj_expr(o->v.Raise.tback);
+ value = ast2obj_expr(o->v.Raise.cause);
if (!value) goto failed;
- if (PyObject_SetAttrString(result, "tback", value) == -1)
+ if (PyObject_SetAttrString(result, "cause", value) == -1)
goto failed;
Py_DECREF(value);
break;
@@ -3179,7 +3171,7 @@ init_ast(void)
if (PyDict_SetItemString(d, "AST", (PyObject*)AST_type) < 0) return;
if (PyModule_AddIntConstant(m, "PyCF_ONLY_AST", PyCF_ONLY_AST) < 0)
return;
- if (PyModule_AddStringConstant(m, "__version__", "56266") < 0)
+ if (PyModule_AddStringConstant(m, "__version__", "465") < 0)
return;
if (PyDict_SetItemString(d, "mod", (PyObject*)mod_type) < 0) return;
if (PyDict_SetItemString(d, "Module", (PyObject*)Module_type) < 0)
diff --git a/Python/ast.c b/Python/ast.c
index c13d093..8dd3c4ab 100644
--- a/Python/ast.c
+++ b/Python/ast.c
@@ -2199,39 +2199,18 @@ ast_for_flow_stmt(struct compiling *c, const node *n)
}
case raise_stmt:
if (NCH(ch) == 1)
- return Raise(NULL, NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena);
- else if (NCH(ch) == 2) {
+ return Raise(NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena);
+ else if (NCH(ch) >= 2) {
+ expr_ty cause = NULL;
expr_ty expression = ast_for_expr(c, CHILD(ch, 1));
if (!expression)
return NULL;
- return Raise(expression, NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena);
- }
- else if (NCH(ch) == 4) {
- expr_ty expr1, expr2;
-
- expr1 = ast_for_expr(c, CHILD(ch, 1));
- if (!expr1)
- return NULL;
- expr2 = ast_for_expr(c, CHILD(ch, 3));
- if (!expr2)
- return NULL;
-
- return Raise(expr1, expr2, NULL, LINENO(n), n->n_col_offset, c->c_arena);
- }
- else if (NCH(ch) == 6) {
- expr_ty expr1, expr2, expr3;
-
- expr1 = ast_for_expr(c, CHILD(ch, 1));
- if (!expr1)
- return NULL;
- expr2 = ast_for_expr(c, CHILD(ch, 3));
- if (!expr2)
- return NULL;
- expr3 = ast_for_expr(c, CHILD(ch, 5));
- if (!expr3)
- return NULL;
-
- return Raise(expr1, expr2, expr3, LINENO(n), n->n_col_offset, c->c_arena);
+ if (NCH(ch) == 4) {
+ cause = ast_for_expr(c, CHILD(ch, 3));
+ if (!cause)
+ return NULL;
+ }
+ return Raise(expression, cause, LINENO(n), n->n_col_offset, c->c_arena);
}
default:
PyErr_Format(PyExc_SystemError,
diff --git a/Python/ceval.c b/Python/ceval.c
index be804ad..24d4dec 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -484,7 +484,7 @@ enum why_code {
WHY_YIELD = 0x0040 /* 'yield' operator */
};
-static enum why_code do_raise(PyObject *, PyObject *, PyObject *);
+static enum why_code do_raise(PyObject *, PyObject *);
static int unpack_iterable(PyObject *, int, int, PyObject **);
/* for manipulating the thread switch and periodic "stuff" - used to be
@@ -1465,18 +1465,14 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
default: switch (opcode) {
#endif
case RAISE_VARARGS:
- u = v = w = NULL;
+ v = w = NULL;
switch (oparg) {
- case 3:
- u = POP(); /* traceback */
- /* Fallthrough */
- case 2:
- v = POP(); /* value */
- /* Fallthrough */
+ case 2:
+ v = POP(); /* cause */
case 1:
w = POP(); /* exc */
case 0: /* Fallthrough */
- why = do_raise(w, v, u);
+ why = do_raise(w, v);
break;
default:
PyErr_SetString(PyExc_SystemError,
@@ -2880,6 +2876,7 @@ set_exc_info(PyThreadState *tstate,
tstate->exc_type = type;
tstate->exc_value = value;
tstate->exc_traceback = tb;
+ PyException_SetTraceback(value, tb);
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
@@ -2928,95 +2925,78 @@ reset_exc_info(PyThreadState *tstate)
/* Logic for the raise statement (too complicated for inlining).
This *consumes* a reference count to each of its arguments. */
static enum why_code
-do_raise(PyObject *type, PyObject *value, PyObject *tb)
+do_raise(PyObject *exc, PyObject *cause)
{
- if (type == NULL) {
+ PyObject *type = NULL, *value = NULL, *tb = NULL;
+
+ if (exc == NULL) {
/* Reraise */
PyThreadState *tstate = PyThreadState_GET();
- type = tstate->exc_type == NULL ? Py_None : tstate->exc_type;
+ type = tstate->exc_type;
value = tstate->exc_value;
tb = tstate->exc_traceback;
- Py_XINCREF(type);
+ if (type == Py_None) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "No active exception to reraise");
+ return WHY_EXCEPTION;
+ }
+ Py_XINCREF(type);
Py_XINCREF(value);
Py_XINCREF(tb);
+ PyErr_Restore(type, value, tb);
+ return WHY_RERAISE;
}
/* We support the following forms of raise:
- raise <class>, <classinstance>
- raise <class>, <argument tuple>
- raise <class>, None
- raise <class>, <argument>
- raise <classinstance>, None
- raise <string>, <object>
- raise <string>, None
-
- An omitted second argument is the same as None.
-
- In addition, raise <tuple>, <anything> is the same as
- raising the tuple's first item (and it better have one!);
- this rule is applied recursively.
-
- Finally, an optional third argument can be supplied, which
- gives the traceback to be substituted (useful when
- re-raising an exception after examining it). */
-
- /* First, check the traceback argument, replacing None with
- NULL. */
- if (tb == Py_None) {
- Py_DECREF(tb);
- tb = NULL;
- }
- else if (tb != NULL && !PyTraceBack_Check(tb)) {
- PyErr_SetString(PyExc_TypeError,
- "raise: arg 3 must be a traceback or None");
- goto raise_error;
- }
-
- /* Next, replace a missing value with None */
- if (value == NULL) {
- value = Py_None;
- Py_INCREF(value);
- }
+ raise
+ raise <instance>
+ raise <type> */
- /* Next, repeatedly, replace a tuple exception with its first item */
- while (PyTuple_Check(type) && PyTuple_Size(type) > 0) {
- PyObject *tmp = type;
- type = PyTuple_GET_ITEM(type, 0);
+ if (PyExceptionClass_Check(exc)) {
+ type = exc;
+ value = PyObject_CallObject(exc, NULL);
+ if (value == NULL)
+ goto raise_error;
+ }
+ else if (PyExceptionInstance_Check(exc)) {
+ value = exc;
+ type = PyExceptionInstance_Class(exc);
Py_INCREF(type);
- Py_DECREF(tmp);
- }
-
- if (PyExceptionClass_Check(type))
- PyErr_NormalizeException(&type, &value, &tb);
-
- else if (PyExceptionInstance_Check(type)) {
- /* Raising an instance. The value should be a dummy. */
- if (value != Py_None) {
- PyErr_SetString(PyExc_TypeError,
- "instance exception may not have a separate value");
- goto raise_error;
- }
- else {
- /* Normalize to raise <class>, <instance> */
- Py_DECREF(value);
- value = type;
- type = PyExceptionInstance_Class(type);
- Py_INCREF(type);
- }
}
else {
/* Not something you can raise. You get an exception
anyway, just not what you specified :-) */
+ Py_DECREF(exc);
+ Py_XDECREF(cause);
PyErr_SetString(PyExc_TypeError,
"exceptions must derive from BaseException");
goto raise_error;
}
+
+ tb = PyException_GetTraceback(value);
+ if (cause) {
+ PyObject *fixed_cause;
+ if (PyExceptionClass_Check(cause)) {
+ fixed_cause = PyObject_CallObject(cause, NULL);
+ if (fixed_cause == NULL)
+ goto raise_error;
+ }
+ else if (PyExceptionInstance_Check(cause)) {
+ fixed_cause = cause;
+ }
+ else {
+ Py_DECREF(cause);
+ PyErr_SetString(PyExc_TypeError,
+ "exception causes must derive from BaseException");
+ goto raise_error;
+ }
+ PyException_SetCause(value, fixed_cause);
+ }
+
PyErr_Restore(type, value, tb);
- if (tb == NULL)
- return WHY_EXCEPTION;
- else
- return WHY_RERAISE;
- raise_error:
+ return WHY_EXCEPTION;
+
+raise_error:
Py_XDECREF(value);
Py_XDECREF(type);
Py_XDECREF(tb);
diff --git a/Python/compile.c b/Python/compile.c
index 3a21127..e569102 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -2187,11 +2187,9 @@ compiler_assert(struct compiler *c, stmt_ty s)
ADDOP_O(c, LOAD_GLOBAL, assertion_error, names);
if (s->v.Assert.msg) {
VISIT(c, expr, s->v.Assert.msg);
- ADDOP_I(c, RAISE_VARARGS, 2);
- }
- else {
- ADDOP_I(c, RAISE_VARARGS, 1);
+ ADDOP_I(c, CALL_FUNCTION, 1);
}
+ ADDOP_I(c, RAISE_VARARGS, 1);
compiler_use_next_block(c, end);
ADDOP(c, POP_TOP);
return 1;
@@ -2244,17 +2242,13 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s)
return compiler_if(c, s);
case Raise_kind:
n = 0;
- if (s->v.Raise.type) {
- VISIT(c, expr, s->v.Raise.type);
+ if (s->v.Raise.exc) {
+ VISIT(c, expr, s->v.Raise.exc);
n++;
- if (s->v.Raise.inst) {
- VISIT(c, expr, s->v.Raise.inst);
- n++;
- if (s->v.Raise.tback) {
- VISIT(c, expr, s->v.Raise.tback);
- n++;
- }
- }
+ if (s->v.Raise.cause) {
+ VISIT(c, expr, s->v.Raise.cause);
+ n++;
+ }
}
ADDOP_I(c, RAISE_VARARGS, n);
break;
diff --git a/Python/graminit.c b/Python/graminit.c
index 95905d7..081a072 100644
--- a/Python/graminit.c
+++ b/Python/graminit.c
@@ -503,34 +503,25 @@ static arc arcs_24_1[2] = {
{0, 1},
};
static arc arcs_24_2[2] = {
- {30, 3},
+ {71, 3},
{0, 2},
};
static arc arcs_24_3[1] = {
{24, 4},
};
-static arc arcs_24_4[2] = {
- {30, 5},
+static arc arcs_24_4[1] = {
{0, 4},
};
-static arc arcs_24_5[1] = {
- {24, 6},
-};
-static arc arcs_24_6[1] = {
- {0, 6},
-};
-static state states_24[7] = {
+static state states_24[5] = {
{1, arcs_24_0},
{2, arcs_24_1},
{2, arcs_24_2},
{1, arcs_24_3},
- {2, arcs_24_4},
- {1, arcs_24_5},
- {1, arcs_24_6},
+ {1, arcs_24_4},
};
static arc arcs_25_0[2] = {
- {71, 1},
{72, 1},
+ {73, 1},
};
static arc arcs_25_1[1] = {
{0, 1},
@@ -540,10 +531,10 @@ static state states_25[2] = {
{1, arcs_25_1},
};
static arc arcs_26_0[1] = {
- {73, 1},
+ {74, 1},
};
static arc arcs_26_1[1] = {
- {74, 2},
+ {75, 2},
};
static arc arcs_26_2[1] = {
{0, 2},
@@ -554,7 +545,7 @@ static state states_26[3] = {
{1, arcs_26_2},
};
static arc arcs_27_0[1] = {
- {75, 1},
+ {71, 1},
};
static arc arcs_27_1[3] = {
{76, 2},
@@ -565,10 +556,10 @@ static arc arcs_27_2[4] = {
{76, 2},
{77, 2},
{12, 3},
- {73, 4},
+ {74, 4},
};
static arc arcs_27_3[1] = {
- {73, 4},
+ {74, 4},
};
static arc arcs_27_4[3] = {
{31, 5},
@@ -1733,9 +1724,9 @@ static state states_80[3] = {
};
static dfa dfas[81] = {
{256, "single_input", 0, 3, states_0,
- "\004\050\060\200\000\000\000\050\170\052\034\144\011\040\004\000\200\041\224\017\101"},
+ "\004\050\060\200\000\000\000\050\370\044\034\144\011\040\004\000\200\041\224\017\101"},
{257, "file_input", 0, 2, states_1,
- "\204\050\060\200\000\000\000\050\170\052\034\144\011\040\004\000\200\041\224\017\101"},
+ "\204\050\060\200\000\000\000\050\370\044\034\144\011\040\004\000\200\041\224\017\101"},
{258, "eval_input", 0, 3, states_2,
"\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\200\041\224\017\000"},
{259, "decorator", 0, 7, states_3,
@@ -1757,11 +1748,11 @@ static dfa dfas[81] = {
{267, "vfpdef", 0, 2, states_11,
"\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
{268, "stmt", 0, 2, states_12,
- "\000\050\060\200\000\000\000\050\170\052\034\144\011\040\004\000\200\041\224\017\101"},
+ "\000\050\060\200\000\000\000\050\370\044\034\144\011\040\004\000\200\041\224\017\101"},
{269, "simple_stmt", 0, 4, states_13,
- "\000\040\040\200\000\000\000\050\170\052\034\000\000\040\004\000\200\041\224\017\100"},
+ "\000\040\040\200\000\000\000\050\370\044\034\000\000\040\004\000\200\041\224\017\100"},
{270, "small_stmt", 0, 2, states_14,
- "\000\040\040\200\000\000\000\050\170\052\034\000\000\040\004\000\200\041\224\017\100"},
+ "\000\040\040\200\000\000\000\050\370\044\034\000\000\040\004\000\200\041\224\017\100"},
{271, "expr_stmt", 0, 6, states_15,
"\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\200\041\224\017\000"},
{272, "augassign", 0, 2, states_16,
@@ -1780,14 +1771,14 @@ static dfa dfas[81] = {
"\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000"},
{279, "yield_stmt", 0, 2, states_23,
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\100"},
- {280, "raise_stmt", 0, 7, states_24,
+ {280, "raise_stmt", 0, 5, states_24,
"\000\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000\000\000\000\000"},
{281, "import_stmt", 0, 2, states_25,
- "\000\000\000\000\000\000\000\000\000\012\000\000\000\000\000\000\000\000\000\000\000"},
+ "\000\000\000\000\000\000\000\000\200\004\000\000\000\000\000\000\000\000\000\000\000"},
{282, "import_name", 0, 3, states_26,
- "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000"},
+ "\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000"},
{283, "import_from", 0, 8, states_27,
- "\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000\000\000"},
+ "\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000"},
{284, "import_as_name", 0, 4, states_28,
"\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
{285, "dotted_as_name", 0, 4, states_29,
@@ -1821,7 +1812,7 @@ static dfa dfas[81] = {
{299, "except_clause", 0, 5, states_43,
"\000\000\000\000\000\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000"},
{300, "suite", 0, 5, states_44,
- "\004\040\040\200\000\000\000\050\170\052\034\000\000\040\004\000\200\041\224\017\100"},
+ "\004\040\040\200\000\000\000\050\370\044\034\000\000\040\004\000\200\041\224\017\100"},
{301, "test", 0, 6, states_45,
"\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\200\041\224\017\000"},
{302, "test_nocond", 0, 2, states_46,
@@ -1967,11 +1958,11 @@ static label labels[167] = {
{1, "continue"},
{1, "return"},
{1, "raise"},
+ {1, "from"},
{282, 0},
{283, 0},
{1, "import"},
{287, 0},
- {1, "from"},
{23, 0},
{52, 0},
{286, 0},
diff --git a/Python/import.c b/Python/import.c
index 2ef6aec..33cafd0 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -74,6 +74,7 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *);
3040 (added signature annotations)
3050 (print becomes a function)
3060 (PEP 3115 metaclass syntax)
+ 3070 (PEP 3109 raise changes)
.
*/
#define MAGIC (3060 | ((long)'\r'<<16) | ((long)'\n'<<24))
diff --git a/Python/symtable.c b/Python/symtable.c
index 59eef02..83e571e 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -1101,13 +1101,11 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
VISIT_SEQ(st, stmt, s->v.If.orelse);
break;
case Raise_kind:
- if (s->v.Raise.type) {
- VISIT(st, expr, s->v.Raise.type);
- if (s->v.Raise.inst) {
- VISIT(st, expr, s->v.Raise.inst);
- if (s->v.Raise.tback)
- VISIT(st, expr, s->v.Raise.tback);
- }
+ if (s->v.Raise.exc) {
+ VISIT(st, expr, s->v.Raise.exc);
+ if (s->v.Raise.cause) {
+ VISIT(st, expr, s->v.Raise.cause);
+ }
}
break;
case TryExcept_kind:
diff --git a/Tools/webchecker/webchecker.py b/Tools/webchecker/webchecker.py
index 5b97851..6ad92b2 100755
--- a/Tools/webchecker/webchecker.py
+++ b/Tools/webchecker/webchecker.py
@@ -267,7 +267,7 @@ class Checker:
def setflags(self, **kw):
for key in kw.keys():
if key not in self.validflags:
- raise NameError, "invalid keyword argument: %s" % str(key)
+ raise NameError("invalid keyword argument: %s" % str(key))
for key, value in kw.items():
setattr(self, key, value)
@@ -761,7 +761,7 @@ class MyURLopener(urllib.FancyURLopener):
names = os.listdir(path)
except os.error as msg:
exc_type, exc_value, exc_tb = sys.exc_info()
- raise IOError, msg, exc_tb
+ raise IOError(msg).with_traceback(exc_tb)
names.sort()
s = MyStringIO("file:"+url, {'content-type': 'text/html'})
s.write('<BASE HREF="file:%s">\n' %