Fix #7807: autodoc: wrong signature is shown for the function using contextmanager

This commit is contained in:
Takeshi KOMIYA 2020-06-14 01:19:21 +09:00
parent b3affa6949
commit d77622ba79
4 changed files with 38 additions and 2 deletions

View File

@ -21,6 +21,7 @@ Bugs fixed
* #7808: autodoc: Warnings raised on variable and attribute type annotations
* #7802: autodoc: EOFError is raised on parallel build
* #7807: autodoc: wrong signature is shown for the function using contextmanager
* #7812: autosummary: generates broken stub files if the target code contains
an attribute and module that are same name
* #7811: sphinx.util.inspect causes circular import problem

View File

@ -9,6 +9,7 @@
"""
import builtins
import contextlib
import enum
import inspect
import re
@ -421,6 +422,17 @@ def is_builtin_class_method(obj: Any, attr_name: str) -> bool:
return getattr(builtins, name, None) is cls
def _should_unwrap(subject: Callable) -> bool:
"""Check the function should be unwrapped on getting signature."""
if (safe_getattr(subject, '__globals__', None) and
subject.__globals__.get('__name__') == 'contextlib' and # type: ignore
subject.__globals__.get('__file__') == contextlib.__file__): # type: ignore
# contextmanger should be unwrapped
return True
return False
def signature(subject: Callable, bound_method: bool = False, follow_wrapped: bool = False
) -> inspect.Signature:
"""Return a Signature object for the given *subject*.
@ -431,7 +443,10 @@ def signature(subject: Callable, bound_method: bool = False, follow_wrapped: boo
"""
try:
try:
signature = inspect.signature(subject, follow_wrapped=follow_wrapped)
if _should_unwrap(subject):
signature = inspect.signature(subject)
else:
signature = inspect.signature(subject, follow_wrapped=follow_wrapped)
except ValueError:
# follow built-in wrappers up (ex. functools.lru_cache)
signature = inspect.signature(subject)

View File

@ -1,8 +1,15 @@
# for py32 or above
from contextlib import contextmanager
from functools import lru_cache
from typing import Generator
@lru_cache(maxsize=None)
def slow_function(message, timeout):
"""This function is slow."""
print(message)
@contextmanager
def feeling_good(x: int, y: int) -> Generator:
"""You'll feel better in this context!"""
yield

View File

@ -146,3 +146,16 @@ def test_wrapped_function(app):
' This function is slow.',
'',
]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_wrapped_function_contextmanager(app):
actual = do_autodoc(app, 'function', 'target.wrappedfunction.feeling_good')
assert list(actual) == [
'',
'.. py:function:: feeling_good(x: int, y: int) -> Generator',
' :module: target.wrappedfunction',
'',
" You'll feel better in this context!",
'',
]