Source code for falcon.util.deprecation

# Copyright 2013 by Rackspace Hosting, Inc.
#
# 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.

"""Miscellaneous deprecation utilities.

This module provides decorators to mark functions and classes as deprecated.
"""

from __future__ import annotations

import functools
from typing import Any, Callable, Optional
import warnings

__all__ = (
    'AttributeRemovedError',
    'DeprecatedWarning',
    'deprecated',
    'deprecated_args',
)


class AttributeRemovedError(AttributeError):
    """A deprecated attribute, class, or function has been subsequently removed."""


# NOTE(kgriffs): We don't want our deprecations to be ignored by default,
# so create our own type.
#
# TODO(kgriffs): Revisit this decision if users complain.
class DeprecatedWarning(UserWarning):
    pass


[docs] def deprecated( instructions: str, is_property: bool = False, method_name: Optional[str] = None ) -> Callable[[Callable[..., Any]], Any]: """Flag a method as deprecated. This function returns a decorator which can be used to mark deprecated functions. Applying this decorator will result in a warning being emitted when the function is used. Args: instructions (str): Specific guidance for the developer, e.g.: 'Please migrate to add_proxy(...)'. is_property (bool): If the deprecated object is a property. It will omit the ``(...)`` from the generated documentation. method_name (str, optional): Set to override the name of the deprecated function or property in the generated documentation (default ``None``). This is useful when decorating an alias that carries the target's ``__name__``. """ def decorator(func: Callable[..., Any]) -> Callable[[Callable[..., Any]], Any]: object_name = 'property' if is_property else 'function' post_name = '' if is_property else '(...)' message = 'Call to deprecated {} {}{}. {}'.format( object_name, method_name or func.__name__, post_name, instructions ) @functools.wraps(func) def wrapper(*args: Any, **kwargs: Any) -> Callable[..., Any]: warnings.warn(message, category=DeprecatedWarning, stacklevel=2) return func(*args, **kwargs) return wrapper return decorator
[docs] def deprecated_args( *, allowed_positional: int, is_method: bool = True ) -> Callable[..., Callable[..., Any]]: """Flag a method call with positional args as deprecated. Keyword Args: allowed_positional (int): Number of allowed positional arguments is_method (bool, optional): The decorated function is a method. Will add one to the number of allowed positional args to account for ``self``. Defaults to True. """ template = ( 'Calls to {{fn}}(...) with{arg_text} positional args are deprecated.' ' Please specify them as keyword arguments instead.' ) text = ' more than {}'.format(allowed_positional) if allowed_positional else '' warn_text = template.format(arg_text=text) if is_method: allowed_positional += 1 def deprecated_args(fn: Callable[..., Any]) -> Callable[..., Callable[..., Any]]: @functools.wraps(fn) def wraps(*args: Any, **kwargs: Any) -> Callable[..., Any]: if len(args) > allowed_positional: warnings.warn( warn_text.format(fn=fn.__qualname__), DeprecatedWarning, stacklevel=2, ) return fn(*args, **kwargs) return wraps return deprecated_args