Skip to content

Commit

Permalink
gh-119049: Fix incorrect display of warning which is constructed by C…
Browse files Browse the repository at this point in the history
… API (GH-119063)

The source line was not displayed if the warnings module had not yet
been imported.
  • Loading branch information
Eclips4 committed May 16, 2024
1 parent 4702b7b commit 100c7ab
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 4 deletions.
44 changes: 43 additions & 1 deletion Lib/test/test_capi/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
import re
import sys
import unittest
import textwrap

from test import support
from test.support import import_helper
from test.support.os_helper import TESTFN, TESTFN_UNDECODABLE
from test.support.script_helper import assert_python_failure
from test.support.script_helper import assert_python_failure, assert_python_ok
from test.support.testcase import ExceptionIsLikeMixin

from .test_misc import decode_stderr
Expand Down Expand Up @@ -68,6 +69,47 @@ def test_exc_info(self):
else:
self.assertTrue(False)

def test_warn_with_stacklevel(self):
code = textwrap.dedent('''\
import _testcapi
def foo():
_testcapi.function_set_warning()
foo() # line 6
foo() # line 9
''')
proc = assert_python_ok("-c", code)
warnings = proc.err.splitlines()
self.assertEqual(warnings, [
b'<string>:6: RuntimeWarning: Testing PyErr_WarnEx',
b' foo() # line 6',
b'<string>:9: RuntimeWarning: Testing PyErr_WarnEx',
b' foo() # line 9',
])

def test_warn_during_finalization(self):
code = textwrap.dedent('''\
import _testcapi
class Foo:
def foo(self):
_testcapi.function_set_warning()
def __del__(self):
self.foo()
ref = Foo()
''')
proc = assert_python_ok("-c", code)
warnings = proc.err.splitlines()
# Due to the finalization of the interpreter, the source will be ommited
# because the ``warnings`` module cannot be imported at this time
self.assertEqual(warnings, [
b'<string>:7: RuntimeWarning: Testing PyErr_WarnEx',
])


class Test_FatalError(unittest.TestCase):

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix displaying the source line for warnings created by the C API if the
:mod:`warnings` module had not yet been imported.
10 changes: 10 additions & 0 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -3303,6 +3303,15 @@ test_reftracer(PyObject *ob, PyObject *Py_UNUSED(ignored))
return NULL;
}

static PyObject *
function_set_warning(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
{
if (PyErr_WarnEx(PyExc_RuntimeWarning, "Testing PyErr_WarnEx", 2)) {
return NULL;
}
Py_RETURN_NONE;
}

static PyMethodDef TestMethods[] = {
{"set_errno", set_errno, METH_VARARGS},
{"test_config", test_config, METH_NOARGS},
Expand Down Expand Up @@ -3444,6 +3453,7 @@ static PyMethodDef TestMethods[] = {
{"function_set_closure", function_set_closure, METH_VARARGS, NULL},
{"check_pyimport_addmodule", check_pyimport_addmodule, METH_VARARGS},
{"test_weakref_capi", test_weakref_capi, METH_NOARGS},
{"function_set_warning", function_set_warning, METH_NOARGS},
{NULL, NULL} /* sentinel */
};

Expand Down
5 changes: 2 additions & 3 deletions Python/_warnings.c
Original file line number Diff line number Diff line change
Expand Up @@ -569,10 +569,9 @@ call_show_warning(PyThreadState *tstate, PyObject *category,
PyObject *show_fn, *msg, *res, *warnmsg_cls = NULL;
PyInterpreterState *interp = tstate->interp;

/* If the source parameter is set, try to get the Python implementation.
The Python implementation is able to log the traceback where the source
/* The Python implementation is able to log the traceback where the source
was allocated, whereas the C implementation doesn't. */
show_fn = GET_WARNINGS_ATTR(interp, _showwarnmsg, source != NULL);
show_fn = GET_WARNINGS_ATTR(interp, _showwarnmsg, 1);
if (show_fn == NULL) {
if (PyErr_Occurred())
return -1;
Expand Down

0 comments on commit 100c7ab

Please sign in to comment.