Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
8170e8c0
Commit
8170e8c0
authored
May 09, 2015
by
Yury Selivanov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
PEP 479: Change StopIteration handling inside generators.
Closes issue #22906.
parent
bd60e8de
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
103 additions
and
15 deletions
+103
-15
Doc/howto/functional.rst
Doc/howto/functional.rst
+4
-4
Doc/library/__future__.rst
Doc/library/__future__.rst
+3
-0
Doc/library/exceptions.rst
Doc/library/exceptions.rst
+8
-0
Doc/reference/expressions.rst
Doc/reference/expressions.rst
+6
-6
Include/code.h
Include/code.h
+1
-0
Include/compile.h
Include/compile.h
+1
-0
Include/pythonrun.h
Include/pythonrun.h
+2
-1
Lib/__future__.py
Lib/__future__.py
+6
-0
Lib/contextlib.py
Lib/contextlib.py
+9
-2
Lib/difflib.py
Lib/difflib.py
+1
-2
Lib/test/test_contextlib.py
Lib/test/test_contextlib.py
+34
-0
Misc/NEWS
Misc/NEWS
+2
-0
Objects/genobject.c
Objects/genobject.c
+24
-0
Python/future.c
Python/future.c
+2
-0
No files found.
Doc/howto/functional.rst
View file @
8170e8c0
...
...
@@ -481,10 +481,10 @@ Here's a sample usage of the ``generate_ints()`` generator:
You could equally write ``for i in generate_ints(5)``, or ``a,b,c =
generate_ints(3)``.
Inside a generator function, ``return value``
is semantically equivalent to
``raise StopIteration(value)``. If no value is returned or the bottom of the
function is reached, the procession of values ends and the generator cannot
return
any further values.
Inside a generator function, ``return value``
causes ``StopIteration(value)``
to be raised from the :meth:`~generator.__next__` method. Once this happens, or
the bottom of the function is reached, the procession of values ends and the
generator cannot yield
any further values.
You could achieve the effect of generators manually by writing your own class
and storing all the local variables of the generator as instance variables. For
...
...
Doc/library/__future__.rst
View file @
8170e8c0
...
...
@@ -87,6 +87,9 @@ language using this mechanism:
| unicode_literals | 2.6.0a2 | 3.0 | :pep:`3112`: |
| | | | *Bytes literals in Python 3000* |
+------------------+-------------+--------------+---------------------------------------------+
| generator_stop | 3.5.0b1 | 3.7 | :pep:`479`: |
| | | | *StopIteration handling inside generators* |
+------------------+-------------+--------------+---------------------------------------------+
.. seealso::
...
...
Doc/library/exceptions.rst
View file @
8170e8c0
...
...
@@ -310,10 +310,18 @@ The following exceptions are the exceptions that are usually raised.
raised, and the value returned by the function is used as the
:attr:`value` parameter to the constructor of the exception.
If a generator function defined in the presence of a ``from __future__
import generator_stop`` directive raises :exc:`StopIteration`, it will be
converted into a :exc:`RuntimeError` (retaining the :exc:`StopIteration`
as the new exception's cause).
.. versionchanged:: 3.3
Added ``value`` attribute and the ability for generator functions to
use it to return a value.
.. versionchanged:: 3.5
Introduced the RuntimeError transformation.
.. exception:: SyntaxError
Raised when the parser encounters a syntax error. This may occur in an
...
...
Doc/reference/expressions.rst
View file @
8170e8c0
...
...
@@ -443,12 +443,12 @@ is already executing raises a :exc:`ValueError` exception.
.. method:: generator.close()
Raises a :exc:`GeneratorExit` at the point where the generator function was
paused. If the generator function then
raises :exc:`StopIteration` (by
exiting normally, or due to already being closed) or :exc:`GeneratorExit` (by
not catching the exception), close returns to its caller. If the generator
yields a value, a :exc:`RuntimeError` is raised. If the generator raises any
other exception, it is propagated to the caller. :meth:`close` does nothing
if the generator
has already exited due to an exception or normal exit.
paused. If the generator function then
exits gracefully, is already closed,
or raises :exc:`GeneratorExit` (by not catching the exception), close
returns to its caller. If the generator yields a value, a
:exc:`RuntimeError` is raised. If the generator raises any other exception,
it is propagated to the caller. :meth:`close` does nothing if the generator
has already exited due to an exception or normal exit.
.. index:: single: yield; examples
...
...
Include/code.h
View file @
8170e8c0
...
...
@@ -62,6 +62,7 @@ typedef struct {
#define CO_FUTURE_UNICODE_LITERALS 0x20000
#define CO_FUTURE_BARRY_AS_BDFL 0x40000
#define CO_FUTURE_GENERATOR_STOP 0x80000
/* This value is found in the co_cell2arg array when the associated cell
variable does not correspond to an argument. The maximum number of
...
...
Include/compile.h
View file @
8170e8c0
...
...
@@ -27,6 +27,7 @@ typedef struct {
#define FUTURE_PRINT_FUNCTION "print_function"
#define FUTURE_UNICODE_LITERALS "unicode_literals"
#define FUTURE_BARRY_AS_BDFL "barry_as_FLUFL"
#define FUTURE_GENERATOR_STOP "generator_stop"
struct
_mod
;
/* Declare the existence of this type */
#define PyAST_Compile(mod, s, f, ar) PyAST_CompileEx(mod, s, f, -1, ar)
...
...
Include/pythonrun.h
View file @
8170e8c0
...
...
@@ -9,7 +9,8 @@ extern "C" {
#define PyCF_MASK (CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT | \
CO_FUTURE_WITH_STATEMENT | CO_FUTURE_PRINT_FUNCTION | \
CO_FUTURE_UNICODE_LITERALS | CO_FUTURE_BARRY_AS_BDFL)
CO_FUTURE_UNICODE_LITERALS | CO_FUTURE_BARRY_AS_BDFL | \
CO_FUTURE_GENERATOR_STOP)
#define PyCF_MASK_OBSOLETE (CO_NESTED)
#define PyCF_SOURCE_IS_UTF8 0x0100
#define PyCF_DONT_IMPLY_DEDENT 0x0200
...
...
Lib/__future__.py
View file @
8170e8c0
...
...
@@ -56,6 +56,7 @@ all_feature_names = [
"print_function"
,
"unicode_literals"
,
"barry_as_FLUFL"
,
"generator_stop"
,
]
__all__
=
[
"all_feature_names"
]
+
all_feature_names
...
...
@@ -72,6 +73,7 @@ CO_FUTURE_WITH_STATEMENT = 0x8000 # with statement
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 @@ unicode_literals = _Feature((2, 6, 0, "alpha", 2),
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
)
Lib/contextlib.py
View file @
8170e8c0
...
...
@@ -77,10 +77,17 @@ class _GeneratorContextManager(ContextDecorator):
self
.
gen
.
throw
(
type
,
value
,
traceback
)
raise
RuntimeError
(
"generator didn't stop after throw()"
)
except
StopIteration
as
exc
:
# Suppress
the excep
tion *unless* it's the same exception that
# Suppress
StopItera
tion *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
...
...
Lib/difflib.py
View file @
8170e8c0
...
...
@@ -1596,8 +1596,7 @@ def _mdiff(fromlines, tolines, context=None, linejunk=None,
# 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:
...
...
Lib/test/test_contextlib.py
View file @
8170e8c0
...
...
@@ -83,6 +83,40 @@ class ContextManagerTestCase(unittest.TestCase):
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
):
...
...
Misc/NEWS
View file @
8170e8c0
...
...
@@ -33,6 +33,8 @@ Core and Builtins
- Issue #9951: Added a hex() method to bytes, bytearray, and memoryview.
- Issue #22906: PEP 479: Change StopIteration handling inside generators.
Library
-------
...
...
Objects/genobject.c
View file @
8170e8c0
...
...
@@ -130,6 +130,30 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc)
}
Py_CLEAR
(
result
);
}
else
if
(
!
result
)
{
/* Check for __future__ generator_stop and conditionally turn
* a leaking StopIteration into RuntimeError (with its cause
* set appropriately). */
if
((((
PyCodeObject
*
)
gen
->
gi_code
)
->
co_flags
&
CO_FUTURE_GENERATOR_STOP
)
&&
PyErr_ExceptionMatches
(
PyExc_StopIteration
))
{
PyObject
*
exc
,
*
val
,
*
val2
,
*
tb
;
PyErr_Fetch
(
&
exc
,
&
val
,
&
tb
);
PyErr_NormalizeException
(
&
exc
,
&
val
,
&
tb
);
if
(
tb
!=
NULL
)
PyException_SetTraceback
(
val
,
tb
);
Py_DECREF
(
exc
);
Py_XDECREF
(
tb
);
PyErr_SetString
(
PyExc_RuntimeError
,
"generator raised StopIteration"
);
PyErr_Fetch
(
&
exc
,
&
val2
,
&
tb
);
PyErr_NormalizeException
(
&
exc
,
&
val2
,
&
tb
);
PyException_SetCause
(
val2
,
val
);
PyException_SetContext
(
val2
,
val
);
PyErr_Restore
(
exc
,
val2
,
tb
);
}
}
if
(
!
result
||
f
->
f_stacktop
==
NULL
)
{
/* generator can't be rerun, so release the frame */
...
...
Python/future.c
View file @
8170e8c0
...
...
@@ -40,6 +40,8 @@ future_check_features(PyFutureFeatures *ff, stmt_ty s, PyObject *filename)
continue
;
}
else
if
(
strcmp
(
feature
,
FUTURE_BARRY_AS_BDFL
)
==
0
)
{
ff
->
ff_features
|=
CO_FUTURE_BARRY_AS_BDFL
;
}
else
if
(
strcmp
(
feature
,
FUTURE_GENERATOR_STOP
)
==
0
)
{
ff
->
ff_features
|=
CO_FUTURE_GENERATOR_STOP
;
}
else
if
(
strcmp
(
feature
,
"braces"
)
==
0
)
{
PyErr_SetString
(
PyExc_SyntaxError
,
"not a chance"
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment