Fix #7383: autodoc: Support typehints for properties

py:property directive now outputs py:property directive to describe
its type annotation.
This commit is contained in:
Takeshi KOMIYA 2021-03-11 02:01:17 +09:00
parent 17bb78997c
commit 75f5122996
7 changed files with 77 additions and 16 deletions

View File

@ -62,6 +62,7 @@ Features added
--------------
* #8924: autodoc: Support ``bound`` argument for TypeVar
* #7383: autodoc: Support typehints for properties
* #7549: autosummary: Enable :confval:`autosummary_generate` by default
* #4826: py domain: Add ``:canonical:`` option to python directives to describe
the location where the object is defined

View File

@ -2526,7 +2526,6 @@ class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): #
Specialized Documenter subclass for properties.
"""
objtype = 'property'
directivetype = 'method'
member_order = 60
# before AttributeDocumenter
@ -2549,7 +2548,20 @@ class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): #
sourcename = self.get_sourcename()
if inspect.isabstractmethod(self.object):
self.add_line(' :abstractmethod:', sourcename)
self.add_line(' :property:', sourcename)
if safe_getattr(self.object, 'fget', None):
try:
signature = inspect.signature(self.object.fget,
type_aliases=self.config.autodoc_type_aliases)
if signature.return_annotation is not Parameter.empty:
objrepr = stringify_typehint(signature.return_annotation)
self.add_line(' :type: ' + objrepr, sourcename)
except TypeError as exc:
logger.warning(__("Failed to get a function signature for %s: %s"),
self.fullname, exc)
return None
except ValueError:
raise
class NewTypeAttributeDocumenter(AttributeDocumenter):

View File

@ -0,0 +1,6 @@
class Foo:
"""docstring"""
@property
def prop(self) -> int:
"""docstring"""

View File

@ -1033,9 +1033,8 @@ def test_autodoc_descriptor(app):
' Descriptor instance docstring.',
'',
'',
' .. py:method:: Class.prop',
' .. py:property:: Class.prop',
' :module: target.descriptor',
' :property:',
'',
' Property.',
''
@ -1055,9 +1054,8 @@ def test_autodoc_cached_property(app):
' :module: target.cached_property',
'',
'',
' .. py:method:: Foo.prop',
' .. py:property:: Foo.prop',
' :module: target.cached_property',
' :property:',
'',
]
@ -1516,10 +1514,9 @@ def test_abstractmethods(app):
' :module: target.abstractmethods',
'',
'',
' .. py:method:: Base.prop',
' .. py:property:: Base.prop',
' :module: target.abstractmethods',
' :abstractmethod:',
' :property:',
'',
'',
' .. py:method:: Base.staticmeth()',

View File

@ -199,6 +199,27 @@ def test_decorators(app):
]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_properties(app):
options = {"members": None}
actual = do_autodoc(app, 'class', 'target.properties.Foo', options)
assert list(actual) == [
'',
'.. py:class:: Foo()',
' :module: target.properties',
'',
' docstring',
'',
'',
' .. py:property:: Foo.prop',
' :module: target.properties',
' :type: int',
'',
' docstring',
'',
]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_slots_attribute(app):
options = {"members": None}

View File

@ -0,0 +1,28 @@
"""
test_ext_autodoc_autoproperty
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Test the autodoc extension. This tests mainly the Documenters; the auto
directives are tested in a test source file translated by test_build.
:copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import pytest
from .test_ext_autodoc import do_autodoc
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_properties(app):
actual = do_autodoc(app, 'property', 'target.properties.Foo.prop')
assert list(actual) == [
'',
'.. py:property:: Foo.prop',
' :module: target.properties',
' :type: int',
'',
' docstring',
'',
]

View File

@ -261,16 +261,14 @@ def test_autodoc_docstring_signature(app):
' indented line',
'',
'',
' .. py:method:: DocstringSig.prop1',
' .. py:property:: DocstringSig.prop1',
' :module: target',
' :property:',
'',
' First line of docstring',
'',
'',
' .. py:method:: DocstringSig.prop2',
' .. py:property:: DocstringSig.prop2',
' :module: target',
' :property:',
'',
' First line of docstring',
' Second line of docstring',
@ -305,17 +303,15 @@ def test_autodoc_docstring_signature(app):
' indented line',
'',
'',
' .. py:method:: DocstringSig.prop1',
' .. py:property:: DocstringSig.prop1',
' :module: target',
' :property:',
'',
' DocstringSig.prop1(self)',
' First line of docstring',
'',
'',
' .. py:method:: DocstringSig.prop2',
' .. py:property:: DocstringSig.prop2',
' :module: target',
' :property:',
'',
' First line of docstring',
' Second line of docstring',