135 lines
4 KiB
Python
135 lines
4 KiB
Python
|
import sys
|
||
|
import warnings
|
||
|
import functools
|
||
|
|
||
|
__all__ = ["deprecated", "DeprecationDict"]
|
||
|
|
||
|
|
||
|
class deprecated(object):
|
||
|
"""Decorator to mark a function or class as deprecated.
|
||
|
|
||
|
Issue a warning when the function is called/the class is instantiated and
|
||
|
adds a warning to the docstring.
|
||
|
|
||
|
The optional extra argument will be appended to the deprecation message
|
||
|
and the docstring. Note: to use this with the default value for extra, put
|
||
|
in an empty of parentheses:
|
||
|
|
||
|
>>> from sklearn.utils import deprecated
|
||
|
>>> deprecated() # doctest: +ELLIPSIS
|
||
|
<sklearn.utils.deprecation.deprecated object at ...>
|
||
|
|
||
|
>>> @deprecated()
|
||
|
... def some_function(): pass
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
extra : string
|
||
|
to be added to the deprecation messages
|
||
|
"""
|
||
|
|
||
|
# Adapted from http://wiki.python.org/moin/PythonDecoratorLibrary,
|
||
|
# but with many changes.
|
||
|
|
||
|
def __init__(self, extra=''):
|
||
|
self.extra = extra
|
||
|
|
||
|
def __call__(self, obj):
|
||
|
"""Call method
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
obj : object
|
||
|
"""
|
||
|
if isinstance(obj, type):
|
||
|
return self._decorate_class(obj)
|
||
|
else:
|
||
|
return self._decorate_fun(obj)
|
||
|
|
||
|
def _decorate_class(self, cls):
|
||
|
msg = "Class %s is deprecated" % cls.__name__
|
||
|
if self.extra:
|
||
|
msg += "; %s" % self.extra
|
||
|
|
||
|
# FIXME: we should probably reset __new__ for full generality
|
||
|
init = cls.__init__
|
||
|
|
||
|
def wrapped(*args, **kwargs):
|
||
|
warnings.warn(msg, category=DeprecationWarning)
|
||
|
return init(*args, **kwargs)
|
||
|
cls.__init__ = wrapped
|
||
|
|
||
|
wrapped.__name__ = '__init__'
|
||
|
wrapped.__doc__ = self._update_doc(init.__doc__)
|
||
|
wrapped.deprecated_original = init
|
||
|
|
||
|
return cls
|
||
|
|
||
|
def _decorate_fun(self, fun):
|
||
|
"""Decorate function fun"""
|
||
|
|
||
|
msg = "Function %s is deprecated" % fun.__name__
|
||
|
if self.extra:
|
||
|
msg += "; %s" % self.extra
|
||
|
|
||
|
@functools.wraps(fun)
|
||
|
def wrapped(*args, **kwargs):
|
||
|
warnings.warn(msg, category=DeprecationWarning)
|
||
|
return fun(*args, **kwargs)
|
||
|
|
||
|
wrapped.__doc__ = self._update_doc(wrapped.__doc__)
|
||
|
|
||
|
return wrapped
|
||
|
|
||
|
def _update_doc(self, olddoc):
|
||
|
newdoc = "DEPRECATED"
|
||
|
if self.extra:
|
||
|
newdoc = "%s: %s" % (newdoc, self.extra)
|
||
|
if olddoc:
|
||
|
newdoc = "%s\n\n%s" % (newdoc, olddoc)
|
||
|
return newdoc
|
||
|
|
||
|
|
||
|
def _is_deprecated(func):
|
||
|
"""Helper to check if func is wraped by our deprecated decorator"""
|
||
|
if sys.version_info < (3, 5):
|
||
|
raise NotImplementedError("This is only available for python3.5 "
|
||
|
"or above")
|
||
|
closures = getattr(func, '__closure__', [])
|
||
|
if closures is None:
|
||
|
closures = []
|
||
|
is_deprecated = ('deprecated' in ''.join([c.cell_contents
|
||
|
for c in closures
|
||
|
if isinstance(c.cell_contents, str)]))
|
||
|
return is_deprecated
|
||
|
|
||
|
|
||
|
class DeprecationDict(dict):
|
||
|
"""A dict which raises a warning when some keys are looked up
|
||
|
|
||
|
Note, this does not raise a warning for __contains__ and iteration.
|
||
|
|
||
|
It also will raise a warning even after the key has been manually set by
|
||
|
the user.
|
||
|
"""
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
self._deprecations = {}
|
||
|
super(DeprecationDict, self).__init__(*args, **kwargs)
|
||
|
|
||
|
def __getitem__(self, key):
|
||
|
if key in self._deprecations:
|
||
|
warn_args, warn_kwargs = self._deprecations[key]
|
||
|
warnings.warn(*warn_args, **warn_kwargs)
|
||
|
return super(DeprecationDict, self).__getitem__(key)
|
||
|
|
||
|
def get(self, key, default=None):
|
||
|
# dict does not implement it like this, hence it needs to be overridden
|
||
|
try:
|
||
|
return self[key]
|
||
|
except KeyError:
|
||
|
return default
|
||
|
|
||
|
def add_warning(self, key, *args, **kwargs):
|
||
|
"""Add a warning to be triggered when the specified key is read"""
|
||
|
self._deprecations[key] = (args, kwargs)
|