Decorator to mark a function or a class as deprecated.
    Parameters
    ----------
    since : str
        The release at which this API became deprecated.  This is
        required.
    message : str, optional
        Override the default deprecation message.  The format
        specifier `%(name)s` may be used for the name of the object,
        and `%(alternative)s` may be used in the deprecation message
        to insert the name of an alternative to the deprecated
        object.
    name : str, optional
        The name of the deprecated object; if not provided the name
        is automatically determined from the passed in object,
        though this is useful in the case of renamed functions, where
        the new function is just assigned to the name of the
        deprecated function.  For example::
            def new_function():
                ...
            oldFunction = new_function
    alternative : str, optional
        An alternative API that the user may use in place of the deprecated
        API.  The deprecation warning will tell the user about this alternative
        if provided.
    pending : bool, optional
        If True, uses a PendingDeprecationWarning instead of a
        DeprecationWarning.  Cannot be used together with *removal*.
    removal : str, optional
        The expected removal version.  With the default (an empty string), a
        removal version is automatically computed from *since*.  Set to other
        Falsy values to not schedule a removal date.  Cannot be used together
        with *pending*.
    addendum : str, optional
        Additional text appended directly to the final message.
    Examples
    --------
        Basic example::
            @deprecated('1.4.0')
            def the_function_to_deprecate():
                pass

def deprecated(since, message='', name='', alternative='', pending=False,
               addendum='', removal=''):
    """
    Decorator to mark a function or a class as deprecated.
    Parameters
    ----------
    since : str
        The release at which this API became deprecated.  This is
        required.
    message : str, optional
        Override the default deprecation message.  The format
        specifier `%(name)s` may be used for the name of the object,
        and `%(alternative)s` may be used in the deprecation message
        to insert the name of an alternative to the deprecated
        object.
    name : str, optional
        The name of the deprecated object; if not provided the name
        is automatically determined from the passed in object,
        though this is useful in the case of renamed functions, where
        the new function is just assigned to the name of the
        deprecated function.  For example::
            def new_function():
                ...
            oldFunction = new_function
    alternative : str, optional
        An alternative API that the user may use in place of the deprecated
        API.  The deprecation warning will tell the user about this alternative
        if provided.
    pending : bool, optional
        If True, uses a PendingDeprecationWarning instead of a
        DeprecationWarning.  Cannot be used together with *removal*.
    removal : str, optional
        The expected removal version.  With the default (an empty string), a
        removal version is automatically computed from *since*.  Set to other
        Falsy values to not schedule a removal date.  Cannot be used together
        with *pending*.
    addendum : str, optional
        Additional text appended directly to the final message.
    Examples
    --------
        Basic example::
            @deprecated('1.4.0')
            def the_function_to_deprecate():
                pass
    """

    def deprecate(obj, message=message, name=name, alternative=alternative,
                  pending=pending, addendum=addendum):

        if not name:
            name = obj.__name__

        if isinstance(obj, type):
            obj_type = "class"
            old_doc = obj.__doc__
            func = obj.__init__

            def finalize(wrapper, new_doc):
                obj.__doc__ = new_doc
                obj.__init__ = wrapper
                return obj
        else:
            obj_type = "function"
            if isinstance(obj, classmethod):
                func = obj.__func__
                old_doc = func.__doc__

                def finalize(wrapper, new_doc):
                    wrapper = functools.wraps(func)(wrapper)
                    wrapper.__doc__ = new_doc
                    return classmethod(wrapper)
            else:
                func = obj
                old_doc = func.__doc__

                def finalize(wrapper, new_doc):
                    wrapper = functools.wraps(func)(wrapper)
                    wrapper.__doc__ = new_doc
                    return wrapper

        message = _generate_deprecation_message(
            since, message, name, alternative, pending, obj_type, addendum,
            removal=removal)
        category = (PendingDeprecationWarning if pending
                    else _projectWarning)

        def wrapper(*args, **kwargs):
            warnings.warn(message, category, stacklevel=2)
            return func(*args, **kwargs)

        old_doc = textwrap.dedent(old_doc or '').strip('\n')
        message = message.strip()
        new_doc = (('\n.. deprecated:: %(since)s'
                    '\n    %(message)s\n\n' %
                    {'since': since, 'message': message}) + old_doc)
        if not old_doc:
            # This is to prevent a spurious 'unexected unindent' warning from
            # docutils when the original docstring was blank.
            new_doc += r'\ '

        return finalize(wrapper, new_doc)

    return deprecate