https://github.com/python/cpython/commit/f61481fbec8cc12e20809af511d346c6b30e6c5e
commit: f61481fbec8cc12e20809af511d346c6b30e6c5e
branch: 3.13
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-08-15T07:36:11Z
summary:
[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 c92e2fd8f9c8af3ea383dec6222cfcca47a405ff)
files:
A Misc/NEWS.d/next/Library/2026-08-07-02-20-00.gh-issue-155319.srcline.rst
M Lib/test/test_warnings/__init__.py
M Python/_warnings.c
diff --git a/Lib/test/test_warnings/__init__.py
b/Lib/test/test_warnings/__init__.py
index bcbea1b29320275..7fbb1c99823770c 100644
--- a/Lib/test/test_warnings/__init__.py
+++ b/Lib/test/test_warnings/__init__.py
@@ -1536,6 +1536,37 @@ def test_RuntimeError(self):
_version=version)
+class WarnExplicitSourceTests(BaseTest):
+ # gh-155319: the source line is taken from the loader of the module
+ # whose globals are passed as module_globals, if the file which name
+ # is passed as filename cannot be read.
+
+ def warn_explicit(self, lineno):
+ with support.captured_stderr() as stderr:
+ with self.module.catch_warnings():
+ self.module.simplefilter("always")
+ self.module.warn_explicit(
+ 'eggs', UserWarning, 'nonexistent', lineno,
+ module_globals=warning_tests.__dict__)
+ return stderr.getvalue()
+
+ def test_source_line(self):
+ source = warning_tests.__loader__.get_source(warning_tests.__name__)
+ expected = source.splitlines()[0].strip()
+ self.assertEqual(self.warn_explicit(1),
+ f'nonexistent:1: UserWarning: eggs\n {expected}\n')
+
+ def test_source_line_out_of_range(self):
+ self.assertEqual(self.warn_explicit(1000),
+ 'nonexistent:1000: UserWarning: eggs\n')
+
+class CWarnExplicitSourceTests(WarnExplicitSourceTests, unittest.TestCase):
+ module = c_warnings
+
+class PyWarnExplicitSourceTests(WarnExplicitSourceTests, unittest.TestCase):
+ module = py_warnings
+
+
class BootstrapTest(unittest.TestCase):
def test_issue_8766(self):
diff --git
a/Misc/NEWS.d/next/Library/2026-08-07-02-20-00.gh-issue-155319.srcline.rst
b/Misc/NEWS.d/next/Library/2026-08-07-02-20-00.gh-issue-155319.srcline.rst
new file mode 100644
index 000000000000000..34a7ff83a73c0b8
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-08-07-02-20-00.gh-issue-155319.srcline.rst
@@ -0,0 +1,4 @@
+:func:`warnings.warn_explicit` now displays the source line taken from the
+loader of the module whose globals are passed as *module_globals*. It also
+no longer raises :exc:`IndexError` if *lineno* is out of the range of the
+module source.
diff --git a/Python/_warnings.c b/Python/_warnings.c
index 4bb83b214ae6cc7..fcd2c774d0a8f8f 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -595,7 +595,9 @@ call_show_warning(PyThreadState *tstate, PyObject *category,
}
msg = PyObject_CallFunctionObjArgs(warnmsg_cls, message, category,
- filename, lineno_obj, Py_None, Py_None, source,
+ filename, lineno_obj, Py_None,
+ sourceline ? sourceline : Py_None,
+ source,
NULL);
Py_DECREF(warnmsg_cls);
if (msg == NULL)
@@ -1100,8 +1102,11 @@ get_source_line(PyInterpreterState *interp, PyObject
*module_globals, int lineno
}
/* Get the source line. */
- source_line = PyList_GetItem(source_list, lineno-1);
- Py_XINCREF(source_line);
+ if (lineno < 1 || lineno > PyList_GET_SIZE(source_list)) {
+ Py_DECREF(source_list);
+ return NULL;
+ }
+ source_line = Py_NewRef(PyList_GET_ITEM(source_list, lineno-1));
Py_DECREF(source_list);
return source_line;
}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]