Skip to content

Instantly share code, notes, and snippets.

@tk0miya
Created February 13, 2020 02:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tk0miya/4279adc2d6ff4da52ea73c18cfdd229a to your computer and use it in GitHub Desktop.
Save tk0miya/4279adc2d6ff4da52ea73c18cfdd229a to your computer and use it in GitHub Desktop.
"""
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