mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Close #2755: autodoc: Support type_comment style annotation
Note: python3.8+ or typed_ast is required
This commit is contained in:
3
CHANGES
3
CHANGES
@@ -36,6 +36,9 @@ Features added
|
||||
* #6994: imgconverter: Support illustrator file (.ai) to .png conversion
|
||||
* autodoc: Support Positional-Only Argument separator (PEP-570 compliant)
|
||||
* #2755: autodoc: Add new event: :event:`autodoc-before-process-signature`
|
||||
* #2755: autodoc: Support type_comment style (ex. ``# type: (str) -> str``)
|
||||
annotation (python3.8+ or `typed_ast <https://github.com/python/typed_ast>`_
|
||||
is required)
|
||||
* SphinxTranslator now calls visitor/departure method for super node class if
|
||||
visitor/departure method for original node class not found
|
||||
|
||||
|
@@ -1574,5 +1574,6 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_event('autodoc-skip-member')
|
||||
|
||||
app.connect('config-inited', merge_autodoc_default_flags)
|
||||
app.setup_extension('sphinx.ext.autodoc.type_comment')
|
||||
|
||||
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
|
||||
|
74
sphinx/ext/autodoc/type_comment.py
Normal file
74
sphinx/ext/autodoc/type_comment.py
Normal file
@@ -0,0 +1,74 @@
|
||||
"""
|
||||
sphinx.ext.autodoc.type_comment
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Update annotations info of living objects using type_comments.
|
||||
|
||||
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import ast
|
||||
from inspect import getsource
|
||||
from typing import Any, Dict
|
||||
from typing import cast
|
||||
|
||||
import sphinx
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.pycode.ast import parse as ast_parse
|
||||
from sphinx.pycode.ast import unparse as ast_unparse
|
||||
from sphinx.util import inspect
|
||||
from sphinx.util import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_type_comment(obj: Any) -> ast.FunctionDef:
|
||||
"""Get type_comment'ed FunctionDef object from living object.
|
||||
|
||||
This tries to parse original code for living object and returns
|
||||
AST node for given *obj*. It requires py38+ or typed_ast module.
|
||||
"""
|
||||
try:
|
||||
source = getsource(obj)
|
||||
if source.startswith((' ', r'\t')):
|
||||
# subject is placed inside class or block. To read its docstring,
|
||||
# this adds if-block before the declaration.
|
||||
module = ast_parse('if True:\n' + source)
|
||||
subject = cast(ast.FunctionDef, module.body[0].body[0]) # type: ignore
|
||||
else:
|
||||
module = ast_parse(source)
|
||||
subject = cast(ast.FunctionDef, module.body[0]) # type: ignore
|
||||
|
||||
if getattr(subject, "type_comment", None):
|
||||
return ast_parse(subject.type_comment, mode='func_type') # type: ignore
|
||||
else:
|
||||
return None
|
||||
except (OSError, TypeError): # failed to load source code
|
||||
return None
|
||||
except SyntaxError: # failed to parse type_comments
|
||||
return None
|
||||
|
||||
|
||||
def update_annotations_using_type_comments(app: Sphinx, obj: Any, bound_method: bool) -> None:
|
||||
"""Update annotations info of *obj* using type_comments."""
|
||||
try:
|
||||
function = get_type_comment(obj)
|
||||
if function and hasattr(function, 'argtypes'):
|
||||
if function.argtypes != [ast.Ellipsis]: # type: ignore
|
||||
sig = inspect.signature(obj, bound_method)
|
||||
for i, param in enumerate(sig.parameters.values()):
|
||||
if param.name not in obj.__annotations__:
|
||||
annotation = ast_unparse(function.argtypes[i]) # type: ignore
|
||||
obj.__annotations__[param.name] = annotation
|
||||
|
||||
if 'return' not in obj.__annotations__:
|
||||
obj.__annotations__['return'] = ast_unparse(function.returns) # type: ignore
|
||||
except NotImplementedError as exc: # failed to ast.unparse()
|
||||
logger.warning("Failed to parse type_comment for %r: %s", obj, exc)
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.connect('autodoc-before-process-signature', update_annotations_using_type_comments)
|
||||
|
||||
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
|
@@ -2,9 +2,23 @@ def incr(a: int, b: int = 1) -> int:
|
||||
return a + b
|
||||
|
||||
|
||||
def decr(a, b = 1):
|
||||
# type: (int, int) -> int
|
||||
return a - b
|
||||
|
||||
|
||||
class Math:
|
||||
def __init__(self, s: str, o: object = None) -> None:
|
||||
pass
|
||||
|
||||
def incr(self, a: int, b: int = 1) -> int:
|
||||
return a + b
|
||||
|
||||
def decr(self, a, b = 1):
|
||||
# type: (int, int) -> int
|
||||
return a - b
|
||||
|
||||
|
||||
def complex_func(arg1, arg2, arg3=None, *args, **kwargs):
|
||||
# type: (str, List[int], Tuple[int, Union[str, Unknown]], *str, **str) -> None
|
||||
pass
|
||||
|
@@ -479,10 +479,23 @@ def test_autodoc_typehints_signature(app):
|
||||
' :module: target.typehints',
|
||||
'',
|
||||
' ',
|
||||
' .. py:method:: Math.decr(a: int, b: int = 1) -> int',
|
||||
' :module: target.typehints',
|
||||
' ',
|
||||
' ',
|
||||
' .. py:method:: Math.incr(a: int, b: int = 1) -> int',
|
||||
' :module: target.typehints',
|
||||
' ',
|
||||
'',
|
||||
'.. py:function:: complex_func(arg1: str, arg2: List[int], arg3: Tuple[int, '
|
||||
'Union[str, Unknown]] = None, *args: str, **kwargs: str) -> None',
|
||||
' :module: target.typehints',
|
||||
'',
|
||||
'',
|
||||
'.. py:function:: decr(a: int, b: int = 1) -> int',
|
||||
' :module: target.typehints',
|
||||
'',
|
||||
'',
|
||||
'.. py:function:: incr(a: int, b: int = 1) -> int',
|
||||
' :module: target.typehints',
|
||||
''
|
||||
@@ -505,10 +518,22 @@ def test_autodoc_typehints_none(app):
|
||||
' :module: target.typehints',
|
||||
'',
|
||||
' ',
|
||||
' .. py:method:: Math.decr(a, b=1)',
|
||||
' :module: target.typehints',
|
||||
' ',
|
||||
' ',
|
||||
' .. py:method:: Math.incr(a, b=1)',
|
||||
' :module: target.typehints',
|
||||
' ',
|
||||
'',
|
||||
'.. py:function:: complex_func(arg1, arg2, arg3=None, *args, **kwargs)',
|
||||
' :module: target.typehints',
|
||||
'',
|
||||
'',
|
||||
'.. py:function:: decr(a, b=1)',
|
||||
' :module: target.typehints',
|
||||
'',
|
||||
'',
|
||||
'.. py:function:: incr(a, b=1)',
|
||||
' :module: target.typehints',
|
||||
''
|
||||
|
Reference in New Issue
Block a user