Skip to content

Commit 100c7ab

Browse files
authored
gh-119049: Fix incorrect display of warning which is constructed by C API (GH-119063)
The source line was not displayed if the warnings module had not yet been imported.
1 parent 4702b7b commit 100c7ab

File tree

4 files changed

+57
-4
lines changed

4 files changed

+57
-4
lines changed

Lib/test/test_capi/test_exceptions.py

+43-1
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
import re
44
import sys
55
import unittest
6+
import textwrap
67

78
from test import support
89
from test.support import import_helper
910
from test.support.os_helper import TESTFN, TESTFN_UNDECODABLE
10-
from test.support.script_helper import assert_python_failure
11+
from test.support.script_helper import assert_python_failure, assert_python_ok
1112
from test.support.testcase import ExceptionIsLikeMixin
1213

1314
from .test_misc import decode_stderr
@@ -68,6 +69,47 @@ def test_exc_info(self):
6869
else:
6970
self.assertTrue(False)
7071

72+
def test_warn_with_stacklevel(self):
73+
code = textwrap.dedent('''\
74+
import _testcapi
75+
76+
def foo():
77+
_testcapi.function_set_warning()
78+
79+
foo() # line 6
80+
81+
82+
foo() # line 9
83+
''')
84+
proc = assert_python_ok("-c", code)
85+
warnings = proc.err.splitlines()
86+
self.assertEqual(warnings, [
87+
b'<string>:6: RuntimeWarning: Testing PyErr_WarnEx',
88+
b' foo() # line 6',
89+
b'<string>:9: RuntimeWarning: Testing PyErr_WarnEx',
90+
b' foo() # line 9',
91+
])
92+
93+
def test_warn_during_finalization(self):
94+
code = textwrap.dedent('''\
95+
import _testcapi
96+
97+
class Foo:
98+
def foo(self):
99+
_testcapi.function_set_warning()
100+
def __del__(self):
101+
self.foo()
102+
103+
ref = Foo()
104+
''')
105+
proc = assert_python_ok("-c", code)
106+
warnings = proc.err.splitlines()
107+
# Due to the finalization of the interpreter, the source will be ommited
108+
# because the ``warnings`` module cannot be imported at this time
109+
self.assertEqual(warnings, [
110+
b'<string>:7: RuntimeWarning: Testing PyErr_WarnEx',
111+
])
112+
71113

72114
class Test_FatalError(unittest.TestCase):
73115

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix displaying the source line for warnings created by the C API if the
2+
:mod:`warnings` module had not yet been imported.

Modules/_testcapimodule.c

+10
Original file line numberDiff line numberDiff line change
@@ -3303,6 +3303,15 @@ test_reftracer(PyObject *ob, PyObject *Py_UNUSED(ignored))
33033303
return NULL;
33043304
}
33053305

3306+
static PyObject *
3307+
function_set_warning(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
3308+
{
3309+
if (PyErr_WarnEx(PyExc_RuntimeWarning, "Testing PyErr_WarnEx", 2)) {
3310+
return NULL;
3311+
}
3312+
Py_RETURN_NONE;
3313+
}
3314+
33063315
static PyMethodDef TestMethods[] = {
33073316
{"set_errno", set_errno, METH_VARARGS},
33083317
{"test_config", test_config, METH_NOARGS},
@@ -3444,6 +3453,7 @@ static PyMethodDef TestMethods[] = {
34443453
{"function_set_closure", function_set_closure, METH_VARARGS, NULL},
34453454
{"check_pyimport_addmodule", check_pyimport_addmodule, METH_VARARGS},
34463455
{"test_weakref_capi", test_weakref_capi, METH_NOARGS},
3456+
{"function_set_warning", function_set_warning, METH_NOARGS},
34473457
{NULL, NULL} /* sentinel */
34483458
};
34493459

Python/_warnings.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -569,10 +569,9 @@ call_show_warning(PyThreadState *tstate, PyObject *category,
569569
PyObject *show_fn, *msg, *res, *warnmsg_cls = NULL;
570570
PyInterpreterState *interp = tstate->interp;
571571

572-
/* If the source parameter is set, try to get the Python implementation.
573-
The Python implementation is able to log the traceback where the source
572+
/* The Python implementation is able to log the traceback where the source
574573
was allocated, whereas the C implementation doesn't. */
575-
show_fn = GET_WARNINGS_ATTR(interp, _showwarnmsg, source != NULL);
574+
show_fn = GET_WARNINGS_ATTR(interp, _showwarnmsg, 1);
576575
if (show_fn == NULL) {
577576
if (PyErr_Occurred())
578577
return -1;

0 commit comments

Comments
 (0)