bpo-39166: Fix trace of last iteration of async for loops (#17800)
This commit is contained in:
parent
850a8856e1
commit
4c53e63cc9
|
@ -526,6 +526,82 @@ class TraceTestCase(unittest.TestCase):
|
|||
(7, 'line'),
|
||||
(7, 'return')])
|
||||
|
||||
def test_20_async_for_loop(self):
|
||||
class AsyncIteratorWrapper:
|
||||
def __init__(self, obj):
|
||||
self._it = iter(obj)
|
||||
|
||||
def __aiter__(self):
|
||||
return self
|
||||
|
||||
async def __anext__(self):
|
||||
try:
|
||||
return next(self._it)
|
||||
except StopIteration:
|
||||
raise StopAsyncIteration
|
||||
|
||||
async def doit_async():
|
||||
async for letter in AsyncIteratorWrapper("abc"):
|
||||
x = letter
|
||||
y = 42
|
||||
|
||||
def run(tracer):
|
||||
x = doit_async()
|
||||
try:
|
||||
sys.settrace(tracer)
|
||||
x.send(None)
|
||||
finally:
|
||||
sys.settrace(None)
|
||||
|
||||
tracer = self.make_tracer()
|
||||
events = [
|
||||
(0, 'call'),
|
||||
(1, 'line'),
|
||||
(-12, 'call'),
|
||||
(-11, 'line'),
|
||||
(-11, 'return'),
|
||||
(-9, 'call'),
|
||||
(-8, 'line'),
|
||||
(-8, 'return'),
|
||||
(-6, 'call'),
|
||||
(-5, 'line'),
|
||||
(-4, 'line'),
|
||||
(-4, 'return'),
|
||||
(1, 'exception'),
|
||||
(2, 'line'),
|
||||
(1, 'line'),
|
||||
(-6, 'call'),
|
||||
(-5, 'line'),
|
||||
(-4, 'line'),
|
||||
(-4, 'return'),
|
||||
(1, 'exception'),
|
||||
(2, 'line'),
|
||||
(1, 'line'),
|
||||
(-6, 'call'),
|
||||
(-5, 'line'),
|
||||
(-4, 'line'),
|
||||
(-4, 'return'),
|
||||
(1, 'exception'),
|
||||
(2, 'line'),
|
||||
(1, 'line'),
|
||||
(-6, 'call'),
|
||||
(-5, 'line'),
|
||||
(-4, 'line'),
|
||||
(-4, 'exception'),
|
||||
(-3, 'line'),
|
||||
(-2, 'line'),
|
||||
(-2, 'exception'),
|
||||
(-2, 'return'),
|
||||
(1, 'exception'),
|
||||
(3, 'line'),
|
||||
(3, 'return')]
|
||||
try:
|
||||
run(tracer.trace)
|
||||
except Exception:
|
||||
pass
|
||||
self.compare_events(doit_async.__code__.co_firstlineno,
|
||||
tracer.events, events)
|
||||
|
||||
|
||||
class SkipLineEventsTraceTestCase(TraceTestCase):
|
||||
"""Repeat the trace tests, but with per-line events skipped"""
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Fix incorrect line execution reporting in trace functions when tracing the
|
||||
last iteration of asynchronous for loops. Patch by Pablo Galindo.
|
|
@ -3610,12 +3610,16 @@ exception_unwind:
|
|||
PUSH(val);
|
||||
PUSH(exc);
|
||||
JUMPTO(handler);
|
||||
if (_Py_TracingPossible(ceval) &&
|
||||
((f->f_lasti < instr_lb || f->f_lasti >= instr_ub) ||
|
||||
!(f->f_lasti == instr_lb || f->f_lasti < instr_prev))) {
|
||||
/* Make sure that we trace line after exception */
|
||||
if (_Py_TracingPossible(ceval)) {
|
||||
int needs_new_execution_window = (f->f_lasti < instr_lb || f->f_lasti >= instr_ub);
|
||||
int needs_line_update = (f->f_lasti == instr_lb || f->f_lasti < instr_prev);
|
||||
/* Make sure that we trace line after exception if we are in a new execution
|
||||
* window or we don't need a line update and we are not in the first instruction
|
||||
* of the line. */
|
||||
if (needs_new_execution_window || (!needs_line_update && instr_lb > 0)) {
|
||||
instr_prev = INT_MAX;
|
||||
}
|
||||
}
|
||||
/* Resume normal execution */
|
||||
goto main_loop;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue