mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	bpo-39166: Fix trace of last iteration of async for loops (#17800)
This commit is contained in:
		
							parent
							
								
									850a8856e1
								
							
						
					
					
						commit
						4c53e63cc9
					
				
					 3 changed files with 87 additions and 5 deletions
				
			
		|  | @ -526,6 +526,82 @@ def func(): | ||||||
|              (7, 'line'), |              (7, 'line'), | ||||||
|              (7, 'return')]) |              (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): | class SkipLineEventsTraceTestCase(TraceTestCase): | ||||||
|     """Repeat the trace tests, but with per-line events skipped""" |     """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,11 +3610,15 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) | ||||||
|                 PUSH(val); |                 PUSH(val); | ||||||
|                 PUSH(exc); |                 PUSH(exc); | ||||||
|                 JUMPTO(handler); |                 JUMPTO(handler); | ||||||
|                 if (_Py_TracingPossible(ceval) && |                 if (_Py_TracingPossible(ceval)) { | ||||||
|                     ((f->f_lasti < instr_lb || f->f_lasti >= instr_ub) || |                     int needs_new_execution_window = (f->f_lasti < instr_lb || f->f_lasti >= instr_ub); | ||||||
|                     !(f->f_lasti == instr_lb || f->f_lasti < instr_prev))) { |                     int needs_line_update = (f->f_lasti == instr_lb || f->f_lasti < instr_prev); | ||||||
|                     /* Make sure that we trace line after exception */ |                     /* Make sure that we trace line after exception if we are in a new execution
 | ||||||
|                     instr_prev = INT_MAX; |                      * 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 */ |                 /* Resume normal execution */ | ||||||
|                 goto main_loop; |                 goto main_loop; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Pablo Galindo
						Pablo Galindo