Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 100c7ab

Browse filesBrowse 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
Copy full SHA for 100c7ab

File tree

4 files changed

+57
-4
lines changed
Filter options

4 files changed

+57
-4
lines changed

‎Lib/test/test_capi/test_exceptions.py

Copy file name to clipboardExpand all lines: Lib/test/test_capi/test_exceptions.py
+43-1Lines changed: 43 additions & 1 deletion
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

+2Lines changed: 2 additions & 0 deletions
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

Copy file name to clipboardExpand all lines: Modules/_testcapimodule.c
+10Lines changed: 10 additions & 0 deletions
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

Copy file name to clipboardExpand all lines: Python/_warnings.c
+2-3Lines changed: 2 additions & 3 deletions
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.