Skip to content

Commit

Permalink
Fix sphinx-doc#7807: autodoc: wrong signature is shown for the functi…
Browse files Browse the repository at this point in the history
…on using contextmanager
  • Loading branch information
tk0miya committed Jun 13, 2020
1 parent b3affa6 commit 25aca87
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGES
Expand Up @@ -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
Expand Down
17 changes: 16 additions & 1 deletion sphinx/util/inspect.py
Expand Up @@ -9,6 +9,7 @@
"""

import builtins
import contextlib
import enum
import inspect
import re
Expand Down Expand Up @@ -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*.
Expand All @@ -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)
Expand Down
9 changes: 8 additions & 1 deletion tests/roots/test-ext-autodoc/target/wrappedfunction.py
@@ -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[None, None, None]:
"""You'll feel better in this context!"""
yield
13 changes: 13 additions & 0 deletions tests/test_ext_autodoc_autofunction.py
Expand Up @@ -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[None, None, None]',
' :module: target.wrappedfunction',
'',
" You'll feel better in this context!",
'',
]

0 comments on commit 25aca87

Please sign in to comment.