prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  `experimental` decorator breaks class documentation.
  The `experimental` decorator used on classes break documentation. This could be one manifestation but there is an issue with how the documentation including type hints are propagated to the decorated class. This does not apply for free functions.
  
  See https://github.com/optuna/optuna/pull/1265#issuecomment-633195955 for how it may break.
  
  ## Expected behavior
  
  Class documentation should not be altered by applying the experimental decorator.
  
  ## Steps to reproduce
  
  1. Apply the experimental decorator to a class.
  1. Build the document (`cd docs && make html`) 
  1. Open the rendered documentation and note that the class signatures is broken.
  
  ## Additional context (optional)
  
  - An issue regarding the indentation https://github.com/optuna/optuna/issues/1213.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `optuna/_experimental.py`
  Content:
  ```
  1 import functools
  2 import inspect
  3 from typing import Any
  4 from typing import Callable
  5 import warnings
  6 
  7 from optuna.exceptions import ExperimentalWarning
  8 
  9 
  10 # White spaces of each line are necessary to beautifully rendered documentation.
  11 # NOTE(crcrpar): When `experimental` decorator is applied to member methods, these lines require
  12 # another four spaces.
  13 _EXPERIMENTAL_DOCSTRING_TEMPLATE = """
  14 
  15     .. note::
  16         Added in v{ver} as an experimental feature. The interface may change in newer versions
  17         without prior notice. See https://github.com/optuna/optuna/releases/tag/v{ver}.
  18 """
  19 
  20 
  21 def _make_func_spec_str(func: Callable[..., Any]) -> str:
  22 
  23     name = func.__name__
  24     argspec = inspect.getfullargspec(func)
  25 
  26     n_defaults = len(argspec.defaults) if argspec.defaults is not None else 0
  27     offset = int(len(argspec.args) > 0 and argspec.args[0] == "self")
  28 
  29     if n_defaults > 0:
  30         args = ", ".join(argspec.args[offset:-n_defaults])
  31         with_default_values = ", ".join(
  32             [
  33                 "{}={}".format(a, d)
  34                 for a, d in zip(argspec.args[-n_defaults:], argspec.defaults)  # type: ignore
  35             ]
  36         )
  37     else:
  38         args = ", ".join(argspec.args[offset:])
  39         with_default_values = ""
  40 
  41     if len(args) > 0 and len(with_default_values) > 0:
  42         args += ", "
  43 
  44     # NOTE(crcrpar): The four spaces are necessary to correctly render documentation.
  45     # Different classes or methods require more spaces.
  46     str_args_description = "(" + args + with_default_values + ")\n\n    "
  47     return name + str_args_description
  48 
  49 
  50 def _validate_version(version: str) -> None:
  51 
  52     if not isinstance(version, str) or len(version.split(".")) != 3:
  53         raise ValueError(
  54             "Invalid version specification. Must follow `x.y.z` format but `{}` is given".format(
  55                 version
  56             )
  57         )
  58 
  59 
  60 def experimental(version: str, name: str = None) -> Any:
  61     """Decorate class or function as experimental.
  62 
  63     Args:
  64         version: The first version that supports the target feature.
  65         name: The name of the feature. Defaults to the function or class name. Optional.
  66     """
  67 
  68     _validate_version(version)
  69 
  70     def _experimental_wrapper(f: Any) -> Any:
  71         # f is either func or class.
  72 
  73         def _experimental_func(func: Callable[[Any], Any]) -> Callable[[Any], Any]:
  74 
  75             docstring = _EXPERIMENTAL_DOCSTRING_TEMPLATE.format(ver=version)
  76             if func.__doc__ is None:
  77                 func.__doc__ = ""
  78             func.__doc__ += docstring
  79 
  80             # TODO(crcrpar): Annotate this correctly.
  81             @functools.wraps(func)
  82             def new_func(*args: Any, **kwargs: Any) -> Any:
  83                 """Wrapped function."""
  84 
  85                 warnings.warn(
  86                     "{} is experimental (supported from v{}). "
  87                     "The interface can change in the future.".format(
  88                         name if name is not None else func.__name__, version
  89                     ),
  90                     ExperimentalWarning,
  91                 )
  92 
  93                 return func(*args, **kwargs)  # type: ignore
  94 
  95             return new_func
  96 
  97         def _experimental_class(cls: Any) -> Any:
  98             """Decorates a class as experimental.
  99 
  100             This decorator is supposed to be applied to the experimental class.
  101             """
  102 
  103             _original_init = cls.__init__
  104 
  105             def wrapped_init(self, *args, **kwargs) -> None:  # type: ignore
  106                 warnings.warn(
  107                     "{} is experimental (supported from v{}). "
  108                     "The interface can change in the future.".format(
  109                         name if name is not None else cls.__name__, version
  110                     ),
  111                     ExperimentalWarning,
  112                 )
  113 
  114                 _original_init(self, *args, **kwargs)
  115 
  116             cls.__init__ = wrapped_init
  117 
  118             if cls.__doc__ is None:
  119                 cls.__doc__ = ""
  120             cls.__doc__ = (
  121                 _make_func_spec_str(_original_init)
  122                 + cls.__doc__
  123                 + _EXPERIMENTAL_DOCSTRING_TEMPLATE.format(ver=version)
  124             )
  125             return cls
  126 
  127         return _experimental_class(f) if inspect.isclass(f) else _experimental_func(f)
  128 
  129     return _experimental_wrapper
  130
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/optuna/_experimental.py b/optuna/_experimental.py
  --- a/optuna/_experimental.py
  +++ b/optuna/_experimental.py
  @@ -18,35 +18,6 @@
   """
   
   
  -def _make_func_spec_str(func: Callable[..., Any]) -> str:
  -
  -    name = func.__name__
  -    argspec = inspect.getfullargspec(func)
  -
  -    n_defaults = len(argspec.defaults) if argspec.defaults is not None else 0
  -    offset = int(len(argspec.args) > 0 and argspec.args[0] == "self")
  -
  -    if n_defaults > 0:
  -        args = ", ".join(argspec.args[offset:-n_defaults])
  -        with_default_values = ", ".join(
  -            [
  -                "{}={}".format(a, d)
  -                for a, d in zip(argspec.args[-n_defaults:], argspec.defaults)  # type: ignore
  -            ]
  -        )
  -    else:
  -        args = ", ".join(argspec.args[offset:])
  -        with_default_values = ""
  -
  -    if len(args) > 0 and len(with_default_values) > 0:
  -        args += ", "
  -
  -    # NOTE(crcrpar): The four spaces are necessary to correctly render documentation.
  -    # Different classes or methods require more spaces.
  -    str_args_description = "(" + args + with_default_values + ")\n\n    "
  -    return name + str_args_description
  -
  -
   def _validate_version(version: str) -> None:
   
       if not isinstance(version, str) or len(version.split(".")) != 3:
  @@ -102,6 +73,7 @@
   
               _original_init = cls.__init__
   
  +            @functools.wraps(_original_init)
               def wrapped_init(self, *args, **kwargs) -> None:  # type: ignore
                   warnings.warn(
                       "{} is experimental (supported from v{}). "
  @@ -117,11 +89,7 @@
   
               if cls.__doc__ is None:
                   cls.__doc__ = ""
  -            cls.__doc__ = (
  -                _make_func_spec_str(_original_init)
  -                + cls.__doc__
  -                + _EXPERIMENTAL_DOCSTRING_TEMPLATE.format(ver=version)
  -            )
  +            cls.__doc__ += _EXPERIMENTAL_DOCSTRING_TEMPLATE.format(ver=version)
               return cls
   
           return _experimental_class(f) if inspect.isclass(f) else _experimental_func(f)
  
verification_info: {"golden_diff": "diff --git a/optuna/_experimental.py b/optuna/_experimental.py\n--- a/optuna/_experimental.py\n+++ b/optuna/_experimental.py\n@@ -18,35 +18,6 @@\n \"\"\"\n \n \n-def _make_func_spec_str(func: Callable[..., Any]) -> str:\n-\n-    name = func.__name__\n-    argspec = inspect.getfullargspec(func)\n-\n-    n_defaults = len(argspec.defaults) if argspec.defaults is not None else 0\n-    offset = int(len(argspec.args) > 0 and argspec.args[0] == \"self\")\n-\n-    if n_defaults > 0:\n-        args = \", \".join(argspec.args[offset:-n_defaults])\n-        with_default_values = \", \".join(\n-            [\n-                \"{}={}\".format(a, d)\n-                for a, d in zip(argspec.args[-n_defaults:], argspec.defaults)  # type: ignore\n-            ]\n-        )\n-    else:\n-        args = \", \".join(argspec.args[offset:])\n-        with_default_values = \"\"\n-\n-    if len(args) > 0 and len(with_default_values) > 0:\n-        args += \", \"\n-\n-    # NOTE(crcrpar): The four spaces are necessary to correctly render documentation.\n-    # Different classes or methods require more spaces.\n-    str_args_description = \"(\" + args + with_default_values + \")\\n\\n    \"\n-    return name + str_args_description\n-\n-\n def _validate_version(version: str) -> None:\n \n     if not isinstance(version, str) or len(version.split(\".\")) != 3:\n@@ -102,6 +73,7 @@\n \n             _original_init = cls.__init__\n \n+            @functools.wraps(_original_init)\n             def wrapped_init(self, *args, **kwargs) -> None:  # type: ignore\n                 warnings.warn(\n                     \"{} is experimental (supported from v{}). \"\n@@ -117,11 +89,7 @@\n \n             if cls.__doc__ is None:\n                 cls.__doc__ = \"\"\n-            cls.__doc__ = (\n-                _make_func_spec_str(_original_init)\n-                + cls.__doc__\n-                + _EXPERIMENTAL_DOCSTRING_TEMPLATE.format(ver=version)\n-            )\n+            cls.__doc__ += _EXPERIMENTAL_DOCSTRING_TEMPLATE.format(ver=version)\n             return cls\n \n         return _experimental_class(f) if inspect.isclass(f) else _experimental_func(f)\n", "issue": "`experimental` decorator breaks class documentation.\nThe `experimental` decorator used on classes break documentation. This could be one manifestation but there is an issue with how the documentation including type hints are propagated to the decorated class. This does not apply for free functions.\r\n\r\nSee https://github.com/optuna/optuna/pull/1265#issuecomment-633195955 for how it may break.\r\n\r\n## Expected behavior\r\n\r\nClass documentation should not be altered by applying the experimental decorator.\r\n\r\n## Steps to reproduce\r\n\r\n1. Apply the experimental decorator to a class.\r\n1. Build the document (`cd docs && make html`) \r\n1. Open the rendered documentation and note that the class signatures is broken.\r\n\r\n## Additional context (optional)\r\n\r\n- An issue regarding the indentation https://github.com/optuna/optuna/issues/1213.\r\n\n", "before_files": [{"content": "import functools\nimport inspect\nfrom typing import Any\nfrom typing import Callable\nimport warnings\n\nfrom optuna.exceptions import ExperimentalWarning\n\n\n# White spaces of each line are necessary to beautifully rendered documentation.\n# NOTE(crcrpar): When `experimental` decorator is applied to member methods, these lines require\n# another four spaces.\n_EXPERIMENTAL_DOCSTRING_TEMPLATE = \"\"\"\n\n    .. note::\n        Added in v{ver} as an experimental feature. The interface may change in newer versions\n        without prior notice. See https://github.com/optuna/optuna/releases/tag/v{ver}.\n\"\"\"\n\n\ndef _make_func_spec_str(func: Callable[..., Any]) -> str:\n\n    name = func.__name__\n    argspec = inspect.getfullargspec(func)\n\n    n_defaults = len(argspec.defaults) if argspec.defaults is not None else 0\n    offset = int(len(argspec.args) > 0 and argspec.args[0] == \"self\")\n\n    if n_defaults > 0:\n        args = \", \".join(argspec.args[offset:-n_defaults])\n        with_default_values = \", \".join(\n            [\n                \"{}={}\".format(a, d)\n                for a, d in zip(argspec.args[-n_defaults:], argspec.defaults)  # type: ignore\n            ]\n        )\n    else:\n        args = \", \".join(argspec.args[offset:])\n        with_default_values = \"\"\n\n    if len(args) > 0 and len(with_default_values) > 0:\n        args += \", \"\n\n    # NOTE(crcrpar): The four spaces are necessary to correctly render documentation.\n    # Different classes or methods require more spaces.\n    str_args_description = \"(\" + args + with_default_values + \")\\n\\n    \"\n    return name + str_args_description\n\n\ndef _validate_version(version: str) -> None:\n\n    if not isinstance(version, str) or len(version.split(\".\")) != 3:\n        raise ValueError(\n            \"Invalid version specification. Must follow `x.y.z` format but `{}` is given\".format(\n                version\n            )\n        )\n\n\ndef experimental(version: str, name: str = None) -> Any:\n    \"\"\"Decorate class or function as experimental.\n\n    Args:\n        version: The first version that supports the target feature.\n        name: The name of the feature. Defaults to the function or class name. Optional.\n    \"\"\"\n\n    _validate_version(version)\n\n    def _experimental_wrapper(f: Any) -> Any:\n        # f is either func or class.\n\n        def _experimental_func(func: Callable[[Any], Any]) -> Callable[[Any], Any]:\n\n            docstring = _EXPERIMENTAL_DOCSTRING_TEMPLATE.format(ver=version)\n            if func.__doc__ is None:\n                func.__doc__ = \"\"\n            func.__doc__ += docstring\n\n            # TODO(crcrpar): Annotate this correctly.\n            @functools.wraps(func)\n            def new_func(*args: Any, **kwargs: Any) -> Any:\n                \"\"\"Wrapped function.\"\"\"\n\n                warnings.warn(\n                    \"{} is experimental (supported from v{}). \"\n                    \"The interface can change in the future.\".format(\n                        name if name is not None else func.__name__, version\n                    ),\n                    ExperimentalWarning,\n                )\n\n                return func(*args, **kwargs)  # type: ignore\n\n            return new_func\n\n        def _experimental_class(cls: Any) -> Any:\n            \"\"\"Decorates a class as experimental.\n\n            This decorator is supposed to be applied to the experimental class.\n            \"\"\"\n\n            _original_init = cls.__init__\n\n            def wrapped_init(self, *args, **kwargs) -> None:  # type: ignore\n                warnings.warn(\n                    \"{} is experimental (supported from v{}). \"\n                    \"The interface can change in the future.\".format(\n                        name if name is not None else cls.__name__, version\n                    ),\n                    ExperimentalWarning,\n                )\n\n                _original_init(self, *args, **kwargs)\n\n            cls.__init__ = wrapped_init\n\n            if cls.__doc__ is None:\n                cls.__doc__ = \"\"\n            cls.__doc__ = (\n                _make_func_spec_str(_original_init)\n                + cls.__doc__\n                + _EXPERIMENTAL_DOCSTRING_TEMPLATE.format(ver=version)\n            )\n            return cls\n\n        return _experimental_class(f) if inspect.isclass(f) else _experimental_func(f)\n\n    return _experimental_wrapper\n", "path": "optuna/_experimental.py"}], "after_files": [{"content": "import functools\nimport inspect\nfrom typing import Any\nfrom typing import Callable\nimport warnings\n\nfrom optuna.exceptions import ExperimentalWarning\n\n\n# White spaces of each line are necessary to beautifully rendered documentation.\n# NOTE(crcrpar): When `experimental` decorator is applied to member methods, these lines require\n# another four spaces.\n_EXPERIMENTAL_DOCSTRING_TEMPLATE = \"\"\"\n\n    .. note::\n        Added in v{ver} as an experimental feature. The interface may change in newer versions\n        without prior notice. See https://github.com/optuna/optuna/releases/tag/v{ver}.\n\"\"\"\n\n\ndef _validate_version(version: str) -> None:\n\n    if not isinstance(version, str) or len(version.split(\".\")) != 3:\n        raise ValueError(\n            \"Invalid version specification. Must follow `x.y.z` format but `{}` is given\".format(\n                version\n            )\n        )\n\n\ndef experimental(version: str, name: str = None) -> Any:\n    \"\"\"Decorate class or function as experimental.\n\n    Args:\n        version: The first version that supports the target feature.\n        name: The name of the feature. Defaults to the function or class name. Optional.\n    \"\"\"\n\n    _validate_version(version)\n\n    def _experimental_wrapper(f: Any) -> Any:\n        # f is either func or class.\n\n        def _experimental_func(func: Callable[[Any], Any]) -> Callable[[Any], Any]:\n\n            docstring = _EXPERIMENTAL_DOCSTRING_TEMPLATE.format(ver=version)\n            if func.__doc__ is None:\n                func.__doc__ = \"\"\n            func.__doc__ += docstring\n\n            # TODO(crcrpar): Annotate this correctly.\n            @functools.wraps(func)\n            def new_func(*args: Any, **kwargs: Any) -> Any:\n                \"\"\"Wrapped function.\"\"\"\n\n                warnings.warn(\n                    \"{} is experimental (supported from v{}). \"\n                    \"The interface can change in the future.\".format(\n                        name if name is not None else func.__name__, version\n                    ),\n                    ExperimentalWarning,\n                )\n\n                return func(*args, **kwargs)  # type: ignore\n\n            return new_func\n\n        def _experimental_class(cls: Any) -> Any:\n            \"\"\"Decorates a class as experimental.\n\n            This decorator is supposed to be applied to the experimental class.\n            \"\"\"\n\n            _original_init = cls.__init__\n\n            @functools.wraps(_original_init)\n            def wrapped_init(self, *args, **kwargs) -> None:  # type: ignore\n                warnings.warn(\n                    \"{} is experimental (supported from v{}). \"\n                    \"The interface can change in the future.\".format(\n                        name if name is not None else cls.__name__, version\n                    ),\n                    ExperimentalWarning,\n                )\n\n                _original_init(self, *args, **kwargs)\n\n            cls.__init__ = wrapped_init\n\n            if cls.__doc__ is None:\n                cls.__doc__ = \"\"\n            cls.__doc__ += _EXPERIMENTAL_DOCSTRING_TEMPLATE.format(ver=version)\n            return cls\n\n        return _experimental_class(f) if inspect.isclass(f) else _experimental_func(f)\n\n    return _experimental_wrapper\n", "path": "optuna/_experimental.py"}]}