Ejemplo n.º 1
0
def deprecated_func(
    deprecated_version: str,
    removed_version: str,
    name: Optional[str] = None,
    text: Optional[str] = None,
) -> Callable[[Callable[FP, FT]], Callable[FP, FT]]:
    """Decorate function as deprecated.

    Args:
        deprecated_version:
            The version in which the target feature is deprecated.
        removed_version:
            The version in which the target feature will be removed.
        name:
            The name of the feature. Defaults to the function name. Optional.
        text:
            The additional text for the deprecation note. The default note is build using specified
            ``deprecated_version`` and ``removed_version``. If you want to provide additional
            information, please specify this argument yourself.

            .. note::
                The default deprecation note is as follows: "Deprecated in v{d_ver}. This feature
                will be removed in the future. The removal of this feature is currently scheduled
                for v{r_ver}, but this schedule is subject to change. See
                https://github.com/optuna/optuna/releases/tag/v{d_ver}."

            .. note::
                The specified text is concatenated after the default deprecation note.
    """

    _validate_version(deprecated_version)
    _validate_version(removed_version)
    _validate_two_version(deprecated_version, removed_version)

    def decorator(func: Callable[FP, FT]) -> Callable[FP, FT]:
        if func.__doc__ is None:
            func.__doc__ = ""

        note = _DEPRECATION_NOTE_TEMPLATE.format(d_ver=deprecated_version,
                                                 r_ver=removed_version)
        if text is not None:
            note += _format_text(text)
        indent = _get_docstring_indent(func.__doc__)
        func.__doc__ = func.__doc__.strip() + textwrap.indent(note,
                                                              indent) + indent

        @functools.wraps(func)
        def wrapper(*args: Any, **kwargs: Any) -> FT:
            """Decorates a function as deprecated.

            This decorator is supposed to be applied to the deprecated function.
            """

            message = _DEPRECATION_WARNING_TEMPLATE.format(
                name=(name if name is not None else func.__name__),
                d_ver=deprecated_version,
                r_ver=removed_version,
            )
            if text is not None:
                message += " " + text
            warnings.warn(message, FutureWarning, stacklevel=2)

            return func(*args, **kwargs)

        return wrapper

    return decorator
Ejemplo n.º 2
0
def deprecated(
    deprecated_version: str,
    removed_version: Optional[str] = None,
    name: Optional[str] = None,
    text: Optional[str] = None,
) -> Any:
    """Decorate class or function as deprecated.

    Args:
        deprecated_version:
            The version in which the target feature is deprecated.
        removed_version:
            The version in which the target feature will be removed. If :obj:`None`, determined
            based on the deprecated version. In this case, it will become the next next major
            version after the deprecated version. E.g. if ``deprecated_version`` is ``1.5.0``,
            this version becomes ``3.0.0``.
        name:
            The name of the feature. Defaults to the function or class name. Optional.
        text:
            The additional text for the deprecation note. The default note is build using specified
            ``deprecated_version`` and ``removed_version``. If you want to provide additional
            information, please specify this argument yourself.

            .. note::
                The default deprecation note is as follows: "Deprecated in v{d_ver}. This feature
                will be removed in the future. The removal of this feature is currently scheduled
                for v{r_ver}, but this schedule is subject to change. See
                https://github.com/optuna/optuna/releases/tag/v{d_ver}."

            .. note::
                The specified text is concatenated after the default deprecation note.
    """

    _validate_version(deprecated_version)
    if removed_version is None:
        removed_version = _get_removed_version_from_deprecated_version(
            deprecated_version)
    _validate_version(removed_version)
    _validate_two_version(deprecated_version, removed_version)

    def _deprecated_wrapper(f: Any) -> Any:
        # f is either func or class.

        def _deprecated_func(
                func: Callable[[Any], Any]) -> Callable[[Any], Any]:
            """Decorates a function as deprecated.

            This decorator is supposed to be applied to the deprecated function.
            """
            if func.__doc__ is None:
                func.__doc__ = ""

            note = _DEPRECATION_NOTE_TEMPLATE.format(d_ver=deprecated_version,
                                                     r_ver=removed_version)
            if text is not None:
                note += _format_text(text)
            indent = _get_docstring_indent(func.__doc__)
            func.__doc__ = func.__doc__.strip() + textwrap.indent(
                note, indent) + indent

            # TODO(mamu): Annotate this correctly.
            @functools.wraps(func)
            def new_func(*args: Any, **kwargs: Any) -> Any:
                warnings.warn(
                    "{} has been deprecated in v{}. "
                    "This feature will be removed in v{}.".format(
                        name if name is not None else func.__name__,
                        deprecated_version,
                        removed_version,
                    ),
                    FutureWarning,
                    stacklevel=2,
                )

                return func(*args, **kwargs)  # type: ignore

            return new_func

        def _deprecated_class(cls: Any) -> Any:
            """Decorates a class as deprecated.

            This decorator is supposed to be applied to the deprecated class.
            """
            _original_init = cls.__init__

            @functools.wraps(_original_init)
            def wrapped_init(self, *args, **kwargs) -> None:  # type: ignore
                warnings.warn(
                    "{} has been deprecated in v{}. "
                    "This feature will be removed in v{}.".format(
                        name if name is not None else cls.__name__,
                        deprecated_version,
                        removed_version,
                    ),
                    FutureWarning,
                    stacklevel=2,
                )

                _original_init(self, *args, **kwargs)

            cls.__init__ = wrapped_init

            if cls.__doc__ is None:
                cls.__doc__ = ""

            note = _DEPRECATION_NOTE_TEMPLATE.format(d_ver=deprecated_version,
                                                     r_ver=removed_version)
            if text is not None:
                note += _format_text(text)
            indent = _get_docstring_indent(cls.__doc__)
            cls.__doc__ = cls.__doc__.strip() + textwrap.indent(
                note, indent) + indent

            return cls

        return _deprecated_class(f) if inspect.isclass(
            f) else _deprecated_func(f)

    return _deprecated_wrapper
