I was attempting to make warning.warn skip all frames in the calling file by setting skip_file_prefixes=(__file__,). Frustratingly it wasn't working as expected and was blaming an intermediate frame in the file I was trying to skip. Looking at Lib/warnings.py I was confused as to why it wasn't working. After some digging I discovered there is a parallel C implementation in Python/_warnings.c.
The following script demonstrates the difference between the two implementations:
import sys
# Uncomment to compare the C and Py implementation of warnings.warn.
# sys.modules["_warnings"] = None
import warnings
# Desired input which works as expected with the Py impl, but not the C impl.
skip_file_prefixes=(__file__,)
# Hack to make the C implementation match the Py behavior:
# skip_file_prefixes=(__file__[:-1],)
def ccc():
warnings.warn("Hello", UserWarning, skip_file_prefixes=skip_file_prefixes)
def bbb():
ccc()
def aaa():
bbb()
aaa()
There is a slight implementation difference between Python/_warnings.c:is_filename_to_skip and Lib/warnings.py:_is_filename_to_skip. The Python implementation is uses filename.startswith(prefix)^1 while the C implementation uses PyUnicode_Tailmatch(filename, prefix, 0, -1, -1)^2. It looks like the C implementation should be something like PyUnicode_Tailmatch(filename, prefix, 0, PY_SSIZE_T_MAX, -1).
Bug report
Bug description:
I was attempting to make warning.warn skip all frames in the calling file by setting
skip_file_prefixes=(__file__,)
. Frustratingly it wasn't working as expected and was blaming an intermediate frame in the file I was trying to skip. Looking atLib/warnings.py
I was confused as to why it wasn't working. After some digging I discovered there is a parallel C implementation inPython/_warnings.c
.The following script demonstrates the difference between the two implementations:
Broken C implementation:
Correct Python implementation:
There is a slight implementation difference between
Python/_warnings.c:is_filename_to_skip
andLib/warnings.py:_is_filename_to_skip
. The Python implementation is usesfilename.startswith(prefix)
^1 while the C implementation usesPyUnicode_Tailmatch(filename, prefix, 0, -1, -1)
^2. It looks like the C implementation should be something likePyUnicode_Tailmatch(filename, prefix, 0, PY_SSIZE_T_MAX, -1)
.CPython versions tested on:
3.12
Operating systems tested on:
Linux
Linked PRs