mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	GH-92236: Remove spurious "line" event when starting coroutine or generator. (GH-92722) (GH-92772)
(cherry picked from commit 22a1db378c)
			
			
This commit is contained in:
		
							parent
							
								
									c41667e71b
								
							
						
					
					
						commit
						2e8b2d0ee2
					
				
					 4 changed files with 107 additions and 0 deletions
				
			
		|  | @ -7,6 +7,7 @@ | |||
| import gc | ||||
| from functools import wraps | ||||
| import asyncio | ||||
| from test.support import import_helper | ||||
| 
 | ||||
| support.requires_working_socket(module=True) | ||||
| 
 | ||||
|  | @ -1473,6 +1474,58 @@ def __init__(self): | |||
|              (3, 'return'), | ||||
|              (1, 'return')]) | ||||
| 
 | ||||
|     @support.cpython_only | ||||
|     def test_no_line_event_after_creating_generator(self): | ||||
|         # Spurious line events before call events only show up with C tracer | ||||
| 
 | ||||
|         # Skip this test if the _testcapi module isn't available. | ||||
|         _testcapi = import_helper.import_module('_testcapi') | ||||
| 
 | ||||
|         def gen(): | ||||
|             yield 1 | ||||
| 
 | ||||
|         def func(): | ||||
|             for _ in ( | ||||
|                 gen() | ||||
|             ): | ||||
|                 pass | ||||
| 
 | ||||
|         EXPECTED_EVENTS = [ | ||||
|             (0, 'call'), | ||||
|             (2, 'line'), | ||||
|             (1, 'line'), | ||||
|             (-3, 'call'), | ||||
|             (-2, 'line'), | ||||
|             (-2, 'return'), | ||||
|             (4, 'line'), | ||||
|             (1, 'line'), | ||||
|             (-2, 'call'), | ||||
|             (-2, 'return'), | ||||
|             (1, 'return'), | ||||
|         ] | ||||
| 
 | ||||
|         # C level events should be the same as expected and the same as Python level. | ||||
| 
 | ||||
|         events = [] | ||||
|         # Turning on and off tracing must be on same line to avoid unwanted LINE events. | ||||
|         _testcapi.settrace_to_record(events); func(); sys.settrace(None) | ||||
|         start_line = func.__code__.co_firstlineno | ||||
|         events = [ | ||||
|             (line-start_line, EVENT_NAMES[what]) | ||||
|             for (what, line, arg) in events | ||||
|         ] | ||||
|         self.assertEqual(events, EXPECTED_EVENTS) | ||||
| 
 | ||||
|         self.run_and_compare(func, EXPECTED_EVENTS) | ||||
| 
 | ||||
| 
 | ||||
| EVENT_NAMES = [ | ||||
|     'call', | ||||
|     'exception', | ||||
|     'line', | ||||
|     'return' | ||||
| ] | ||||
| 
 | ||||
| 
 | ||||
| class SkipLineEventsTraceTestCase(TraceTestCase): | ||||
|     """Repeat the trace tests, but with per-line events skipped""" | ||||
|  |  | |||
|  | @ -0,0 +1,2 @@ | |||
| Remove spurious "LINE" event when starting a generator or coroutine, visible | ||||
| tracing functions implemented in C. | ||||
|  | @ -5955,6 +5955,51 @@ test_code_api(PyObject *self, PyObject *Py_UNUSED(args)) | |||
|     Py_RETURN_NONE; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| record_func(PyObject *obj, PyFrameObject *f, int what, PyObject *arg) | ||||
| { | ||||
|     assert(PyList_Check(obj)); | ||||
|     PyObject *what_obj = NULL; | ||||
|     PyObject *line_obj = NULL; | ||||
|     PyObject *tuple = NULL; | ||||
|     int res = -1; | ||||
|     what_obj = PyLong_FromLong(what); | ||||
|     if (what_obj == NULL) { | ||||
|         goto error; | ||||
|     } | ||||
|     int line = PyFrame_GetLineNumber(f); | ||||
|     line_obj = PyLong_FromLong(line); | ||||
|     if (line_obj == NULL) { | ||||
|         goto error; | ||||
|     } | ||||
|     tuple = PyTuple_Pack(3, what_obj, line_obj, arg); | ||||
|     if (tuple == NULL) { | ||||
|         goto error; | ||||
|     } | ||||
|     PyTuple_SET_ITEM(tuple, 0, what_obj); | ||||
|     if (PyList_Append(obj, tuple)) { | ||||
|         goto error; | ||||
|     } | ||||
|     res = 0; | ||||
| error: | ||||
|     Py_XDECREF(what_obj); | ||||
|     Py_XDECREF(line_obj); | ||||
|     Py_XDECREF(tuple); | ||||
|     return res; | ||||
| } | ||||
| 
 | ||||
| static PyObject * | ||||
| settrace_to_record(PyObject *self, PyObject *list) | ||||
| { | ||||
| 
 | ||||
|    if (!PyList_Check(list)) { | ||||
|         PyErr_SetString(PyExc_TypeError, "argument must be a list"); | ||||
|         return NULL; | ||||
|     } | ||||
|     PyEval_SetTrace(record_func, list); | ||||
|     Py_RETURN_NONE; | ||||
| } | ||||
| 
 | ||||
| static PyObject *negative_dictoffset(PyObject *, PyObject *); | ||||
| static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); | ||||
| static PyObject *getargs_s_hash_int(PyObject *, PyObject *, PyObject*); | ||||
|  | @ -6251,6 +6296,7 @@ static PyMethodDef TestMethods[] = { | |||
|     {"frame_getlasti", frame_getlasti, METH_O, NULL}, | ||||
|     {"get_feature_macros", get_feature_macros, METH_NOARGS, NULL}, | ||||
|     {"test_code_api", test_code_api, METH_NOARGS, NULL}, | ||||
|     {"settrace_to_record", settrace_to_record, METH_O, NULL}, | ||||
|     {NULL, NULL} /* sentinel */ | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -5680,6 +5680,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int | |||
|                     TRACE_FUNCTION_ENTRY(); | ||||
|                     DTRACE_FUNCTION_ENTRY(); | ||||
|                     break; | ||||
|                 case POP_TOP: | ||||
|                     if (_Py_OPCODE(next_instr[-1]) == RETURN_GENERATOR) { | ||||
|                         /* Frame not fully initialized */ | ||||
|                         break; | ||||
|                     } | ||||
|                     /* fall through */ | ||||
|                 default: | ||||
|                     /* line-by-line tracing support */ | ||||
|                     if (PyDTrace_LINE_ENABLED()) { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Miss Islington (bot)
						Miss Islington (bot)