xref: /aosp_15_r20/external/pytorch/torch/onnx/_deprecation.py (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1"""Utility for deprecating functions."""
2
3import functools
4import textwrap
5import warnings
6from typing import Callable, TypeVar
7from typing_extensions import ParamSpec
8
9
10_T = TypeVar("_T")
11_P = ParamSpec("_P")
12
13
14def deprecated(
15    since: str, removed_in: str, instructions: str
16) -> Callable[[Callable[_P, _T]], Callable[_P, _T]]:
17    """Marks functions as deprecated.
18
19    It will result in a warning when the function is called and a note in the
20    docstring.
21
22    Args:
23        since: The version when the function was first deprecated.
24        removed_in: The version when the function will be removed.
25        instructions: The action users should take.
26    """
27
28    def decorator(function: Callable[_P, _T]) -> Callable[_P, _T]:
29        @functools.wraps(function)
30        def wrapper(*args: _P.args, **kwargs: _P.kwargs) -> _T:
31            warnings.warn(
32                f"'{function.__module__}.{function.__name__}' "
33                f"is deprecated in version {since} and will be "
34                f"removed in {removed_in}. Please {instructions}.",
35                category=FutureWarning,
36                stacklevel=2,
37            )
38            return function(*args, **kwargs)
39
40        # Add a deprecation note to the docstring.
41        docstring = function.__doc__ or ""
42
43        # Add a note to the docstring.
44        deprecation_note = textwrap.dedent(
45            f"""\
46            .. deprecated:: {since}
47                Deprecated and will be removed in version {removed_in}.
48                Please {instructions}.
49            """
50        )
51
52        # Split docstring at first occurrence of newline
53        summary_and_body = docstring.split("\n\n", 1)
54
55        if len(summary_and_body) > 1:
56            summary, body = summary_and_body
57
58            # Dedent the body. We cannot do this with the presence of the summary because
59            # the body contains leading whitespaces when the summary does not.
60            body = textwrap.dedent(body)
61
62            new_docstring_parts = [deprecation_note, "\n\n", summary, body]
63        else:
64            summary = summary_and_body[0]
65
66            new_docstring_parts = [deprecation_note, "\n\n", summary]
67
68        wrapper.__doc__ = "".join(new_docstring_parts)
69
70        return wrapper
71
72    return decorator
73