mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Close #744: autodoc: Support abstractmethod
This commit is contained in:
parent
358e582490
commit
e288999933
1
CHANGES
1
CHANGES
@ -81,6 +81,7 @@ Features added
|
||||
* #6289: autodoc: :confval:`autodoc_default_options` now supports
|
||||
``imported-members`` option
|
||||
* #4777: autodoc: Support coroutine
|
||||
* #744: autodoc: Support abstractmethod
|
||||
* #6212 autosummary: Add :confval:`autosummary_imported_members` to display
|
||||
imported members on autosummary
|
||||
* #6271: ``make clean`` is catastrophically broken if building into '.'
|
||||
|
@ -1338,6 +1338,8 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
||||
|
||||
sourcename = self.get_sourcename()
|
||||
obj = self.parent.__dict__.get(self.object_name, self.object)
|
||||
if inspect.isabstractmethod(obj):
|
||||
self.add_line(' :abstractmethod:', sourcename)
|
||||
if inspect.iscoroutinefunction(obj):
|
||||
self.add_line(' :async:', sourcename)
|
||||
if inspect.isclassmethod(obj):
|
||||
@ -1455,7 +1457,10 @@ class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): #
|
||||
def add_directive_header(self, sig):
|
||||
# type: (str) -> None
|
||||
super().add_directive_header(sig)
|
||||
self.add_line(' :property:', self.get_sourcename())
|
||||
sourcename = self.get_sourcename()
|
||||
if inspect.isabstractmethod(self.object):
|
||||
self.add_line(' :abstractmethod:', sourcename)
|
||||
self.add_line(' :property:', sourcename)
|
||||
|
||||
|
||||
class InstanceAttributeDocumenter(AttributeDocumenter):
|
||||
|
@ -172,6 +172,12 @@ def isdescriptor(x):
|
||||
return False
|
||||
|
||||
|
||||
def isabstractmethod(obj):
|
||||
# type: (Any) -> bool
|
||||
"""Check if the object is an abstractmethod."""
|
||||
return safe_getattr(obj, '__isabstractmethod__', False) is True
|
||||
|
||||
|
||||
def isattributedescriptor(obj):
|
||||
# type: (Any) -> bool
|
||||
"""Check if the object is an attribute like descriptor."""
|
||||
@ -231,7 +237,7 @@ def isproperty(obj):
|
||||
|
||||
|
||||
def safe_getattr(obj, name, *defargs):
|
||||
# type: (Any, str, str) -> object
|
||||
# type: (Any, str, Any) -> Any
|
||||
"""A getattr() that turns all exceptions into AttributeErrors."""
|
||||
try:
|
||||
return getattr(obj, name, *defargs)
|
||||
@ -319,9 +325,9 @@ def is_builtin_class_method(obj, attr_name):
|
||||
classes = [c for c in inspect.getmro(obj) if attr_name in c.__dict__]
|
||||
cls = classes[0] if classes else object
|
||||
|
||||
if not hasattr(builtins, safe_getattr(cls, '__name__', '')): # type: ignore
|
||||
if not hasattr(builtins, safe_getattr(cls, '__name__', '')):
|
||||
return False
|
||||
return getattr(builtins, safe_getattr(cls, '__name__', '')) is cls # type: ignore
|
||||
return getattr(builtins, safe_getattr(cls, '__name__', '')) is cls
|
||||
|
||||
|
||||
class Parameter:
|
||||
|
29
tests/roots/test-ext-autodoc/target/abstractmethods.py
Normal file
29
tests/roots/test-ext-autodoc/target/abstractmethods.py
Normal file
@ -0,0 +1,29 @@
|
||||
from abc import abstractmethod
|
||||
|
||||
|
||||
class Base():
|
||||
def meth(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def abstractmeth(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def staticmeth():
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def classmeth(cls):
|
||||
pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def prop(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def coroutinemeth(self):
|
||||
pass
|
@ -1485,6 +1485,55 @@ def test_mocked_module_imports(app, warning):
|
||||
assert warning.getvalue() == ''
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('setup_test')
|
||||
def test_abstractmethods():
|
||||
options = {"members": None,
|
||||
"undoc-members": None}
|
||||
actual = do_autodoc(app, 'module', 'target.abstractmethods', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:module:: target.abstractmethods',
|
||||
'',
|
||||
'',
|
||||
'.. py:class:: Base',
|
||||
' :module: target.abstractmethods',
|
||||
'',
|
||||
' ',
|
||||
' .. py:method:: Base.abstractmeth()',
|
||||
' :module: target.abstractmethods',
|
||||
' :abstractmethod:',
|
||||
' ',
|
||||
' ',
|
||||
' .. py:method:: Base.classmeth()',
|
||||
' :module: target.abstractmethods',
|
||||
' :abstractmethod:',
|
||||
' :classmethod:',
|
||||
' ',
|
||||
' ',
|
||||
' .. py:method:: Base.coroutinemeth()',
|
||||
' :module: target.abstractmethods',
|
||||
' :abstractmethod:',
|
||||
' :async:',
|
||||
' ',
|
||||
' ',
|
||||
' .. py:method:: Base.meth()',
|
||||
' :module: target.abstractmethods',
|
||||
' ',
|
||||
' ',
|
||||
' .. py:method:: Base.prop',
|
||||
' :module: target.abstractmethods',
|
||||
' :abstractmethod:',
|
||||
' :property:',
|
||||
' ',
|
||||
' ',
|
||||
' .. py:method:: Base.staticmeth()',
|
||||
' :module: target.abstractmethods',
|
||||
' :abstractmethod:',
|
||||
' :staticmethod:',
|
||||
' '
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('setup_test')
|
||||
def test_partialfunction():
|
||||
options = {"members": None}
|
||||
|
Loading…
Reference in New Issue
Block a user