Skip to content

Commit

Permalink
Merge branch '2.4.x' into 7183_attr_ref_over_intersphinx
Browse files Browse the repository at this point in the history
  • Loading branch information
tk0miya committed Feb 22, 2020
2 parents 2db006a + 404b507 commit 53e93c9
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Bugs fixed

* #7184: autodoc: ``*args`` and ``**kwarg`` in type comments are not handled
properly
* #7189: autodoc: classmethod coroutines are not detected
* #7183: intersphinx: ``:attr:`` reference to property is broken

Testing
Expand Down
21 changes: 17 additions & 4 deletions sphinx/util/inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,19 @@ def getargspec(func):
kwonlyargs, kwdefaults, annotations)


def unwrap(obj: Any) -> Any:
"""Get an original object from wrapped object."""
while True:
if ispartial(obj):
obj = unpartial(obj)
elif isclassmethod(obj):
obj = obj.__func__
elif isstaticmethod(obj):
obj = obj.__func__
else:
return obj


def isenumclass(x: Any) -> bool:
"""Check if the object is subclass of enum."""
return inspect.isclass(x) and issubclass(x, enum.Enum)
Expand Down Expand Up @@ -141,7 +154,7 @@ def isclassmethod(obj: Any) -> bool:
"""Check if the object is classmethod."""
if isinstance(obj, classmethod):
return True
elif inspect.ismethod(obj) and obj.__self__ is not None:
elif inspect.ismethod(obj) and obj.__self__ is not None and isclass(obj.__self__):
return True

return False
Expand Down Expand Up @@ -208,17 +221,17 @@ def isattributedescriptor(obj: Any) -> bool:

def isfunction(obj: Any) -> bool:
"""Check if the object is function."""
return inspect.isfunction(unpartial(obj))
return inspect.isfunction(unwrap(obj))


def isbuiltin(obj: Any) -> bool:
"""Check if the object is builtin."""
return inspect.isbuiltin(unpartial(obj))
return inspect.isbuiltin(unwrap(obj))


def iscoroutinefunction(obj: Any) -> bool:
"""Check if the object is coroutine-function."""
obj = unpartial(obj)
obj = unwrap(obj)
if hasattr(obj, '__code__') and inspect.iscoroutinefunction(obj):
# check obj.__code__ because iscoroutinefunction() crashes for custom method-like
# objects (see https://github.com/sphinx-doc/sphinx/issues/6605)
Expand Down
10 changes: 10 additions & 0 deletions tests/roots/test-ext-autodoc/target/coroutine.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ async def do_coroutine(self):
"""A documented coroutine function"""
attr_coro_result = await _other_coro_func() # NOQA

@classmethod
async def do_coroutine2(cls):
"""A documented coroutine classmethod"""
pass

@staticmethod
async def do_coroutine3():
"""A documented coroutine staticmethod"""
pass


async def _other_coro_func():
return "run"
18 changes: 17 additions & 1 deletion tests/test_autodoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1319,7 +1319,23 @@ def test_coroutine():
' :async:',
' ',
' A documented coroutine function',
' '
' ',
' ',
' .. py:method:: AsyncClass.do_coroutine2()',
' :module: target.coroutine',
' :async:',
' :classmethod:',
' ',
' A documented coroutine classmethod',
' ',
' ',
' .. py:method:: AsyncClass.do_coroutine3()',
' :module: target.coroutine',
' :async:',
' :staticmethod:',
' ',
' A documented coroutine staticmethod',
' ',
]


Expand Down
10 changes: 10 additions & 0 deletions tests/test_util_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,16 @@ def __repr__(self):
assert "<CustomType(2)>: 2" in description


@pytest.mark.sphinx(testroot='ext-autodoc')
def test_isclassmethod(app):
from target.methods import Base, Inherited

assert inspect.isclassmethod(Base.classmeth) is True
assert inspect.isclassmethod(Base.meth) is False
assert inspect.isclassmethod(Inherited.classmeth) is True
assert inspect.isclassmethod(Inherited.meth) is False


@pytest.mark.sphinx(testroot='ext-autodoc')
def test_isstaticmethod(app):
from target.methods import Base, Inherited
Expand Down

0 comments on commit 53e93c9

Please sign in to comment.