Skip to content
Permalink
Browse files

monkey patch warnings.showwarning to provide more context lines

  • Loading branch information...
cosmicexplorer committed Apr 4, 2019
1 parent 33d543d commit 47b0044a5d70916b0fa9385e46e56f7322fb269a
Showing with 35 additions and 8 deletions.
  1. +35 −8 src/python/pants/base/deprecated.py
@@ -7,6 +7,7 @@
import inspect
import sys
import warnings
from contextlib import contextmanager
from functools import wraps

import six
@@ -99,8 +100,30 @@ def _get_frame_info(stacklevel, context=1):
return frame_list[frame_stack_index]


@contextmanager
def _greater_warnings_context(context_lines_string):
"""Provide the `line` argument to warnings.showwarning().
warnings.warn_explicit() doesn't use the `line` argument to showwarning(), but we want to
make use of the warning filtering provided by warn_explicit(). This contextmanager overwrites the
showwarning() method to pipe in the desired amount of context lines when using warn_explicit().
"""
prev_showwarning = warnings.showwarning
def wrapped(message, category, filename, lineno, file=None, line=None):
return prev_showwarning(
message=message,
category=category,
filename=filename,
lineno=lineno,
file=file,
line=(line or context_lines_string))
warnings.showwarning = wrapped
yield
warnings.showwarning = prev_showwarning


def warn_or_error(removal_version, deprecated_entity_description, hint=None, stacklevel=3,
frame_info=None, ensure_stderr=False):
frame_info=None, context=1, ensure_stderr=False):
"""Check the removal_version against the current pants version.
Issues a warning if the removal version is > current pants version, or an error otherwise.
@@ -113,6 +136,8 @@ def warn_or_error(removal_version, deprecated_entity_description, hint=None, sta
:param int stacklevel: The stacklevel to pass to warnings.warn.
:param FrameInfo frame_info: If provided, use this frame info instead of getting one from
`stacklevel`.
:param int context: The number of lines of source code surrounding the selected frame to display
in a warning message.
:param bool ensure_stderr: Whether use warnings.warn, or use warnings.showwarning to print
directly to stderr.
:raises DeprecationApplicationError: if the removal_version parameter is invalid.
@@ -127,9 +152,10 @@ def warn_or_error(removal_version, deprecated_entity_description, hint=None, sta

# We need to have filename and line_number for warnings.formatwarning, which appears to be the only
# way to get a warning message to display to stderr. We get that from frame_info -- it's too bad
# we have to reconstruct the `stacklevel` logic ourselves.
# we have to reconstruct the `stacklevel` logic ourselves, but we do also gain the ability to have
# multiple lines of context, which is neat.
if frame_info is None:
frame_info = _get_frame_info(stacklevel, context=1)
frame_info = _get_frame_info(stacklevel, context=context)
_, filename, line_number, _, code_context, _ = frame_info
if code_context:
context_lines = ''.join(code_context)
@@ -144,11 +170,12 @@ def warn_or_error(removal_version, deprecated_entity_description, hint=None, sta
print(warning_msg, file=sys.stderr)
else:
# This output is filtered by warning filters.
warnings.warn_explicit(
message=DeprecationWarning(msg) if PY2 else msg,
category=DeprecationWarning,
filename=filename,
lineno=line_number)
with _greater_warnings_context(context_lines):
warnings.warn_explicit(
message=DeprecationWarning(msg) if PY2 else msg,
category=DeprecationWarning,
filename=filename,
lineno=line_number)
else:
raise CodeRemovedError(msg)

0 comments on commit 47b0044

Please sign in to comment.
You can’t perform that action at this time.