Skip to content

Commit 94e5346

Browse files
[3.14] gh-155319: Fix the source line of a warning issued with module_globals (GH-155320) (GH-155825)
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 4dbd529 commit 94e5346

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
@@ -1601,6 +1601,37 @@ def test_RuntimeError(self):
16011601
_version=version)
16021602

16031603

1604+
class WarnExplicitSourceTests(BaseTest):
1605+
# gh-155319: the source line is taken from the loader of the module
1606+
# whose globals are passed as module_globals, if the file which name
1607+
# is passed as filename cannot be read.
1608+
1609+
def warn_explicit(self, lineno):
1610+
with support.captured_stderr() as stderr:
1611+
with self.module.catch_warnings():
1612+
self.module.simplefilter("always")
1613+
self.module.warn_explicit(
1614+
'eggs', UserWarning, 'nonexistent', lineno,
1615+
module_globals=warning_tests.__dict__)
1616+
return stderr.getvalue()
1617+
1618+
def test_source_line(self):
1619+
source = warning_tests.__loader__.get_source(warning_tests.__name__)
1620+
expected = source.splitlines()[0].strip()
1621+
self.assertEqual(self.warn_explicit(1),
1622+
f'nonexistent:1: UserWarning: eggs\n {expected}\n')
1623+
1624+
def test_source_line_out_of_range(self):
1625+
self.assertEqual(self.warn_explicit(1000),
1626+
'nonexistent:1000: UserWarning: eggs\n')
1627+
1628+
class CWarnExplicitSourceTests(WarnExplicitSourceTests, unittest.TestCase):
1629+
module = c_warnings
1630+
1631+
class PyWarnExplicitSourceTests(WarnExplicitSourceTests, unittest.TestCase):
1632+
module = py_warnings
1633+
1634+
16041635
class BootstrapTest(unittest.TestCase):
16051636

16061637
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
@@ -768,7 +768,9 @@ call_show_warning(PyThreadState *tstate, PyObject *category,
768768
}
769769

770770
msg = PyObject_CallFunctionObjArgs(warnmsg_cls, message, category,
771-
filename, lineno_obj, Py_None, Py_None, source,
771+
filename, lineno_obj, Py_None,
772+
sourceline ? sourceline : Py_None,
773+
source,
772774
NULL);
773775
Py_DECREF(warnmsg_cls);
774776
if (msg == NULL)
@@ -1269,8 +1271,11 @@ get_source_line(PyInterpreterState *interp, PyObject *module_globals, int lineno
12691271
}
12701272

12711273
/* Get the source line. */
1272-
source_line = PyList_GetItem(source_list, lineno-1);
1273-
Py_XINCREF(source_line);
1274+
if (lineno < 1 || lineno > PyList_GET_SIZE(source_list)) {
1275+
Py_DECREF(source_list);
1276+
return NULL;
1277+
}
1278+
source_line = Py_NewRef(PyList_GET_ITEM(source_list, lineno-1));
12741279
Py_DECREF(source_list);
12751280
return source_line;
12761281
}

0 commit comments

Comments
 (0)