Created
February 13, 2020 02:54
-
-
Save tk0miya/4279adc2d6ff4da52ea73c18cfdd229a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
autodoc: show default value of arguments as is | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
:license: Same as Sphinx | |
""" | |
import ast | |
import inspect | |
from typing import Any, Dict | |
from sphinx.application import Sphinx | |
from sphinx.locale import __ | |
from sphinx.pycode.ast import parse as ast_parse | |
from sphinx.pycode.ast import unparse as ast_unparse | |
from sphinx.util import logging | |
logger = logging.getLogger(__name__) | |
class DefaultValue: | |
def __init__(self, name: str) -> None: | |
self.name = name | |
def __repr__(self) -> str: | |
return self.name | |
def get_function_def(obj: Any) -> ast.FunctionDef: | |
"""Get FunctionDef object from living object. | |
This tries to parse original code for living object and returns | |
AST node for given *obj*. | |
""" | |
try: | |
source = inspect.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) | |
return module.body[0].body[0] # type: ignore | |
else: | |
module = ast_parse(source) | |
return module.body[0] # type: ignore | |
except (OSError, TypeError): # failed to load source code | |
return None | |
def update_defvalue(app: Sphinx, obj: Any, bound_method: bool) -> None: | |
"""Update defvalue info of *obj* using type_comments.""" | |
try: | |
function = get_function_def(obj) | |
if function.args.defaults or function.args.kw_defaults: | |
sig = inspect.signature(obj) | |
defaults = list(function.args.defaults) | |
kw_defaults = list(function.args.kw_defaults) | |
parameters = list(sig.parameters.values()) | |
for i, param in enumerate(parameters): | |
if param.default is not param.empty: | |
if param.kind in (param.POSITIONAL_ONLY, param.POSITIONAL_OR_KEYWORD): | |
value = DefaultValue(ast_unparse(defaults.pop(0))) | |
parameters[i] = param.replace(default=value) | |
else: | |
value = DefaultValue(ast_unparse(kw_defaults.pop(0))) | |
parameters[i] = param.replace(default=value) | |
sig = sig.replace(parameters=parameters) | |
obj.__signature__ = sig | |
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_defvalue) | |
return { | |
'version': '1.0', | |
'parallel_read_safe': True | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment