Skip to content

Instantly share code, notes, and snippets.

@Phxntxm
Created May 28, 2020 00:22
Show Gist options
  • Save Phxntxm/c558176a5781798bcc0564886d223fb3 to your computer and use it in GitHub Desktop.
Save Phxntxm/c558176a5781798bcc0564886d223fb3 to your computer and use it in GitHub Desktop.
def deprecated(msg="", replace=None):
"""A decorator that denotes that an object wrapped with this is deprecated. This can be around classes,
methods, properties (only put it around the getter, not the setter), staticmethods, and classmethods.
Parameters
-----------
msg : :class:`str`
An extra message that will be put a line after the default one printed with the deprecation warning
replace : :class:`object`
Provide any method/class object that you want to be used in place of the deprecated object. This will
be included in the deprecation message
"""
# The actual decorator that wraps the object
def deprecated_decorator(obj):
# Check if it's a property, if it is then nothing is being "called"
# so we do not want to call our inner function, and the way to get the name is different
if isinstance(obj, property):
# We're only in here if the *property* was wrapped. AKA this decorator was before the property one
# Due to this, that is the object we have here. We want to use that propertie's getter method,
# and base the name off of that
message = f"{obj.fget.__module__}.{obj.fget.__qualname__} is deprecated " \
f"and will be removed in the next major version.\n{msg}".strip()
if replace is not None:
message += f" Use {replace.__module__}.{replace.__qualname__} instead"
_log_deprecation(message)
# Do not go into inner here, simply return what was given
return obj
# If the object wrapped (again, meaning the decorator was BEFORE the staticmethod/classmethod decorators
# then we need to get the functions assigned to these types
if isinstance(obj, (staticmethod, classmethod)):
func = obj.__func__
# otherwise, just use the object. This means classes and normal functions will go to this path
else:
func = obj
# Just create the message that will be sent in the deprecation warning
message = f"{func.__module__}.{func.__qualname__} is deprecated and will " \
f"be removed in the next major version.\n{msg}".strip()
if replace is not None:
message += f" Use {replace.__module__}.{replace.__qualname__} instead"
# This is the inner method, the one called when the object is actually called
@functools.wraps(obj)
def inner(*args, **kwargs):
# Since we intercepted the call here, we need to add the class manually
if isinstance(obj, classmethod):
args = list(args)
args.insert(0, func.__globals__[func.__qualname__.split('.')[0]])
# Simply send the warning, then call/return the function
_log_deprecation(message)
return func(*args, **kwargs)
return inner
return deprecated_decorator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment