# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import functools
import inspect
import six
import wrapt
from debtcollector import _utils
def _get_module_name(mod):
return _utils.get_qualified_name(mod)[1]
[docs]def remove(f=None, message=None, version=None, removal_version=None,
stacklevel=3, category=None):
"""Decorates a function, method, or class to emit a deprecation warning
:param str message: A message to include in the deprecation warning
:param str version: Specify what version the removed function is present in
:param str removal_version: What version the function will be removed. If
'?' is used this implies an undefined future
version
:param int stacklevel: How many entries deep in the call stack before
ignoring
:param type category: warnings message category (this defaults to
``DeprecationWarning`` when none is provided)
"""
if f is None:
return functools.partial(remove, message=message,
version=version,
removal_version=removal_version,
stacklevel=stacklevel,
category=category)
@wrapt.decorator
def wrapper(f, instance, args, kwargs):
qualified, f_name = _utils.get_qualified_name(f)
if qualified:
if inspect.isclass(f):
prefix_pre = "Using class"
thing_post = ''
else:
prefix_pre = "Using function/method"
thing_post = '()'
if not qualified:
prefix_pre = "Using function/method"
base_name = None
if instance is None:
# Decorator was used on a class
if inspect.isclass(f):
prefix_pre = "Using class"
thing_post = ''
module_name = _get_module_name(inspect.getmodule(f))
if module_name == '__main__':
f_name = _utils.get_class_name(
f, fully_qualified=False)
else:
f_name = _utils.get_class_name(
f, fully_qualified=True)
# Decorator was a used on a function
else:
thing_post = '()'
module_name = _get_module_name(inspect.getmodule(f))
if module_name != '__main__':
f_name = _utils.get_callable_name(f)
# Decorator was used on a classmethod or instancemethod
else:
thing_post = '()'
base_name = _utils.get_class_name(instance,
fully_qualified=False)
if base_name:
thing_name = ".".join([base_name, f_name])
else:
thing_name = f_name
else:
thing_name = f_name
if thing_post:
thing_name += thing_post
prefix = prefix_pre + " '%s' is deprecated" % (thing_name)
out_message = _utils.generate_message(
prefix,
version=version,
removal_version=removal_version,
message=message)
_utils.deprecation(out_message,
stacklevel=stacklevel, category=category)
return f(*args, **kwargs)
return wrapper(f)
[docs]def removed_kwarg(old_name, message=None,
version=None, removal_version=None, stacklevel=3,
category=None):
"""Decorates a kwarg accepting function to deprecate a removed kwarg."""
prefix = "Using the '%s' argument is deprecated" % old_name
out_message = _utils.generate_message(
prefix, postfix=None, message=message, version=version,
removal_version=removal_version)
@wrapt.decorator
def wrapper(f, instance, args, kwargs):
if old_name in kwargs:
_utils.deprecation(out_message,
stacklevel=stacklevel, category=category)
return f(*args, **kwargs)
return wrapper
[docs]def removed_module(module, replacement=None, message=None,
version=None, removal_version=None, stacklevel=3,
category=None):
"""Helper to be called inside a module to emit a deprecation warning
:param str replacment: A location (or information about) of any potential
replacement for the removed module (if applicable)
:param str message: A message to include in the deprecation warning
:param str version: Specify what version the removed module is present in
:param str removal_version: What version the module will be removed. If
'?' is used this implies an undefined future
version
:param int stacklevel: How many entries deep in the call stack before
ignoring
:param type category: warnings message category (this defaults to
``DeprecationWarning`` when none is provided)
"""
if inspect.ismodule(module):
module_name = _get_module_name(module)
elif isinstance(module, six.string_types):
module_name = module
else:
_qual, type_name = _utils.get_qualified_name(type(module))
raise TypeError("Unexpected module type '%s' (expected string or"
" module type only)" % type_name)
prefix = "The '%s' module usage is deprecated" % module_name
if replacement:
postfix = ", please use %s instead" % replacement
else:
postfix = None
out_message = _utils.generate_message(prefix,
postfix=postfix, message=message,
version=version,
removal_version=removal_version)
_utils.deprecation(out_message,
stacklevel=stacklevel, category=category)