PEP 479: Change StopIteration handling inside generators.

Closes issue #22906.
diff --git a/Lib/__future__.py b/Lib/__future__.py
index 3b2d5ec..63b2be3 100644
--- a/Lib/__future__.py
+++ b/Lib/__future__.py
@@ -56,6 +56,7 @@
     "print_function",
     "unicode_literals",
     "barry_as_FLUFL",
+    "generator_stop",
 ]
 
 __all__ = ["all_feature_names"] + all_feature_names
@@ -72,6 +73,7 @@
 CO_FUTURE_PRINT_FUNCTION  = 0x10000   # print function
 CO_FUTURE_UNICODE_LITERALS = 0x20000 # unicode string literals
 CO_FUTURE_BARRY_AS_BDFL = 0x40000
+CO_FUTURE_GENERATOR_STOP  = 0x80000 # StopIteration becomes RuntimeError in generators
 
 class _Feature:
     def __init__(self, optionalRelease, mandatoryRelease, compiler_flag):
@@ -132,3 +134,7 @@
 barry_as_FLUFL = _Feature((3, 1, 0, "alpha", 2),
                          (3, 9, 0, "alpha", 0),
                          CO_FUTURE_BARRY_AS_BDFL)
+
+generator_stop = _Feature((3, 5, 0, "beta", 1),
+                         (3, 7, 0, "alpha", 0),
+                         CO_FUTURE_GENERATOR_STOP)
diff --git a/Lib/contextlib.py b/Lib/contextlib.py
index 2fbc90c..379c251 100644
--- a/Lib/contextlib.py
+++ b/Lib/contextlib.py
@@ -77,10 +77,17 @@
                 self.gen.throw(type, value, traceback)
                 raise RuntimeError("generator didn't stop after throw()")
             except StopIteration as exc:
-                # Suppress the exception *unless* it's the same exception that
+                # Suppress StopIteration *unless* it's the same exception that
                 # was passed to throw().  This prevents a StopIteration
-                # raised inside the "with" statement from being suppressed
+                # raised inside the "with" statement from being suppressed.
                 return exc is not value
+            except RuntimeError as exc:
+                # Likewise, avoid suppressing if a StopIteration exception
+                # was passed to throw() and later wrapped into a RuntimeError
+                # (see PEP 479).
+                if exc.__cause__ is value:
+                    return False
+                raise
             except:
                 # only re-raise if it's *not* the exception that was
                 # passed to throw(), because __exit__() must not raise
diff --git a/Lib/difflib.py b/Lib/difflib.py
index 96fd9ab..aa98436 100644
--- a/Lib/difflib.py
+++ b/Lib/difflib.py
@@ -1596,8 +1596,7 @@
     # them up without doing anything else with them.
     line_pair_iterator = _line_pair_iterator()
     if context is None:
-        while True:
-            yield next(line_pair_iterator)
+        yield from line_pair_iterator
     # Handle case where user wants context differencing.  We must do some
     # storage of lines until we know for sure that they are to be yielded.
     else:
diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py
index c52066b..a5d68a9 100644
--- a/Lib/test/test_contextlib.py
+++ b/Lib/test/test_contextlib.py
@@ -83,6 +83,40 @@
             raise ZeroDivisionError(999)
         self.assertEqual(state, [1, 42, 999])
 
+    def test_contextmanager_except_stopiter(self):
+        stop_exc = StopIteration('spam')
+        @contextmanager
+        def woohoo():
+            yield
+        try:
+            with woohoo():
+                raise stop_exc
+        except Exception as ex:
+            self.assertIs(ex, stop_exc)
+        else:
+            self.fail('StopIteration was suppressed')
+
+    def test_contextmanager_except_pep479(self):
+        code = """\
+from __future__ import generator_stop
+from contextlib import contextmanager
+@contextmanager
+def woohoo():
+    yield
+"""
+        locals = {}
+        exec(code, locals, locals)
+        woohoo = locals['woohoo']
+
+        stop_exc = StopIteration('spam')
+        try:
+            with woohoo():
+                raise stop_exc
+        except Exception as ex:
+            self.assertIs(ex, stop_exc)
+        else:
+            self.fail('StopIteration was suppressed')
+
     def _create_contextmanager_attribs(self):
         def attribs(**kw):
             def decorate(func):