From 828f04ac3f0dd3b68b4dbf42a79ebb846d1de568 Mon Sep 17 00:00:00 2001 From: Collin Winter Date: Fri, 31 Aug 2007 00:04:24 +0000 Subject: Issue #1066: implement PEP 3109, 2/3 of PEP 3134. --- Grammar/Grammar | 2 +- Include/Python-ast.h | 11 +- Include/pyerrors.h | 46 ++-- Lib/contextlib.py | 2 +- Lib/doctest.py | 4 +- Lib/os.py | 8 +- Lib/test/test_ast.py | 4 +- Lib/test/test_exceptions.py | 60 +++++- Lib/test/test_grammar.py | 2 +- Lib/test/test_opcodes.py | 12 +- Lib/test/test_raise.py | 417 +++++++++++++++++++++++++++++++++++++ Lib/test/test_syntax.py | 10 + Lib/test/test_sys.py | 5 - Lib/test/test_with.py | 2 +- Lib/test/test_zipimport.py | 2 +- Lib/urllib.py | 8 +- Lib/urllib2.py | 2 +- Lib/wsgiref/handlers.py | 2 +- Mac/BuildScript/build-installer.py | 10 +- Mac/Tools/Doc/setup.py | 5 +- Mac/scripts/buildpkg.py | 2 +- Mac/scripts/mkestrres.py | 2 +- Objects/exceptions.c | 98 ++++++++- Parser/Python.asdl | 3 +- Python/Python-ast.c | 32 ++- Python/ast.c | 39 +--- Python/ceval.c | 134 +++++------- Python/compile.c | 22 +- Python/graminit.c | 51 ++--- Python/import.c | 1 + Python/symtable.c | 12 +- Tools/webchecker/webchecker.py | 4 +- 32 files changed, 761 insertions(+), 253 deletions(-) create mode 100644 Lib/test/test_raise.py 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 , - raise , - raise , None - raise , - raise , None - raise , - raise , None - - An omitted second argument is the same as None. - - In addition, raise , 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 + raise */ - /* 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 , */ - 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('\n' % -- cgit v0.12