diff -r ab6f520f3637 Lib/test/test_warnings/__init__.py --- a/Lib/test/test_warnings/__init__.py Mon Sep 21 01:11:26 2015 -0400 +++ b/Lib/test/test_warnings/__init__.py Mon Sep 21 21:20:32 2015 +0300 @@ -334,7 +334,7 @@ class WarnTests(BaseTest): warning_tests.inner("spam7", stacklevel=9999) self.assertEqual(os.path.basename(w[-1].filename), - "sys") + "runpy.py") def test_stacklevel_import(self): # Issue #24305: With stacklevel=2, module-level warnings should work. diff -r ab6f520f3637 Lib/warnings.py --- a/Lib/warnings.py Mon Sep 21 01:11:26 2015 -0400 +++ b/Lib/warnings.py Mon Sep 21 21:20:32 2015 +0300 @@ -188,17 +188,21 @@ def warn(message, category=None, stackle "not '{:s}'".format(type(category).__name__)) # Get context information try: - if stacklevel <= 1 or _is_internal_frame(sys._getframe(1)): + frame = sys._getframe(1) + if stacklevel <= 1 or _is_internal_frame(frame): # If frame is too small to care or if the warning originated in # internal code, then do not try to hide any frames. - frame = sys._getframe(stacklevel) + for x in range(stacklevel-1): + if frame.f_back is None: + break + frame = frame.f_back else: - frame = sys._getframe(1) # Look for one frame less since the above line starts us off. for x in range(stacklevel-1): - frame = _next_external_frame(frame) - if frame is None: - raise ValueError + f_back = _next_external_frame(frame) + if f_back is None: + break + frame = f_back except ValueError: globals = sys.__dict__ lineno = 1 diff -r ab6f520f3637 Python/_warnings.c --- a/Python/_warnings.c Mon Sep 21 01:11:26 2015 -0400 +++ b/Python/_warnings.c Mon Sep 21 21:20:32 2015 +0300 @@ -583,14 +583,20 @@ setup_context(Py_ssize_t stack_level, Py PyFrameObject *f = PyThreadState_GET()->frame; // Stack level comparisons to Python code is off by one as there is no // warnings-related stack level to avoid. - if (stack_level <= 0 || is_internal_frame(f)) { - while (--stack_level > 0 && f != NULL) { - f = f->f_back; + if (stack_level > 0 && f != NULL) { + if (is_internal_frame(f)) { + while (stack_level > 1 && f->f_back != NULL) { + f = f->f_back; + stack_level--; + } } - } - else { - while (--stack_level > 0 && f != NULL) { - f = next_external_frame(f); + else { + PyFrameObject *f_back; + while (stack_level > 1 && + (f_back = next_external_frame(f)) != NULL) { + f = f_back; + stack_level--; + } } }