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 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()
Broken C implementation:
$ python sample.py
/tmp/sample.py:12: UserWarning: Hello
ccc()
Correct Python implementation:
$ python sample.py
sys:1: UserWarning: Hello
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).
$ python --version
Python 3.12.7
CPython versions tested on:
3.12
Operating systems tested on:
Linux