summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES2
-rw-r--r--sphinx/ext/autodoc/__init__.py59
-rw-r--r--tests/roots/test-ext-autodoc/target/cached_property.py5
-rw-r--r--tests/roots/test-ext-autodoc/target/properties.py11
-rw-r--r--tests/test_ext_autodoc.py5
-rw-r--r--tests/test_ext_autodoc_autoclass.py15
-rw-r--r--tests/test_ext_autodoc_autoproperty.py41
7 files changed, 115 insertions, 23 deletions
diff --git a/CHANGES b/CHANGES
index 0097c68e7..e8f0b22d1 100644
--- a/CHANGES
+++ b/CHANGES
@@ -27,6 +27,8 @@ Deprecated
Features added
--------------
+* #11277: :rst:dir:`autoproperty` allows the return type to be specified as
+ a type comment (e.g., ``# type: () -> int``). Patch by Bénédikt Tran
* #10811: Autosummary: extend ``__all__`` to imported members for template rendering
when option ``autosummary_ignore_module_all`` is set to ``False``. Patch by
Clement Pinard
diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py
index f16072196..0bb5cb6a8 100644
--- a/sphinx/ext/autodoc/__init__.py
+++ b/sphinx/ext/autodoc/__init__.py
@@ -2706,6 +2706,16 @@ class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): #
self.isclassmethod = False
return ret
+ def format_args(self, **kwargs: Any) -> str | None:
+ func = self._get_property_getter()
+ if func is None:
+ return None
+
+ # update the annotations of the property getter
+ self.env.app.emit('autodoc-before-process-signature', func, False)
+ # correctly format the arguments for a property
+ return super().format_args(**kwargs)
+
def document_members(self, all_members: bool = False) -> None:
pass
@@ -2721,30 +2731,33 @@ class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): #
if self.isclassmethod:
self.add_line(' :classmethod:', sourcename)
- if safe_getattr(self.object, 'fget', None): # property
- func = self.object.fget
- elif safe_getattr(self.object, 'func', None): # cached_property
- func = self.object.func
- else:
- func = None
+ func = self._get_property_getter()
+ if func is None or self.config.autodoc_typehints == 'none':
+ return
- if func and self.config.autodoc_typehints != 'none':
- try:
- signature = inspect.signature(func,
- type_aliases=self.config.autodoc_type_aliases)
- if signature.return_annotation is not Parameter.empty:
- if self.config.autodoc_typehints_format == "short":
- objrepr = stringify_annotation(signature.return_annotation, "smart")
- else:
- objrepr = stringify_annotation(signature.return_annotation,
- "fully-qualified-except-typing")
- self.add_line(' :type: ' + objrepr, sourcename)
- except TypeError as exc:
- logger.warning(__("Failed to get a function signature for %s: %s"),
- self.fullname, exc)
- pass
- except ValueError:
- pass
+ try:
+ signature = inspect.signature(func,
+ type_aliases=self.config.autodoc_type_aliases)
+ if signature.return_annotation is not Parameter.empty:
+ if self.config.autodoc_typehints_format == "short":
+ objrepr = stringify_annotation(signature.return_annotation, "smart")
+ else:
+ objrepr = stringify_annotation(signature.return_annotation,
+ "fully-qualified-except-typing")
+ self.add_line(' :type: ' + objrepr, sourcename)
+ except TypeError as exc:
+ logger.warning(__("Failed to get a function signature for %s: %s"),
+ self.fullname, exc)
+ pass
+ except ValueError:
+ pass
+
+ def _get_property_getter(self):
+ if safe_getattr(self.object, 'fget', None): # property
+ return self.object.fget
+ if safe_getattr(self.object, 'func', None): # cached_property
+ return self.object.func
+ return None
def autodoc_attrgetter(app: Sphinx, obj: Any, name: str, *defargs: Any) -> Any:
diff --git a/tests/roots/test-ext-autodoc/target/cached_property.py b/tests/roots/test-ext-autodoc/target/cached_property.py
index 63ec09f8e..712d1d917 100644
--- a/tests/roots/test-ext-autodoc/target/cached_property.py
+++ b/tests/roots/test-ext-autodoc/target/cached_property.py
@@ -5,3 +5,8 @@ class Foo:
@cached_property
def prop(self) -> int:
return 1
+
+ @cached_property
+ def prop_with_type_comment(self):
+ # type: () -> int
+ return 1
diff --git a/tests/roots/test-ext-autodoc/target/properties.py b/tests/roots/test-ext-autodoc/target/properties.py
index 561daefb8..018f51ee4 100644
--- a/tests/roots/test-ext-autodoc/target/properties.py
+++ b/tests/roots/test-ext-autodoc/target/properties.py
@@ -9,3 +9,14 @@ class Foo:
@property
def prop2(self) -> int:
"""docstring"""
+
+ @property
+ def prop1_with_type_comment(self):
+ # type: () -> int
+ """docstring"""
+
+ @classmethod
+ @property
+ def prop2_with_type_comment(self):
+ # type: () -> int
+ """docstring"""
diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py
index 64347bbc6..1023323aa 100644
--- a/tests/test_ext_autodoc.py
+++ b/tests/test_ext_autodoc.py
@@ -1089,6 +1089,11 @@ def test_autodoc_cached_property(app):
' :module: target.cached_property',
' :type: int',
'',
+ '',
+ ' .. py:property:: Foo.prop_with_type_comment',
+ ' :module: target.cached_property',
+ ' :type: int',
+ '',
]
diff --git a/tests/test_ext_autodoc_autoclass.py b/tests/test_ext_autodoc_autoclass.py
index 2c70104ea..fd4e4165b 100644
--- a/tests/test_ext_autodoc_autoclass.py
+++ b/tests/test_ext_autodoc_autoclass.py
@@ -213,6 +213,13 @@ def test_properties(app):
' docstring',
'',
'',
+ ' .. py:property:: Foo.prop1_with_type_comment',
+ ' :module: target.properties',
+ ' :type: int',
+ '',
+ ' docstring',
+ '',
+ '',
' .. py:property:: Foo.prop2',
' :module: target.properties',
' :classmethod:',
@@ -220,6 +227,14 @@ def test_properties(app):
'',
' docstring',
'',
+ '',
+ ' .. py:property:: Foo.prop2_with_type_comment',
+ ' :module: target.properties',
+ ' :classmethod:',
+ ' :type: int',
+ '',
+ ' docstring',
+ '',
]
diff --git a/tests/test_ext_autodoc_autoproperty.py b/tests/test_ext_autodoc_autoproperty.py
index f982144a9..ca8b981d3 100644
--- a/tests/test_ext_autodoc_autoproperty.py
+++ b/tests/test_ext_autodoc_autoproperty.py
@@ -39,6 +39,35 @@ def test_class_properties(app):
@pytest.mark.sphinx('html', testroot='ext-autodoc')
+def test_properties_with_type_comment(app):
+ actual = do_autodoc(app, 'property', 'target.properties.Foo.prop1_with_type_comment')
+ assert list(actual) == [
+ '',
+ '.. py:property:: Foo.prop1_with_type_comment',
+ ' :module: target.properties',
+ ' :type: int',
+ '',
+ ' docstring',
+ '',
+ ]
+
+
+@pytest.mark.sphinx('html', testroot='ext-autodoc')
+def test_class_properties_with_type_comment(app):
+ actual = do_autodoc(app, 'property', 'target.properties.Foo.prop2_with_type_comment')
+ assert list(actual) == [
+ '',
+ '.. py:property:: Foo.prop2_with_type_comment',
+ ' :module: target.properties',
+ ' :classmethod:',
+ ' :type: int',
+ '',
+ ' docstring',
+ '',
+ ]
+
+
+@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_cached_properties(app):
actual = do_autodoc(app, 'property', 'target.cached_property.Foo.prop')
assert list(actual) == [
@@ -48,3 +77,15 @@ def test_cached_properties(app):
' :type: int',
'',
]
+
+
+@pytest.mark.sphinx('html', testroot='ext-autodoc')
+def test_cached_properties_with_type_comment(app):
+ actual = do_autodoc(app, 'property', 'target.cached_property.Foo.prop_with_type_comment')
+ assert list(actual) == [
+ '',
+ '.. py:property:: Foo.prop_with_type_comment',
+ ' :module: target.cached_property',
+ ' :type: int',
+ '',
+ ]