https://github.com/python/cpython/commit/00c4a946f48ccbef865deaa78d7578b9fecf1121
commit: 00c4a946f48ccbef865deaa78d7578b9fecf1121
branch: main
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-05-03T09:35:47Z
summary:
gh-143231: Add the module attribute to warnings.WarningMessage (GH-149298)
files:
A Misc/NEWS.d/next/Library/2026-05-02-18-23-50.gh-issue-143231.oBbQb5.rst
M Lib/_py_warnings.py
M Lib/test/test_warnings/__init__.py
M Python/_warnings.c
diff --git a/Lib/_py_warnings.py b/Lib/_py_warnings.py
index 81a386c4487d95..ab09913de6812d 100644
--- a/Lib/_py_warnings.py
+++ b/Lib/_py_warnings.py
@@ -620,17 +620,18 @@ def warn_explicit(message, category, filename, lineno,
linecache.getlines(filename, module_globals)
# Print message and context
- msg = _wm.WarningMessage(message, category, filename, lineno,
source=source)
+ msg = _wm.WarningMessage(message, category, filename, lineno,
+ module=module, source=source)
_wm._showwarnmsg(msg)
class WarningMessage(object):
_WARNING_DETAILS = ("message", "category", "filename", "lineno", "file",
- "line", "source")
+ "line", "source", "module")
def __init__(self, message, category, filename, lineno, file=None,
- line=None, source=None):
+ line=None, source=None, module=None):
self.message = message
self.category = category
self.filename = filename
@@ -638,12 +639,14 @@ def __init__(self, message, category, filename, lineno,
file=None,
self.file = file
self.line = line
self.source = source
+ self.module = module
self._category_name = category.__name__ if category else None
def __str__(self):
- return ("{message : %r, category : %r, filename : %r, lineno : %s, "
- "line : %r}" % (self.message, self._category_name,
- self.filename, self.lineno, self.line))
+ return ("{message : %r, category : %r, module : %r, "
+ "filename : %r, lineno : %s, line : %r}" % (
+ self.message, self._category_name, self.module,
+ self.filename, self.lineno, self.line))
def __repr__(self):
return f'<{type(self).__qualname__} {self}>'
diff --git a/Lib/test/test_warnings/__init__.py
b/Lib/test/test_warnings/__init__.py
index d86844c1a29a9a..bf1bcf8e6ed5d9 100644
--- a/Lib/test/test_warnings/__init__.py
+++ b/Lib/test/test_warnings/__init__.py
@@ -582,15 +582,19 @@ def test_warn_nonstandard_types(self):
# ``Warning() != Warning()``.
self.assertEqual(str(w[-1].message), str(UserWarning(ob)))
- def test_filename(self):
+ def test_filename_module(self):
with warnings_state(self.module):
with self.module.catch_warnings(record=True) as w:
warning_tests.inner("spam1")
self.assertEqual(os.path.basename(w[-1].filename),
"stacklevel.py")
+ self.assertEqual(w[-1].module,
+ "test.test_warnings.data.stacklevel")
warning_tests.outer("spam2")
self.assertEqual(os.path.basename(w[-1].filename),
"stacklevel.py")
+ self.assertEqual(w[-1].module,
+ "test.test_warnings.data.stacklevel")
def test_stacklevel(self):
# Test stacklevel argument
@@ -600,23 +604,32 @@ def test_stacklevel(self):
warning_tests.inner("spam3", stacklevel=1)
self.assertEqual(os.path.basename(w[-1].filename),
"stacklevel.py")
+ self.assertEqual(w[-1].module,
+ "test.test_warnings.data.stacklevel")
warning_tests.outer("spam4", stacklevel=1)
self.assertEqual(os.path.basename(w[-1].filename),
"stacklevel.py")
+ self.assertEqual(w[-1].module,
+ "test.test_warnings.data.stacklevel")
warning_tests.inner("spam5", stacklevel=2)
self.assertEqual(os.path.basename(w[-1].filename),
"__init__.py")
+ self.assertEqual(w[-1].module, __name__)
warning_tests.outer("spam6", stacklevel=2)
self.assertEqual(os.path.basename(w[-1].filename),
"stacklevel.py")
+ self.assertEqual(w[-1].module,
+ "test.test_warnings.data.stacklevel")
warning_tests.outer("spam6.5", stacklevel=3)
self.assertEqual(os.path.basename(w[-1].filename),
"__init__.py")
+ self.assertEqual(w[-1].module, __name__)
warning_tests.inner("spam7", stacklevel=9999)
self.assertEqual(os.path.basename(w[-1].filename),
"<sys>")
+ self.assertEqual(w[-1].module, "sys")
def test_stacklevel_import(self):
# Issue #24305: With stacklevel=2, module-level warnings should work.
@@ -627,6 +640,7 @@ def test_stacklevel_import(self):
import test.test_warnings.data.import_warning # noqa: F401
self.assertEqual(len(w), 1)
self.assertEqual(w[0].filename, __file__)
+ self.assertEqual(w[0].module, __name__)
def test_skip_file_prefixes(self):
with warnings_state(self.module):
@@ -638,20 +652,27 @@ def test_skip_file_prefixes(self):
"inner_api", stacklevel=2,
warnings_module=warning_tests.warnings)
self.assertEqual(w[-1].filename, __file__)
+ self.assertEqual(w[-1].module, __name__)
warning_tests.package("package api", stacklevel=2)
self.assertEqual(w[-1].filename, __file__)
+ self.assertEqual(w[-1].module, __name__)
self.assertEqual(w[-2].filename, w[-1].filename)
+ self.assertEqual(w[-2].module, w[-1].module)
# Low stacklevels are overridden to 2 behavior.
warning_tests.package("package api 1", stacklevel=1)
self.assertEqual(w[-1].filename, __file__)
+ self.assertEqual(w[-1].module, __name__)
warning_tests.package("package api 0", stacklevel=0)
self.assertEqual(w[-1].filename, __file__)
+ self.assertEqual(w[-1].module, __name__)
warning_tests.package("package api -99", stacklevel=-99)
self.assertEqual(w[-1].filename, __file__)
+ self.assertEqual(w[-1].module, __name__)
# The stacklevel still goes up out of the package.
warning_tests.package("prefix02", stacklevel=3)
self.assertIn("unittest", w[-1].filename)
+ self.assertStartsWith(w[-1].module, "unittest")
def test_skip_file_prefixes_file_path(self):
# see: gh-126209
@@ -662,6 +683,8 @@ def test_skip_file_prefixes_file_path(self):
self.assertEqual(len(w), 1)
self.assertNotEqual(w[-1].filename, skipped)
+ self.assertEqual(w[-1].filename, __file__)
+ self.assertEqual(w[-1].module, __name__)
def test_skip_file_prefixes_type_errors(self):
with warnings_state(self.module):
@@ -673,7 +696,7 @@ def test_skip_file_prefixes_type_errors(self):
with self.assertRaises(TypeError):
warn("msg", skip_file_prefixes="a sequence of strs")
- def test_exec_filename(self):
+ def test_exec_filename_module(self):
filename = "<warnings-test>"
codeobj = compile(("import warnings\n"
"warnings.warn('hello', UserWarning)"),
@@ -682,6 +705,12 @@ def test_exec_filename(self):
self.module.simplefilter("always", category=UserWarning)
exec(codeobj)
self.assertEqual(w[0].filename, filename)
+ self.assertEqual(w[0].module, __name__)
+ with self.module.catch_warnings(record=True) as w:
+ self.module.simplefilter("always", category=UserWarning)
+ exec(codeobj, {})
+ self.assertEqual(w[0].filename, filename)
+ self.assertEqual(w[0].module, '<string>')
def test_warn_explicit_non_ascii_filename(self):
with self.module.catch_warnings(record=True) as w:
diff --git
a/Misc/NEWS.d/next/Library/2026-05-02-18-23-50.gh-issue-143231.oBbQb5.rst
b/Misc/NEWS.d/next/Library/2026-05-02-18-23-50.gh-issue-143231.oBbQb5.rst
new file mode 100644
index 00000000000000..e4769866c2045d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-05-02-18-23-50.gh-issue-143231.oBbQb5.rst
@@ -0,0 +1 @@
+A *module* attribute has been added to :class:`!warnings.WarningMessage`.
diff --git a/Python/_warnings.c b/Python/_warnings.c
index 6b8fa19ff3f606..4f6de50efa14a8 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -716,7 +716,7 @@ static int
call_show_warning(PyThreadState *tstate, PyObject *category,
PyObject *text, PyObject *message,
PyObject *filename, int lineno, PyObject *lineno_obj,
- PyObject *sourceline, PyObject *source)
+ PyObject *sourceline, PyObject *source, PyObject *module)
{
PyObject *show_fn, *msg, *res, *warnmsg_cls = NULL;
PyInterpreterState *interp = tstate->interp;
@@ -747,7 +747,8 @@ 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, Py_None,
+ source ? source : Py_None, module,
NULL);
Py_DECREF(warnmsg_cls);
if (msg == NULL)
@@ -878,7 +879,7 @@ warn_explicit(PyThreadState *tstate, PyObject *category,
PyObject *message,
goto return_none;
if (rc == 0) {
if (call_show_warning(tstate, category, text, message, filename,
- lineno, lineno_obj, sourceline, source) < 0)
+ lineno, lineno_obj, sourceline, source, module)
< 0)
goto cleanup;
}
else /* if (rc == -1) */
_______________________________________________
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]