Skip to content

Instantly share code, notes, and snippets.

@rwirth
Forked from kgriffs/util.py
Last active August 25, 2017 04:39
Show Gist options
  • Save rwirth/1233007ecebbcc2c8234824d83076e6b to your computer and use it in GitHub Desktop.
Save rwirth/1233007ecebbcc2c8234824d83076e6b to your computer and use it in GitHub Desktop.
Deprecated decorator for Python. Uses clever introspection to set a helpful filename and lineno in the warning message, even in complex cases like code being executed via execfile. The warning is properly registered and repeated only once for each 'offending' line (by default).
import functools
import inspect
import warnings
# NOTE(kgriffs): We don't want our deprecations to be ignored by default,
# so create our own type.
class DeprecatedWarning(UserWarning):
pass
def deprecated(instructions):
"""Flags a method as deprecated.
Args:
instructions: A human-friendly string of instructions, such
as: 'Please migrate to add_proxy() ASAP.'
"""
def decorator(func):
'''This is a decorator which can be used to mark functions
as deprecated. It will result in a warning being emitted
when the function is used.'''
module = inspect.getmodule(func)
@functools.wraps(func)
def new_func(*args, **kwargs):
if module is not None:
message = "Call to deprecated function {} (defined in {}). {}".format(func.__name__, module, instructions)
else:
message = "Call to deprecated function {}. {}".format(func.__name__, instructions)
frame = inspect.currentframe()
# walk the stack until we find a frame with valid source code
while frame is not None:
frame = frame.f_back
try:
filename = inspect.getsourcefile(frame)
lineno = frame.f_lineno
globals = frame.f_globals
except TypeError:
continue
else:
break
else:
filename = '<unknown>'
lineno = 0
globals = sys.__dict__ # this emulates behavior of warnings.warn
# create the warningregistry attribute if needed, emulates bevavior of warnings.warn
registry = globals.setdefault("__warningregistry__", {})
warnings.warn_explicit(
message,
category=DeprecatedWarning,
filename=filename,
lineno=lineno,
registry=registry
)
return func(*args, **kwargs)
return new_func
return decorator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment