Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8170e8c

Browse files
committed
PEP 479: Change StopIteration handling inside generators.
Closes issue #22906.
1 parent bd60e8d commit 8170e8c

14 files changed

Lines changed: 103 additions & 15 deletions

File tree

Doc/howto/functional.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -481,10 +481,10 @@ Here's a sample usage of the ``generate_ints()`` generator:
481481
You could equally write ``for i in generate_ints(5)``, or ``a,b,c =
482482
generate_ints(3)``.
483483

484-
Inside a generator function, ``return value`` is semantically equivalent to
485-
``raise StopIteration(value)``. If no value is returned or the bottom of the
486-
function is reached, the procession of values ends and the generator cannot
487-
return any further values.
484+
Inside a generator function, ``return value`` causes ``StopIteration(value)``
485+
to be raised from the :meth:`~generator.__next__` method. Once this happens, or
486+
the bottom of the function is reached, the procession of values ends and the
487+
generator cannot yield any further values.
488488

489489
You could achieve the effect of generators manually by writing your own class
490490
and storing all the local variables of the generator as instance variables. For

Doc/library/__future__.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ language using this mechanism:
8787
| unicode_literals | 2.6.0a2 | 3.0 | :pep:`3112`: |
8888
| | | | *Bytes literals in Python 3000* |
8989
+------------------+-------------+--------------+---------------------------------------------+
90+
| generator_stop | 3.5.0b1 | 3.7 | :pep:`479`: |
91+
| | | | *StopIteration handling inside generators* |
92+
+------------------+-------------+--------------+---------------------------------------------+
9093

9194

9295
.. seealso::

Doc/library/exceptions.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,10 +310,18 @@ The following exceptions are the exceptions that are usually raised.
310310
raised, and the value returned by the function is used as the
311311
:attr:`value` parameter to the constructor of the exception.
312312

313+
If a generator function defined in the presence of a ``from __future__
314+
import generator_stop`` directive raises :exc:`StopIteration`, it will be
315+
converted into a :exc:`RuntimeError` (retaining the :exc:`StopIteration`
316+
as the new exception's cause).
317+
313318
.. versionchanged:: 3.3
314319
Added ``value`` attribute and the ability for generator functions to
315320
use it to return a value.
316321

322+
.. versionchanged:: 3.5
323+
Introduced the RuntimeError transformation.
324+
317325
.. exception:: SyntaxError
318326

319327
Raised when the parser encounters a syntax error. This may occur in an

Doc/reference/expressions.rst

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -443,12 +443,12 @@ is already executing raises a :exc:`ValueError` exception.
443443
.. method:: generator.close()
444444

445445
Raises a :exc:`GeneratorExit` at the point where the generator function was
446-
paused. If the generator function then raises :exc:`StopIteration` (by
447-
exiting normally, or due to already being closed) or :exc:`GeneratorExit` (by
448-
not catching the exception), close returns to its caller. If the generator
449-
yields a value, a :exc:`RuntimeError` is raised. If the generator raises any
450-
other exception, it is propagated to the caller. :meth:`close` does nothing
451-
if the generator has already exited due to an exception or normal exit.
446+
paused. If the generator function then exits gracefully, is already closed,
447+
or raises :exc:`GeneratorExit` (by not catching the exception), close
448+
returns to its caller. If the generator yields a value, a
449+
:exc:`RuntimeError` is raised. If the generator raises any other exception,
450+
it is propagated to the caller. :meth:`close` does nothing if the generator
451+
has already exited due to an exception or normal exit.
452452

453453
.. index:: single: yield; examples
454454

Include/code.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ typedef struct {
6262
#define CO_FUTURE_UNICODE_LITERALS 0x20000
6363

6464
#define CO_FUTURE_BARRY_AS_BDFL 0x40000
65+
#define CO_FUTURE_GENERATOR_STOP 0x80000
6566

6667
/* This value is found in the co_cell2arg array when the associated cell
6768
variable does not correspond to an argument. The maximum number of

Include/compile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ typedef struct {
2727
#define FUTURE_PRINT_FUNCTION "print_function"
2828
#define FUTURE_UNICODE_LITERALS "unicode_literals"
2929
#define FUTURE_BARRY_AS_BDFL "barry_as_FLUFL"
30+
#define FUTURE_GENERATOR_STOP "generator_stop"
3031

3132
struct _mod; /* Declare the existence of this type */
3233
#define PyAST_Compile(mod, s, f, ar) PyAST_CompileEx(mod, s, f, -1, ar)

Include/pythonrun.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ extern "C" {
99

1010
#define PyCF_MASK (CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT | \
1111
CO_FUTURE_WITH_STATEMENT | CO_FUTURE_PRINT_FUNCTION | \
12-
CO_FUTURE_UNICODE_LITERALS | CO_FUTURE_BARRY_AS_BDFL)
12+
CO_FUTURE_UNICODE_LITERALS | CO_FUTURE_BARRY_AS_BDFL | \
13+
CO_FUTURE_GENERATOR_STOP)
1314
#define PyCF_MASK_OBSOLETE (CO_NESTED)
1415
#define PyCF_SOURCE_IS_UTF8 0x0100
1516
#define PyCF_DONT_IMPLY_DEDENT 0x0200

Lib/__future__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"print_function",
5757
"unicode_literals",
5858
"barry_as_FLUFL",
59+
"generator_stop",
5960
]
6061

