The only purpose of the module_globals argument of warnings.warn_explicit() is to get the source line of the warning from the module loader when the file cannot be read. The C implementation computes it in get_source_line(), but then throws it away.
call_show_warning() passes None in the line slot of WarningMessage and ignores its own sourceline argument:
msg = PyObject_CallFunctionObjArgs(warnmsg_cls, message, category, filename, lineno_obj, Py_None, Py_None, source ? source : Py_None, module, NULL);
sourceline is only used in the fallback show_warning() path, taken when warnings._showwarnmsg is not available.
As a result the source line is lost, while the pure Python implementation, which seeds linecache instead, displays it:
$ cat > spam.py <<EOF
import warnings
def f():
warnings.warn_explicit('eggs', UserWarning, 'bar', 1, module_globals=globals())
EOF
$ ./python -c 'import spam; spam.f()'
bar:1: UserWarning: eggs
$ ./python -c 'import sys; sys.modules["_warnings"] = None; import spam; spam.f()'
bar:1: UserWarning: eggs
import warnings
The None was added in 914cde8 together with the source argument, so the C implementation has never passed the source line.
Linked PRs
- gh-155319: Fix the source line of a warning issued with module_globals #155320
- [3.15] gh-155319: Fix the source line of a warning issued with module_globals (GH-155320) #155824
- [3.14] gh-155319: Fix the source line of a warning issued with module_globals (GH-155320) #155825
- [3.13] gh-155319: Fix the source line of a warning issued with module_globals (GH-155320) #155826