Ejemplo n.º 3
0
def deprecated_class(
    deprecated_version: str,
    removed_version: str,
    name: Optional[str] = None,
    text: Optional[str] = None,
) -> Callable[[CT], CT]:
    """Decorate class as deprecated.

    Args:
        deprecated_version:
            The version in which the target feature is deprecated.
        removed_version:
            The version in which the target feature will be removed.
        name:
            The name of the feature. Defaults to the class name. Optional.
        text:
            The additional text for the deprecation note. The default note is build using specified
            ``deprecated_version`` and ``removed_version``. If you want to provide additional
            information, please specify this argument yourself.

            .. note::
                The default deprecation note is as follows: "Deprecated in v{d_ver}. This feature
                will be removed in the future. The removal of this feature is currently scheduled
                for v{r_ver}, but this schedule is subject to change. See
                https://github.com/optuna/optuna/releases/tag/v{d_ver}."

            .. note::
                The specified text is concatenated after the default deprecation note.
    """

    _validate_version(deprecated_version)
    _validate_version(removed_version)
    _validate_two_version(deprecated_version, removed_version)

    def decorator(cls: CT) -> CT:
        def wrapper(cls: CT) -> CT:
            """Decorates a class as deprecated.

            This decorator is supposed to be applied to the deprecated class.
            """
            _original_init = getattr(cls, "__init__")
            _original_name = getattr(cls, "__name__")

            @functools.wraps(_original_init)
            def wrapped_init(self, *args, **kwargs) -> None:  # type: ignore
                message = _DEPRECATION_WARNING_TEMPLATE.format(
                    name=(name if name is not None else _original_name),
                    d_ver=deprecated_version,
                    r_ver=removed_version,
                )
                if text is not None:
                    message += " " + text
                warnings.warn(
                    message,
                    FutureWarning,
                    stacklevel=2,
                )

                _original_init(self, *args, **kwargs)

            setattr(cls, "__init__", wrapped_init)

            if cls.__doc__ is None:
                cls.__doc__ = ""

            note = _DEPRECATION_NOTE_TEMPLATE.format(d_ver=deprecated_version,
                                                     r_ver=removed_version)
            if text is not None:
                note += _format_text(text)
            indent = _get_docstring_indent(cls.__doc__)
            cls.__doc__ = cls.__doc__.strip() + textwrap.indent(
                note, indent) + indent

            return cls

        return wrapper(cls)

    return decorator