6162
__all__ = ["all_feature_names"] + all_feature_names
@@ -72,6 +73,7 @@
7273
CO_FUTURE_PRINT_FUNCTION = 0x10000 # print function
7374
CO_FUTURE_UNICODE_LITERALS = 0x20000 # unicode string literals
7475
CO_FUTURE_BARRY_AS_BDFL = 0x40000
76+
CO_FUTURE_GENERATOR_STOP = 0x80000 # StopIteration becomes RuntimeError in generators
7577

7678
class _Feature:
7779
def __init__(self, optionalRelease, mandatoryRelease, compiler_flag):
@@ -132,3 +134,7 @@ def __repr__(self):
132134
barry_as_FLUFL = _Feature((3, 1, 0, "alpha", 2),
133135
(3, 9, 0, "alpha", 0),
134136
CO_FUTURE_BARRY_AS_BDFL)
137+
138+
generator_stop = _Feature((3, 5, 0, "beta", 1),
139+
(3, 7, 0, "alpha", 0),
140+
CO_FUTURE_GENERATOR_STOP)

Lib/contextlib.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,17 @@ def __exit__(self, type, value, traceback):
7777
self.gen.throw(type, value, traceback)
7878
raise RuntimeError("generator didn't stop after throw()")
7979
except StopIteration as exc:
80-
# Suppress the exception *unless* it's the same exception that
80+
# Suppress StopIteration *unless* it's the same exception that
8181
# was passed to throw(). This prevents a StopIteration
82-
# raised inside the "with" statement from being suppressed
82+
# raised inside the "with" statement from being suppressed.
8383
return exc is not value
84+
except RuntimeError as exc:
85+
# Likewise, avoid suppressing if a StopIteration exception
86+
# was passed to throw() and later wrapped into a RuntimeError
87+
# (see PEP 479).
88+
if exc.__cause__ is value:
89+
return False
90+
raise
8491
except:
8592
# only re-raise if it's *not* the exception that was
8693
# passed to throw(), because __exit__() must not raise

Lib/difflib.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,8 +1596,7 @@ def _line_pair_iterator():
15961596
# them up without doing anything else with them.
15971597
line_pair_iterator = _line_pair_iterator()
15981598
if context is None:
1599-
while True:
1600-
yield next(line_pair_iterator)
1599+
yield from line_pair_iterator
16011600
# Handle case where user wants context differencing. We must do some
16021601
# storage of lines until we know for sure that they are to be yielded.
16031602
else:

0 commit comments

Comments
 (0)