Issue #1066: implement PEP 3109, 2/3 of PEP 3134.
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 @@
             # 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 @@
          '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 @@
              '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 @@
     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 @@
                 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 @@
                 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 @@
     # If
     "if v:pass",
     # Raise
-    "raise Exception, 'string'",
+    "raise Exception('string')",
     # TryExcept
     "try:\n  pass\nexcept Exception:\n  pass",
     # TryFinally
@@ -160,7 +160,7 @@
 ('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 @@
 
     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 BadException(Exception):
             def __init__(self_):
-                raise RuntimeError, "can't instantiate BadException"
+                raise RuntimeError("can't instantiate BadException")
 
         class InvalidException:
             pass
@@ -305,6 +305,62 @@
                                               '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 @@
 
     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 @@
         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 @@
         ##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 @@
      ...
    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 @@
 
         # 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 @@
                 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 @@
         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 @@
             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 @@
             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 @@
                 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 @@
             # 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 @@
             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 @@
             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: