Skip to content

Commit

Permalink
Fix sphinx-doc#7383: autodoc: Support typehints for properties
Browse files Browse the repository at this point in the history
py:property directive now outputs py:property directive to describe
its type annotation.
  • Loading branch information
tk0miya committed Mar 11, 2021
1 parent 204f86f commit 0fd252f
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Features added
--------------

* #8924: autodoc: Support ``bound`` argument for TypeVar
* #7383: autodoc: Support typehints for properties
* #4826: py domain: Add ``:canonical:`` option to python directives to describe
the location where the object is defined
* #7199: py domain: Add :confval:`python_use_unqualified_type_names` to suppress
Expand Down
16 changes: 14 additions & 2 deletions sphinx/ext/autodoc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2526,7 +2526,6 @@ class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): #
Specialized Documenter subclass for properties.
"""
objtype = 'property'
directivetype = 'method'
member_order = 60

# before AttributeDocumenter
Expand All @@ -2549,7 +2548,20 @@ def add_directive_header(self, sig: str) -> None:
sourcename = self.get_sourcename()
if inspect.isabstractmethod(self.object):
self.add_line(' :abstractmethod:', sourcename)
self.add_line(' :property:', sourcename)

if self.object.fget:
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):
Expand Down
6 changes: 6 additions & 0 deletions tests/roots/test-ext-autodoc/target/properties.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class Foo:
"""docstring"""

@property
def prop(self) -> int:
"""docstring"""
9 changes: 3 additions & 6 deletions tests/test_ext_autodoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.',
''
Expand All @@ -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:',
'',
]

Expand Down Expand Up @@ -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()',
Expand Down
21 changes: 21 additions & 0 deletions tests/test_ext_autodoc_autoclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
29 changes: 29 additions & 0 deletions tests/test_ext_autodoc_autoproperty.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""
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',
'',
]

12 changes: 4 additions & 8 deletions tests/test_ext_autodoc_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand Down

0 comments on commit 0fd252f

Please sign in to comment.