diff options
author | Larry Hastings <larry@hastings.org> | 2015-09-06 07:39:37 (GMT) |
---|---|---|
committer | Larry Hastings <larry@hastings.org> | 2015-09-06 07:39:37 (GMT) |
commit | 714e49371b8d73059cf19f92a8566dcd20c6089a (patch) | |
tree | 1a90551d36b0ebe9b760ec948fe7bd3e5c6d0cee /Lib/warnings.py | |
parent | 62b24624dd3eec75869372e08d5ecbc4b8976101 (diff) | |
download | cpython-714e49371b8d73059cf19f92a8566dcd20c6089a.zip cpython-714e49371b8d73059cf19f92a8566dcd20c6089a.tar.gz cpython-714e49371b8d73059cf19f92a8566dcd20c6089a.tar.bz2 |
Issue #24305: Prevent import subsystem stack frames from being counted
by the warnings.warn(stacklevel=) parameter.
Diffstat (limited to 'Lib/warnings.py')
-rw-r--r-- | Lib/warnings.py | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/Lib/warnings.py b/Lib/warnings.py index 16246b4..1d4fb20 100644 --- a/Lib/warnings.py +++ b/Lib/warnings.py @@ -160,6 +160,20 @@ def _getcategory(category): return cat +def _is_internal_frame(frame): + """Signal whether the frame is an internal CPython implementation detail.""" + filename = frame.f_code.co_filename + return 'importlib' in filename and '_bootstrap' in filename + + +def _next_external_frame(frame): + """Find the next frame that doesn't involve CPython internals.""" + frame = frame.f_back + while frame is not None and _is_internal_frame(frame): + frame = frame.f_back + return frame + + # Code typically replaced by _warnings def warn(message, category=None, stacklevel=1): """Issue a warning, or maybe ignore it or raise an exception.""" @@ -174,13 +188,23 @@ def warn(message, category=None, stacklevel=1): "not '{:s}'".format(type(category).__name__)) # Get context information try: - caller = sys._getframe(stacklevel) + if stacklevel <= 1 or _is_internal_frame(sys._getframe(1)): + # 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) + 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 except ValueError: globals = sys.__dict__ lineno = 1 else: - globals = caller.f_globals - lineno = caller.f_lineno + globals = frame.f_globals + lineno = frame.f_lineno if '__name__' in globals: module = globals['__name__'] else: @@ -374,7 +398,6 @@ try: defaultaction = _defaultaction onceregistry = _onceregistry _warnings_defaults = True - except ImportError: filters = [] defaultaction = "default" |