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

Lines 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

Lines 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

Lines 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

Lines 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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy