Skip to content

Commit f61481f

Browse files
[3.13] gh-155319: Fix the source line of a warning issued with module_globals (GH-155320) (GH-155826)
warn_explicit() computed the source line from the loader of the module whose globals were passed as module_globals, but did not pass it to WarningMessage. It also raised IndexError if lineno was out of the range of the module source. (cherry picked from commit c92e2fd)
1 parent e4046ce commit f61481f

3 files changed

Lines changed: 43 additions & 3 deletions

File tree

Lib/test/test_warnings/__init__.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,6 +1536,37 @@ def test_RuntimeError(self):
15361536
_version=version)
15371537

15381538

1539+
class WarnExplicitSourceTests(BaseTest):
1540+
# gh-155319: the source line is taken from the loader of the module
1541+
# whose globals are passed as module_globals, if the file which name
1542+
# is passed as filename cannot be read.
1543+
1544+
def warn_explicit(self, lineno):
1545+
with support.captured_stderr() as stderr:
1546+
with self.module.catch_warnings():
1547+
self.module.simplefilter("always")
1548+
self.module.warn_explicit(
1549+
'eggs', UserWarning, 'nonexistent', lineno,
1550+
module_globals=warning_tests.__dict__)
1551+
return stderr.getvalue()
1552+
1553+
def test_source_line(self):
1554+
source = warning_tests.__loader__.get_source(warning_tests.__name__)
1555+
expected = source.splitlines()[0].strip()
1556+
self.assertEqual(self.warn_explicit(1),
1557+
f'nonexistent:1: UserWarning: eggs\n {expected}\n')
1558+
1559+
def test_source_line_out_of_range(self):
1560+
self.assertEqual(self.warn_explicit(1000),
1561+
'nonexistent:1000: UserWarning: eggs\n')
1562+
1563+
class CWarnExplicitSourceTests(WarnExplicitSourceTests, unittest.TestCase):
1564+
module = c_warnings
1565+
1566+
class PyWarnExplicitSourceTests(WarnExplicitSourceTests, unittest.TestCase):
1567+
module = py_warnings
1568+
1569+
15391570
class BootstrapTest(unittest.TestCase):
15401571

15411572
def test_issue_8766(self):
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
:func:`warnings.warn_explicit` now displays the source line taken from the
2+
loader of the module whose globals are passed as *module_globals*. It also
3+
no longer raises :exc:`IndexError` if *lineno* is out of the range of the
4+
module source.

Python/_warnings.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,9 @@ call_show_warning(PyThreadState *tstate, PyObject *category,
595595
}
596596

597597
msg = PyObject_CallFunctionObjArgs(warnmsg_cls, message, category,
598-
filename, lineno_obj, Py_None, Py_None, source,
598+
filename, lineno_obj, Py_None,
599+
sourceline ? sourceline : Py_None,
600+
source,
599601
NULL);
600602
Py_DECREF(warnmsg_cls);
601603
if (msg == NULL)
@@ -1100,8 +1102,11 @@ get_source_line(PyInterpreterState *interp, PyObject *module_globals, int lineno
11001102
}
11011103

11021104
/* Get the source line. */
1103-
source_line = PyList_GetItem(source_list, lineno-1);
1104-
Py_XINCREF(source_line);
1105+
if (lineno < 1 || lineno > PyList_GET_SIZE(source_list)) {
1106+
Py_DECREF(source_list);
1107+
return NULL;
1108+
}
1109+
source_line = Py_NewRef(PyList_GET_ITEM(source_list, lineno-1));
11051110
Py_DECREF(source_list);
11061111
return source_line;
11071112
}

0 commit comments

Comments
 (0)