Handle singledispatch functions with rewritten signatures.

If a singledispatch function has its `__signature__` rewritten, autodoc
fails to annotate that signature because `func.__annotations__` is not
consulted.  Instead, directly assign to `__signature__` instead.
This commit is contained in:
Antony Lee 2020-03-10 10:58:18 +01:00
parent 5caaa5534b
commit f9048cf18e
2 changed files with 19 additions and 8 deletions

View File

@ -13,6 +13,7 @@
import importlib import importlib
import re import re
import warnings import warnings
from inspect import Parameter
from types import ModuleType from types import ModuleType
from typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Union from typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Union
from unittest.mock import patch from unittest.mock import patch
@ -1108,9 +1109,10 @@ class SingledispatchFunctionDocumenter(FunctionDocumenter):
if len(sig.parameters) == 0: if len(sig.parameters) == 0:
return return
name = list(sig.parameters)[0] params = list(sig.parameters.values())
if name not in func.__annotations__: if params[0].annotation is Parameter.empty:
func.__annotations__[name] = typ params[0] = params[0].replace(annotation=typ)
func.__signature__ = sig.replace(parameters=params) # type: ignore
class DecoratorDocumenter(FunctionDocumenter): class DecoratorDocumenter(FunctionDocumenter):
@ -1508,13 +1510,14 @@ class SingledispatchMethodDocumenter(MethodDocumenter):
def annotate_to_first_argument(self, func: Callable, typ: Type) -> None: def annotate_to_first_argument(self, func: Callable, typ: Type) -> None:
"""Annotate type hint to the first argument of function if needed.""" """Annotate type hint to the first argument of function if needed."""
sig = inspect.signature(func, bound_method=True) sig = inspect.signature(func)
if len(sig.parameters) == 0: if len(sig.parameters) == 1:
return return
name = list(sig.parameters)[0] params = list(sig.parameters.values())
if name not in func.__annotations__: if params[1].annotation is Parameter.empty:
func.__annotations__[name] = typ params[1] = params[1].replace(annotation=typ)
func.__signature__ = sig.replace(parameters=params) # type: ignore
class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): # type: ignore class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): # type: ignore

View File

@ -1,4 +1,11 @@
from functools import singledispatch from functools import singledispatch
import inspect
def assign_signature(func):
# This is intended to cover more complex signature-rewriting decorators.
func.__signature__ = inspect.signature(func)
return func
@singledispatch @singledispatch
@ -14,6 +21,7 @@ def _func_int(arg, kwarg=None):
@func.register(str) @func.register(str)
@assign_signature
def _func_str(arg, kwarg=None): def _func_str(arg, kwarg=None):
"""A function for str.""" """A function for str."""
pass pass