New submission from Felipe:

This bug report is the opposite of issue #14718. The interpreter did not raise 
an error when it encountered a `yield` expression inside the `finally` part of 
a `try/finally` statement.

My system's info: Python 3.4.2 (v3.4.2:ab2c023a9432, Oct  6 2014, 22:15:05) 
[MSC v.1600 32 bit (Intel)] on win32



More detail
=======================================================

My interpreter does not raise any errors when yielding from a `finally` block. 
The documentation states, "Yield expressions are allowed in the try clause of a 
try ... finally construct."[1] Though not explicitly stated, the suggestion is 
that `yield` is not allowed in the `finally` clause. Issue #14718 suggests that 
this interpretation is correct.

Not raising an exception for `yield` inside of `finally` can cause incorrect 
behavior when the generator raises its own unhandled exception in the `try` 
block. PEP 342 says, "If the generator raises an uncaught exception, it is 
propagated to send()'s caller." In this case, however, the exception gets 
paused at the `yield` expression, instead of propagating to the caller. 

Here's an example that can clarify the issue:

>>> def f():  # I expected this function not to compile
...     try:
...         raise ValueError
...     finally:
...         yield 1  # Execution freezes here instead of propagating the 
ValueError
...     yield "done"
... 
>>> g = f()
>>> g.send(None)  # PEP 342 would require ValueError to be raised here
1
>>> g.send(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in f2
ValueError

I may be arguing over the meaning of "uncaught exception," but I expected 
(given that the function compiles and doesn't raise a `RuntimeError`) the 
`ValueError` to propagate rather than get frozen.



Example 2
-------------------------------------------------------

The second example is adapted from http://bugs.python.org/issue14718, where the 
submitter received a `RuntimeError`, but I did not:

>>> def f2():  # I also expected this function not to compile
...   try:
...     yield 1
...   finally:
...     yield 4
... 
>>> g = f()  # issue 14718 suggests this should raise RuntimeError
>>> next(g)
1
>>> next(g)
4
>>> next(g)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration




Possible resolution:
=========================================================

1. Enforce the ban on `yield` inside a finally `clause`. It seems like this 
should 
   already be happening, so I'm not sure why my version isn't performing the 
check.
   This could be a run-time check (which seems like it may already be 
implemented),
   but I think this could even be a compile-time check (by looking at the AST).
2. Clarify the documentation to make explicit the ban on the use of `yield` 
inside
   the `finally` clause, and specify what type of error it will raise (i.e., 
   `SyntaxError` or `RuntimeError`? or something else?).

I'll submit a patch for 2 if there's support for this change, and I will work 
on 1 if someone can point me in the right direction. I've engaged with the C 
source relating to the different protocols, but have never looked through the 
compiler/VM.




Notes
============================================
[1] https://docs.python.org/3.4/reference/expressions.html#yield-expressions

----------
components: Interpreter Core
messages: 232081
nosy: fov
priority: normal
severity: normal
status: open
title: No error when yielding from `finally`
type: behavior
versions: Python 3.4

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue22988>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to