[Python-checkins] GH-92236: Remove spurious "line" event when starting coroutine or generator. (GH-92722)
markshannon
webhook-mailer at python.org
Fri May 13 06:25:23 EDT 2022
https://github.com/python/cpython/commit/22a1db378c5c381272362c5b2f68ac78a368e136
commit: 22a1db378c5c381272362c5b2f68ac78a368e136
branch: main
author: Mark Shannon <mark at hotpy.org>
committer: markshannon <mark at hotpy.org>
date: 2022-05-13T11:24:45+01:00
summary:
GH-92236: Remove spurious "line" event when starting coroutine or generator. (GH-92722)
files:
A Misc/NEWS.d/next/Core and Builtins/2022-05-12-13-23-19.gh-issue-92236.sDRzUe.rst
M Lib/test/test_sys_settrace.py
M Modules/_testcapimodule.c
M Python/ceval.c
diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py
index 715204edc44e3..9cc6bcfcab5e1 100644
--- a/Lib/test/test_sys_settrace.py
+++ b/Lib/test/test_sys_settrace.py
@@ -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"""
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-12-13-23-19.gh-issue-92236.sDRzUe.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-12-13-23-19.gh-issue-92236.sDRzUe.rst
new file mode 100644
index 0000000000000..fe482d505c67b
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-05-12-13-23-19.gh-issue-92236.sDRzUe.rst
@@ -0,0 +1,2 @@
+Remove spurious "LINE" event when starting a generator or coroutine, visible
+tracing functions implemented in C.
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 4371bf7da0e86..363dbbb666ca5 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -5787,6 +5787,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*);
@@ -6076,6 +6121,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 */
};
diff --git a/Python/ceval.c b/Python/ceval.c
index f6b07b4b28eb6..c73218fcf307e 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -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()) {
More information about the Python-checkins
mailing list