Migrate to py3 style type annotation: sphinx.ext.autodoc

This commit is contained in:
Takeshi KOMIYA 2019-06-30 00:52:32 +09:00
parent ad81d788f9
commit 22fd569f9b

View File

@ -12,15 +12,18 @@
import re import re
import warnings import warnings
from typing import Any from types import ModuleType
from typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Union
from docutils.statemachine import StringList from docutils.statemachine import StringList
import sphinx import sphinx
from sphinx.config import ENUM from sphinx.application import Sphinx
from sphinx.config import Config, ENUM
from sphinx.deprecation import ( from sphinx.deprecation import (
RemovedInSphinx30Warning, RemovedInSphinx40Warning, deprecated_alias RemovedInSphinx30Warning, RemovedInSphinx40Warning, deprecated_alias
) )
from sphinx.environment import BuildEnvironment
from sphinx.ext.autodoc.importer import import_object, get_object_members from sphinx.ext.autodoc.importer import import_object, get_object_members
from sphinx.ext.autodoc.mock import mock from sphinx.ext.autodoc.mock import mock
from sphinx.locale import _, __ from sphinx.locale import _, __
@ -35,12 +38,8 @@ from sphinx.util.inspect import (
if False: if False:
# For type annotation # For type annotation
from types import ModuleType # NOQA from sphinx.ext.autodoc.directive import DocumenterBridge
from typing import Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Union # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.config import Config # NOQA
from sphinx.environment import BuildEnvironment # NOQA
from sphinx.ext.autodoc.directive import DocumenterBridge # NOQA
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -61,8 +60,7 @@ py_ext_sig_re = re.compile(
''', re.VERBOSE) ''', re.VERBOSE)
def identity(x): def identity(x: Any) -> Any:
# type: (Any) -> Any
return x return x
@ -71,16 +69,14 @@ INSTANCEATTR = object()
SLOTSATTR = object() SLOTSATTR = object()
def members_option(arg): def members_option(arg: Any) -> Union[object, List[str]]:
# type: (Any) -> Union[object, List[str]]
"""Used to convert the :members: option to auto directives.""" """Used to convert the :members: option to auto directives."""
if arg is None or arg is True: if arg is None or arg is True:
return ALL return ALL
return [x.strip() for x in arg.split(',')] return [x.strip() for x in arg.split(',')]
def members_set_option(arg): def members_set_option(arg: Any) -> Union[object, Set[str]]:
# type: (Any) -> Union[object, Set[str]]
"""Used to convert the :members: option to auto directives.""" """Used to convert the :members: option to auto directives."""
if arg is None: if arg is None:
return ALL return ALL
@ -90,8 +86,7 @@ def members_set_option(arg):
SUPPRESS = object() SUPPRESS = object()
def annotation_option(arg): def annotation_option(arg: Any) -> Any:
# type: (Any) -> Any
if arg is None: if arg is None:
# suppress showing the representation of the object # suppress showing the representation of the object
return SUPPRESS return SUPPRESS
@ -99,16 +94,14 @@ def annotation_option(arg):
return arg return arg
def bool_option(arg): def bool_option(arg: Any) -> bool:
# type: (Any) -> bool
"""Used to convert flag options to auto directives. (Instead of """Used to convert flag options to auto directives. (Instead of
directives.flag(), which returns None). directives.flag(), which returns None).
""" """
return True return True
def merge_special_members_option(options): def merge_special_members_option(options: Dict) -> None:
# type: (Dict) -> None
"""Merge :special-members: option to :members: option.""" """Merge :special-members: option to :members: option."""
if 'special-members' in options and options['special-members'] is not ALL: if 'special-members' in options and options['special-members'] is not ALL:
if options.get('members') is ALL: if options.get('members') is ALL:
@ -123,8 +116,7 @@ def merge_special_members_option(options):
# Some useful event listener factories for autodoc-process-docstring. # Some useful event listener factories for autodoc-process-docstring.
def cut_lines(pre, post=0, what=None): def cut_lines(pre: int, post: int = 0, what: str = None) -> Callable:
# type: (int, int, str) -> Callable
"""Return a listener that removes the first *pre* and last *post* """Return a listener that removes the first *pre* and last *post*
lines of every docstring. If *what* is a sequence of strings, lines of every docstring. If *what* is a sequence of strings,
only docstrings of a type in *what* will be processed. only docstrings of a type in *what* will be processed.
@ -136,8 +128,8 @@ def cut_lines(pre, post=0, what=None):
This can (and should) be used in place of :confval:`automodule_skip_lines`. This can (and should) be used in place of :confval:`automodule_skip_lines`.
""" """
def process(app, what_, name, obj, options, lines): def process(app: Sphinx, what_: str, name: str, obj: Any, options: Any, lines: List[str]
# type: (Sphinx, str, str, Any, Any, List[str]) -> None ) -> None:
if what and what_ not in what: if what and what_ not in what:
return return
del lines[:pre] del lines[:pre]
@ -152,8 +144,8 @@ def cut_lines(pre, post=0, what=None):
return process return process
def between(marker, what=None, keepempty=False, exclude=False): def between(marker: str, what: Sequence[str] = None, keepempty: bool = False,
# type: (str, Sequence[str], bool, bool) -> Callable exclude: bool = False) -> Callable:
"""Return a listener that either keeps, or if *exclude* is True excludes, """Return a listener that either keeps, or if *exclude* is True excludes,
lines between lines that match the *marker* regular expression. If no line lines between lines that match the *marker* regular expression. If no line
matches, the resulting docstring would be empty, so no change will be made matches, the resulting docstring would be empty, so no change will be made
@ -164,8 +156,8 @@ def between(marker, what=None, keepempty=False, exclude=False):
""" """
marker_re = re.compile(marker) marker_re = re.compile(marker)
def process(app, what_, name, obj, options, lines): def process(app: Sphinx, what_: str, name: str, obj: Any, options: Any, lines: List[str]
# type: (Sphinx, str, str, Any, Any, List[str]) -> None ) -> None:
if what and what_ not in what: if what and what_ not in what:
return return
deleted = 0 deleted = 0
@ -192,8 +184,7 @@ def between(marker, what=None, keepempty=False, exclude=False):
# But we define this class here to keep compatibility (see #4538) # But we define this class here to keep compatibility (see #4538)
class Options(dict): class Options(dict):
"""A dict/attribute hybrid that returns None on nonexisting keys.""" """A dict/attribute hybrid that returns None on nonexisting keys."""
def __getattr__(self, name): def __getattr__(self, name: str) -> Any:
# type: (str) -> Any
try: try:
return self[name.replace('_', '-')] return self[name.replace('_', '-')]
except KeyError: except KeyError:
@ -229,19 +220,17 @@ class Documenter:
option_spec = {'noindex': bool_option} # type: Dict[str, Callable] option_spec = {'noindex': bool_option} # type: Dict[str, Callable]
def get_attr(self, obj, name, *defargs): def get_attr(self, obj: Any, name: str, *defargs) -> Any:
# type: (Any, str, Any) -> Any
"""getattr() override for types such as Zope interfaces.""" """getattr() override for types such as Zope interfaces."""
return autodoc_attrgetter(self.env.app, obj, name, *defargs) return autodoc_attrgetter(self.env.app, obj, name, *defargs)
@classmethod @classmethod
def can_document_member(cls, member, membername, isattr, parent): def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
# type: (Any, str, bool, Any) -> bool ) -> bool:
"""Called to see if a member can be documented by this documenter.""" """Called to see if a member can be documented by this documenter."""
raise NotImplementedError('must be implemented in subclasses') raise NotImplementedError('must be implemented in subclasses')
def __init__(self, directive, name, indent=''): def __init__(self, directive: "DocumenterBridge", name: str, indent: str = '') -> None:
# type: (DocumenterBridge, str, str) -> None
self.directive = directive self.directive = directive
self.env = directive.env # type: BuildEnvironment self.env = directive.env # type: BuildEnvironment
self.options = directive.genopt self.options = directive.genopt
@ -266,18 +255,16 @@ class Documenter:
self.analyzer = None # type: ModuleAnalyzer self.analyzer = None # type: ModuleAnalyzer
@property @property
def documenters(self): def documenters(self) -> Dict[str, Type["Documenter"]]:
# type: () -> Dict[str, Type[Documenter]]
"""Returns registered Documenter classes""" """Returns registered Documenter classes"""
return get_documenters(self.env.app) return get_documenters(self.env.app)
def add_line(self, line, source, *lineno): def add_line(self, line: str, source: str, *lineno: int) -> None:
# type: (str, str, int) -> None
"""Append one line of generated reST to the output.""" """Append one line of generated reST to the output."""
self.directive.result.append(self.indent + line, source, *lineno) self.directive.result.append(self.indent + line, source, *lineno)
def resolve_name(self, modname, parents, path, base): def resolve_name(self, modname: str, parents: Any, path: str, base: Any
# type: (str, Any, str, Any) -> Tuple[str, List[str]] ) -> Tuple[str, List[str]]:
"""Resolve the module and name of the object to document given by the """Resolve the module and name of the object to document given by the
arguments and the current module/class. arguments and the current module/class.
@ -287,8 +274,7 @@ class Documenter:
""" """
raise NotImplementedError('must be implemented in subclasses') raise NotImplementedError('must be implemented in subclasses')
def parse_name(self): def parse_name(self) -> bool:
# type: () -> bool
"""Determine what module to import and what attribute to document. """Determine what module to import and what attribute to document.
Returns True and sets *self.modname*, *self.objpath*, *self.fullname*, Returns True and sets *self.modname*, *self.objpath*, *self.fullname*,
@ -324,8 +310,7 @@ class Documenter:
(self.objpath and '.' + '.'.join(self.objpath) or '') (self.objpath and '.' + '.'.join(self.objpath) or '')
return True return True
def import_object(self): def import_object(self) -> bool:
# type: () -> bool
"""Import the object given by *self.modname* and *self.objpath* and set """Import the object given by *self.modname* and *self.objpath* and set
it as *self.object*. it as *self.object*.
@ -343,8 +328,7 @@ class Documenter:
self.env.note_reread() self.env.note_reread()
return False return False
def get_real_modname(self): def get_real_modname(self) -> str:
# type: () -> str
"""Get the real module name of an object to document. """Get the real module name of an object to document.
It can differ from the name of the module through which the object was It can differ from the name of the module through which the object was
@ -352,8 +336,7 @@ class Documenter:
""" """
return self.get_attr(self.object, '__module__', None) or self.modname return self.get_attr(self.object, '__module__', None) or self.modname
def check_module(self): def check_module(self) -> bool:
# type: () -> bool
"""Check if *self.object* is really defined in the module given by """Check if *self.object* is really defined in the module given by
*self.modname*. *self.modname*.
""" """
@ -367,16 +350,14 @@ class Documenter:
return False return False
return True return True
def format_args(self, **kwargs): def format_args(self, **kwargs) -> str:
# type: (Any) -> str
"""Format the argument signature of *self.object*. """Format the argument signature of *self.object*.
Should return None if the object does not have a signature. Should return None if the object does not have a signature.
""" """
return None return None
def format_name(self): def format_name(self) -> str:
# type: () -> str
"""Format the name of *self.object*. """Format the name of *self.object*.
This normally should be something that can be parsed by the generated This normally should be something that can be parsed by the generated
@ -387,8 +368,7 @@ class Documenter:
# directives of course) # directives of course)
return '.'.join(self.objpath) or self.modname return '.'.join(self.objpath) or self.modname
def format_signature(self, **kwargs): def format_signature(self, **kwargs) -> str:
# type: (Any) -> str
"""Format the signature (arguments and return annotation) of the object. """Format the signature (arguments and return annotation) of the object.
Let the user process it via the ``autodoc-process-signature`` event. Let the user process it via the ``autodoc-process-signature`` event.
@ -422,8 +402,7 @@ class Documenter:
else: else:
return '' return ''
def add_directive_header(self, sig): def add_directive_header(self, sig: str) -> None:
# type: (str) -> None
"""Add the directive header and options to the generated content.""" """Add the directive header and options to the generated content."""
domain = getattr(self, 'domain', 'py') domain = getattr(self, 'domain', 'py')
directive = getattr(self, 'directivetype', self.objtype) directive = getattr(self, 'directivetype', self.objtype)
@ -438,8 +417,7 @@ class Documenter:
# etc. don't support a prepended module name # etc. don't support a prepended module name
self.add_line(' :module: %s' % self.modname, sourcename) self.add_line(' :module: %s' % self.modname, sourcename)
def get_doc(self, encoding=None, ignore=1): def get_doc(self, encoding: str = None, ignore: int = 1) -> List[List[str]]:
# type: (str, int) -> List[List[str]]
"""Decode and return lines of the docstring(s) for the object.""" """Decode and return lines of the docstring(s) for the object."""
if encoding is not None: if encoding is not None:
warnings.warn("The 'encoding' argument to autodoc.%s.get_doc() is deprecated." warnings.warn("The 'encoding' argument to autodoc.%s.get_doc() is deprecated."
@ -452,8 +430,7 @@ class Documenter:
return [prepare_docstring(docstring, ignore, tab_width)] return [prepare_docstring(docstring, ignore, tab_width)]
return [] return []
def process_doc(self, docstrings): def process_doc(self, docstrings: List[List[str]]) -> Iterator[str]:
# type: (List[List[str]]) -> Iterator[str]
"""Let the user process the docstrings before adding them.""" """Let the user process the docstrings before adding them."""
for docstringlines in docstrings: for docstringlines in docstrings:
if self.env.app: if self.env.app:
@ -463,14 +440,12 @@ class Documenter:
self.options, docstringlines) self.options, docstringlines)
yield from docstringlines yield from docstringlines
def get_sourcename(self): def get_sourcename(self) -> str:
# type: () -> str
if self.analyzer: if self.analyzer:
return '%s:docstring of %s' % (self.analyzer.srcname, self.fullname) return '%s:docstring of %s' % (self.analyzer.srcname, self.fullname)
return 'docstring of %s' % self.fullname return 'docstring of %s' % self.fullname
def add_content(self, more_content, no_docstring=False): def add_content(self, more_content: Any, no_docstring: bool = False) -> None:
# type: (Any, bool) -> None
"""Add content from docstrings, attribute documentation and user.""" """Add content from docstrings, attribute documentation and user."""
# set sourcename and add content from attribute documentation # set sourcename and add content from attribute documentation
sourcename = self.get_sourcename() sourcename = self.get_sourcename()
@ -500,8 +475,7 @@ class Documenter:
for line, src in zip(more_content.data, more_content.items): for line, src in zip(more_content.data, more_content.items):
self.add_line(line, src[0], src[1]) self.add_line(line, src[0], src[1])
def get_object_members(self, want_all): def get_object_members(self, want_all: bool) -> Tuple[bool, List[Tuple[str, Any]]]:
# type: (bool) -> Tuple[bool, List[Tuple[str, Any]]]
"""Return `(members_check_module, members)` where `members` is a """Return `(members_check_module, members)` where `members` is a
list of `(membername, member)` pairs of the members of *self.object*. list of `(membername, member)` pairs of the members of *self.object*.
@ -527,8 +501,8 @@ class Documenter:
return False, sorted((m.name, m.value) for m in members.values() return False, sorted((m.name, m.value) for m in members.values()
if m.directly_defined) if m.directly_defined)
def filter_members(self, members, want_all): def filter_members(self, members: List[Tuple[str, Any]], want_all: bool
# type: (List[Tuple[str, Any]], bool) -> List[Tuple[str, Any, bool]] ) -> List[Tuple[str, Any, bool]]:
"""Filter the given member list. """Filter the given member list.
Members are skipped if Members are skipped if
@ -616,8 +590,7 @@ class Documenter:
return ret return ret
def document_members(self, all_members=False): def document_members(self, all_members: bool = False) -> None:
# type: (bool) -> None
"""Generate reST for member documentation. """Generate reST for member documentation.
If *all_members* is True, do all members, else those given by If *all_members* is True, do all members, else those given by
@ -669,8 +642,7 @@ class Documenter:
# sort by source order, by virtue of the module analyzer # sort by source order, by virtue of the module analyzer
tagorder = self.analyzer.tagorder tagorder = self.analyzer.tagorder
def keyfunc(entry): def keyfunc(entry: Tuple[Documenter, bool]) -> int:
# type: (Tuple[Documenter, bool]) -> int
fullname = entry[0].name.split('::')[1] fullname = entry[0].name.split('::')[1]
return tagorder.get(fullname, len(tagorder)) return tagorder.get(fullname, len(tagorder))
memberdocumenters.sort(key=keyfunc) memberdocumenters.sort(key=keyfunc)
@ -684,9 +656,8 @@ class Documenter:
self.env.temp_data['autodoc:module'] = None self.env.temp_data['autodoc:module'] = None
self.env.temp_data['autodoc:class'] = None self.env.temp_data['autodoc:class'] = None
def generate(self, more_content=None, real_modname=None, def generate(self, more_content: Any = None, real_modname: str = None,
check_module=False, all_members=False): check_module: bool = False, all_members: bool = False) -> None:
# type: (Any, str, bool, bool) -> None
"""Generate reST for the object given by *self.name*, and possibly for """Generate reST for the object given by *self.name*, and possibly for
its members. its members.
@ -778,26 +749,24 @@ class ModuleDocumenter(Documenter):
'imported-members': bool_option, 'ignore-module-all': bool_option 'imported-members': bool_option, 'ignore-module-all': bool_option
} # type: Dict[str, Callable] } # type: Dict[str, Callable]
def __init__(self, *args): def __init__(self, *args) -> None:
# type: (Any) -> None
super().__init__(*args) super().__init__(*args)
merge_special_members_option(self.options) merge_special_members_option(self.options)
@classmethod @classmethod
def can_document_member(cls, member, membername, isattr, parent): def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
# type: (Any, str, bool, Any) -> bool ) -> bool:
# don't document submodules automatically # don't document submodules automatically
return False return False
def resolve_name(self, modname, parents, path, base): def resolve_name(self, modname: str, parents: Any, path: str, base: Any
# type: (str, Any, str, Any) -> Tuple[str, List[str]] ) -> Tuple[str, List[str]]:
if modname is not None: if modname is not None:
logger.warning(__('"::" in automodule name doesn\'t make sense'), logger.warning(__('"::" in automodule name doesn\'t make sense'),
type='autodoc') type='autodoc')
return (path or '') + base, [] return (path or '') + base, []
def parse_name(self): def parse_name(self) -> bool:
# type: () -> bool
ret = super().parse_name() ret = super().parse_name()
if self.args or self.retann: if self.args or self.retann:
logger.warning(__('signature arguments or return annotation ' logger.warning(__('signature arguments or return annotation '
@ -805,8 +774,7 @@ class ModuleDocumenter(Documenter):
type='autodoc') type='autodoc')
return ret return ret
def add_directive_header(self, sig): def add_directive_header(self, sig: str) -> None:
# type: (str) -> None
Documenter.add_directive_header(self, sig) Documenter.add_directive_header(self, sig)
sourcename = self.get_sourcename() sourcename = self.get_sourcename()
@ -819,8 +787,7 @@ class ModuleDocumenter(Documenter):
if self.options.deprecated: if self.options.deprecated:
self.add_line(' :deprecated:', sourcename) self.add_line(' :deprecated:', sourcename)
def get_object_members(self, want_all): def get_object_members(self, want_all: bool) -> Tuple[bool, List[Tuple[str, object]]]:
# type: (bool) -> Tuple[bool, List[Tuple[str, object]]]
if want_all: if want_all:
if (self.options.ignore_module_all or not if (self.options.ignore_module_all or not
hasattr(self.object, '__all__')): hasattr(self.object, '__all__')):
@ -861,8 +828,8 @@ class ModuleLevelDocumenter(Documenter):
Specialized Documenter subclass for objects on module level (functions, Specialized Documenter subclass for objects on module level (functions,
classes, data/constants). classes, data/constants).
""" """
def resolve_name(self, modname, parents, path, base): def resolve_name(self, modname: str, parents: Any, path: str, base: Any
# type: (str, Any, str, Any) -> Tuple[str, List[str]] ) -> Tuple[str, List[str]]:
if modname is None: if modname is None:
if path: if path:
modname = path.rstrip('.') modname = path.rstrip('.')
@ -882,8 +849,8 @@ class ClassLevelDocumenter(Documenter):
Specialized Documenter subclass for objects on class level (methods, Specialized Documenter subclass for objects on class level (methods,
attributes). attributes).
""" """
def resolve_name(self, modname, parents, path, base): def resolve_name(self, modname: str, parents: Any, path: str, base: Any
# type: (str, Any, str, Any) -> Tuple[str, List[str]] ) -> Tuple[str, List[str]]:
if modname is None: if modname is None:
if path: if path:
mod_cls = path.rstrip('.') mod_cls = path.rstrip('.')
@ -916,8 +883,7 @@ class DocstringSignatureMixin:
feature of reading the signature from the docstring. feature of reading the signature from the docstring.
""" """
def _find_signature(self, encoding=None): def _find_signature(self, encoding: str = None) -> Tuple[str, str]:
# type: (str) -> Tuple[str, str]
if encoding is not None: if encoding is not None:
warnings.warn("The 'encoding' argument to autodoc.%s._find_signature() is " warnings.warn("The 'encoding' argument to autodoc.%s._find_signature() is "
"deprecated." % self.__class__.__name__, "deprecated." % self.__class__.__name__,
@ -951,8 +917,7 @@ class DocstringSignatureMixin:
break break
return result return result
def get_doc(self, encoding=None, ignore=1): def get_doc(self, encoding: str = None, ignore: int = 1) -> List[List[str]]:
# type: (str, int) -> List[List[str]]
if encoding is not None: if encoding is not None:
warnings.warn("The 'encoding' argument to autodoc.%s.get_doc() is deprecated." warnings.warn("The 'encoding' argument to autodoc.%s.get_doc() is deprecated."
% self.__class__.__name__, % self.__class__.__name__,
@ -962,8 +927,7 @@ class DocstringSignatureMixin:
return lines return lines
return super().get_doc(None, ignore) # type: ignore return super().get_doc(None, ignore) # type: ignore
def format_signature(self, **kwargs): def format_signature(self, **kwargs) -> str:
# type: (Any) -> str
if self.args is None and self.env.config.autodoc_docstring_signature: # type: ignore if self.args is None and self.env.config.autodoc_docstring_signature: # type: ignore
# only act if a signature is not explicitly given already, and if # only act if a signature is not explicitly given already, and if
# the feature is enabled # the feature is enabled
@ -978,8 +942,7 @@ class DocstringStripSignatureMixin(DocstringSignatureMixin):
Mixin for AttributeDocumenter to provide the Mixin for AttributeDocumenter to provide the
feature of stripping any function signature from the docstring. feature of stripping any function signature from the docstring.
""" """
def format_signature(self, **kwargs): def format_signature(self, **kwargs) -> str:
# type: (Any) -> str
if self.args is None and self.env.config.autodoc_docstring_signature: # type: ignore if self.args is None and self.env.config.autodoc_docstring_signature: # type: ignore
# only act if a signature is not explicitly given already, and if # only act if a signature is not explicitly given already, and if
# the feature is enabled # the feature is enabled
@ -1000,14 +963,13 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
member_order = 30 member_order = 30
@classmethod @classmethod
def can_document_member(cls, member, membername, isattr, parent): def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
# type: (Any, str, bool, Any) -> bool ) -> bool:
# supports functions, builtins and bound methods exported at the module level # supports functions, builtins and bound methods exported at the module level
return (inspect.isfunction(member) or inspect.isbuiltin(member) or return (inspect.isfunction(member) or inspect.isbuiltin(member) or
(inspect.isroutine(member) and isinstance(parent, ModuleDocumenter))) (inspect.isroutine(member) and isinstance(parent, ModuleDocumenter)))
def format_args(self, **kwargs): def format_args(self, **kwargs) -> str:
# type: (Any) -> str
if self.env.config.autodoc_typehints == 'none': if self.env.config.autodoc_typehints == 'none':
kwargs.setdefault('show_annotation', False) kwargs.setdefault('show_annotation', False)
@ -1042,12 +1004,10 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
args = args.replace('\\', '\\\\') args = args.replace('\\', '\\\\')
return args return args
def document_members(self, all_members=False): def document_members(self, all_members: bool = False) -> None:
# type: (bool) -> None
pass pass
def add_directive_header(self, sig): def add_directive_header(self, sig: str) -> None:
# type: (str) -> None
sourcename = self.get_sourcename() sourcename = self.get_sourcename()
super().add_directive_header(sig) super().add_directive_header(sig)
@ -1086,18 +1046,16 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
'private-members': bool_option, 'special-members': members_option, 'private-members': bool_option, 'special-members': members_option,
} # type: Dict[str, Callable] } # type: Dict[str, Callable]
def __init__(self, *args): def __init__(self, *args) -> None:
# type: (Any) -> None
super().__init__(*args) super().__init__(*args)
merge_special_members_option(self.options) merge_special_members_option(self.options)
@classmethod @classmethod
def can_document_member(cls, member, membername, isattr, parent): def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
# type: (Any, str, bool, Any) -> bool ) -> bool:
return isinstance(member, type) return isinstance(member, type)
def import_object(self): def import_object(self) -> Any:
# type: () -> Any
ret = super().import_object() ret = super().import_object()
# if the class is documented under another name, document it # if the class is documented under another name, document it
# as data/attribute # as data/attribute
@ -1108,8 +1066,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
self.doc_as_attr = True self.doc_as_attr = True
return ret return ret
def format_args(self, **kwargs): def format_args(self, **kwargs) -> str:
# type: (Any) -> str
if self.env.config.autodoc_typehints == 'none': if self.env.config.autodoc_typehints == 'none':
kwargs.setdefault('show_annotation', False) kwargs.setdefault('show_annotation', False)
@ -1129,15 +1086,13 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
# with __init__ in C # with __init__ in C
return None return None
def format_signature(self, **kwargs): def format_signature(self, **kwargs) -> str:
# type: (Any) -> str
if self.doc_as_attr: if self.doc_as_attr:
return '' return ''
return super().format_signature(**kwargs) return super().format_signature(**kwargs)
def add_directive_header(self, sig): def add_directive_header(self, sig: str) -> None:
# type: (str) -> None
if self.doc_as_attr: if self.doc_as_attr:
self.directivetype = 'attribute' self.directivetype = 'attribute'
super().add_directive_header(sig) super().add_directive_header(sig)
@ -1154,8 +1109,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
self.add_line(' ' + _('Bases: %s') % ', '.join(bases), self.add_line(' ' + _('Bases: %s') % ', '.join(bases),
sourcename) sourcename)
def get_doc(self, encoding=None, ignore=1): def get_doc(self, encoding: str = None, ignore: int = 1) -> List[List[str]]:
# type: (str, int) -> List[List[str]]
if encoding is not None: if encoding is not None:
warnings.warn("The 'encoding' argument to autodoc.%s.get_doc() is deprecated." warnings.warn("The 'encoding' argument to autodoc.%s.get_doc() is deprecated."
% self.__class__.__name__, % self.__class__.__name__,
@ -1199,8 +1153,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
tab_width = self.directive.state.document.settings.tab_width tab_width = self.directive.state.document.settings.tab_width
return [prepare_docstring(docstring, ignore, tab_width) for docstring in docstrings] return [prepare_docstring(docstring, ignore, tab_width) for docstring in docstrings]
def add_content(self, more_content, no_docstring=False): def add_content(self, more_content: Any, no_docstring: bool = False) -> None:
# type: (Any, bool) -> None
if self.doc_as_attr: if self.doc_as_attr:
classname = safe_getattr(self.object, '__qualname__', None) classname = safe_getattr(self.object, '__qualname__', None)
if not classname: if not classname:
@ -1215,15 +1168,13 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
else: else:
super().add_content(more_content) super().add_content(more_content)
def document_members(self, all_members=False): def document_members(self, all_members: bool = False) -> None:
# type: (bool) -> None
if self.doc_as_attr: if self.doc_as_attr:
return return
super().document_members(all_members) super().document_members(all_members)
def generate(self, more_content=None, real_modname=None, def generate(self, more_content: Any = None, real_modname: str = None,
check_module=False, all_members=False): check_module: bool = False, all_members: bool = False) -> None:
# type: (Any, str, bool, bool) -> None
# Do not pass real_modname and use the name from the __module__ # Do not pass real_modname and use the name from the __module__
# attribute of the class. # attribute of the class.
# If a class gets imported into the module real_modname # If a class gets imported into the module real_modname
@ -1245,8 +1196,8 @@ class ExceptionDocumenter(ClassDocumenter):
priority = 10 priority = 10
@classmethod @classmethod
def can_document_member(cls, member, membername, isattr, parent): def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
# type: (Any, str, bool, Any) -> bool ) -> bool:
return isinstance(member, type) and issubclass(member, BaseException) return isinstance(member, type) and issubclass(member, BaseException)
@ -1261,12 +1212,11 @@ class DataDocumenter(ModuleLevelDocumenter):
option_spec["annotation"] = annotation_option option_spec["annotation"] = annotation_option
@classmethod @classmethod
def can_document_member(cls, member, membername, isattr, parent): def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
# type: (Any, str, bool, Any) -> bool ) -> bool:
return isinstance(parent, ModuleDocumenter) and isattr return isinstance(parent, ModuleDocumenter) and isattr
def add_directive_header(self, sig): def add_directive_header(self, sig: str) -> None:
# type: (str) -> None
super().add_directive_header(sig) super().add_directive_header(sig)
sourcename = self.get_sourcename() sourcename = self.get_sourcename()
if not self.options.annotation: if not self.options.annotation:
@ -1282,12 +1232,10 @@ class DataDocumenter(ModuleLevelDocumenter):
self.add_line(' :annotation: %s' % self.options.annotation, self.add_line(' :annotation: %s' % self.options.annotation,
sourcename) sourcename)
def document_members(self, all_members=False): def document_members(self, all_members: bool = False) -> None:
# type: (bool) -> None
pass pass
def get_real_modname(self): def get_real_modname(self) -> str:
# type: () -> str
return self.get_attr(self.parent or self.object, '__module__', None) \ return self.get_attr(self.parent or self.object, '__module__', None) \
or self.modname or self.modname
@ -1302,13 +1250,12 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
priority = 1 # must be more than FunctionDocumenter priority = 1 # must be more than FunctionDocumenter
@classmethod @classmethod
def can_document_member(cls, member, membername, isattr, parent): def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
# type: (Any, str, bool, Any) -> bool ) -> bool:
return inspect.isroutine(member) and \ return inspect.isroutine(member) and \
not isinstance(parent, ModuleDocumenter) not isinstance(parent, ModuleDocumenter)
def import_object(self): def import_object(self) -> Any:
# type: () -> Any
ret = super().import_object() ret = super().import_object()
if not ret: if not ret:
return ret return ret
@ -1325,8 +1272,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
return ret return ret
def format_args(self, **kwargs): def format_args(self, **kwargs) -> str:
# type: (Any) -> str
if self.env.config.autodoc_typehints == 'none': if self.env.config.autodoc_typehints == 'none':
kwargs.setdefault('show_annotation', False) kwargs.setdefault('show_annotation', False)
@ -1341,8 +1287,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
args = args.replace('\\', '\\\\') args = args.replace('\\', '\\\\')
return args return args
def add_directive_header(self, sig): def add_directive_header(self, sig) -> None:
# type: (str) -> None
super().add_directive_header(sig) super().add_directive_header(sig)
sourcename = self.get_sourcename() sourcename = self.get_sourcename()
@ -1356,8 +1301,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
if inspect.isstaticmethod(obj, cls=self.parent, name=self.object_name): if inspect.isstaticmethod(obj, cls=self.parent, name=self.object_name):
self.add_line(' :staticmethod:', sourcename) self.add_line(' :staticmethod:', sourcename)
def document_members(self, all_members=False): def document_members(self, all_members: bool = False) -> None:
# type: (bool) -> None
pass pass
@ -1375,13 +1319,12 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):
priority = 10 priority = 10
@staticmethod @staticmethod
def is_function_or_method(obj): def is_function_or_method(obj: Any) -> bool:
# type: (Any) -> bool
return inspect.isfunction(obj) or inspect.isbuiltin(obj) or inspect.ismethod(obj) return inspect.isfunction(obj) or inspect.isbuiltin(obj) or inspect.ismethod(obj)
@classmethod @classmethod
def can_document_member(cls, member, membername, isattr, parent): def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
# type: (Any, str, bool, Any) -> bool ) -> bool:
if inspect.isattributedescriptor(member): if inspect.isattributedescriptor(member):
return True return True
elif (not isinstance(parent, ModuleDocumenter) and elif (not isinstance(parent, ModuleDocumenter) and
@ -1391,12 +1334,10 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):
else: else:
return False return False
def document_members(self, all_members=False): def document_members(self, all_members: bool = False) -> None:
# type: (bool) -> None
pass pass
def import_object(self): def import_object(self) -> Any:
# type: () -> Any
ret = super().import_object() ret = super().import_object()
if inspect.isenumattribute(self.object): if inspect.isenumattribute(self.object):
self.object = self.object.value self.object = self.object.value
@ -1407,13 +1348,11 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):
self._datadescriptor = False self._datadescriptor = False
return ret return ret
def get_real_modname(self): def get_real_modname(self) -> str:
# type: () -> str
return self.get_attr(self.parent or self.object, '__module__', None) \ return self.get_attr(self.parent or self.object, '__module__', None) \
or self.modname or self.modname
def add_directive_header(self, sig): def add_directive_header(self, sig: str) -> None:
# type: (str) -> None
super().add_directive_header(sig) super().add_directive_header(sig)
sourcename = self.get_sourcename() sourcename = self.get_sourcename()
if not self.options.annotation: if not self.options.annotation:
@ -1429,8 +1368,7 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):
else: else:
self.add_line(' :annotation: %s' % self.options.annotation, sourcename) self.add_line(' :annotation: %s' % self.options.annotation, sourcename)
def add_content(self, more_content, no_docstring=False): def add_content(self, more_content: Any, no_docstring: bool = False) -> None:
# type: (Any, bool) -> None
if not self._datadescriptor: if not self._datadescriptor:
# if it's not a data descriptor, its docstring is very probably the # if it's not a data descriptor, its docstring is very probably the
# wrong thing to display # wrong thing to display
@ -1450,21 +1388,18 @@ class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): #
priority = AttributeDocumenter.priority + 1 priority = AttributeDocumenter.priority + 1
@classmethod @classmethod
def can_document_member(cls, member, membername, isattr, parent): def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
# type: (Any, str, bool, Any) -> bool ) -> bool:
return inspect.isproperty(member) and isinstance(parent, ClassDocumenter) return inspect.isproperty(member) and isinstance(parent, ClassDocumenter)
def document_members(self, all_members=False): def document_members(self, all_members: bool = False) -> None:
# type: (bool) -> None
pass pass
def get_real_modname(self): def get_real_modname(self) -> str:
# type: () -> str
return self.get_attr(self.parent or self.object, '__module__', None) \ return self.get_attr(self.parent or self.object, '__module__', None) \
or self.modname or self.modname
def add_directive_header(self, sig): def add_directive_header(self, sig: str) -> None:
# type: (str) -> None
super().add_directive_header(sig) super().add_directive_header(sig)
sourcename = self.get_sourcename() sourcename = self.get_sourcename()
if inspect.isabstractmethod(self.object): if inspect.isabstractmethod(self.object):
@ -1485,21 +1420,19 @@ class InstanceAttributeDocumenter(AttributeDocumenter):
priority = 11 priority = 11
@classmethod @classmethod
def can_document_member(cls, member, membername, isattr, parent): def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
# type: (Any, str, bool, Any) -> bool ) -> bool:
"""This documents only INSTANCEATTR members.""" """This documents only INSTANCEATTR members."""
return isattr and (member is INSTANCEATTR) return isattr and (member is INSTANCEATTR)
def import_object(self): def import_object(self) -> bool:
# type: () -> bool
"""Never import anything.""" """Never import anything."""
# disguise as an attribute # disguise as an attribute
self.objtype = 'attribute' self.objtype = 'attribute'
self._datadescriptor = False self._datadescriptor = False
return True return True
def add_content(self, more_content, no_docstring=False): def add_content(self, more_content: Any, no_docstring: bool = False) -> None:
# type: (Any, bool) -> None
"""Never try to get a docstring from the object.""" """Never try to get a docstring from the object."""
super().add_content(more_content, no_docstring=True) super().add_content(more_content, no_docstring=True)
@ -1517,13 +1450,12 @@ class SlotsAttributeDocumenter(AttributeDocumenter):
priority = 11 priority = 11
@classmethod @classmethod
def can_document_member(cls, member, membername, isattr, parent): def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
# type: (Any, str, bool, Any) -> bool ) -> bool:
"""This documents only SLOTSATTR members.""" """This documents only SLOTSATTR members."""
return member is SLOTSATTR return member is SLOTSATTR
def import_object(self): def import_object(self) -> Any:
# type: () -> bool
"""Never import anything.""" """Never import anything."""
# disguise as an attribute # disguise as an attribute
self.objtype = 'attribute' self.objtype = 'attribute'
@ -1541,8 +1473,7 @@ class SlotsAttributeDocumenter(AttributeDocumenter):
self.env.note_reread() self.env.note_reread()
return False return False
def get_doc(self, encoding=None, ignore=1): def get_doc(self, encoding: str = None, ignore: int = 1) -> List[List[str]]:
# type: (str, int) -> List[List[str]]
"""Decode and return lines of the docstring(s) for the object.""" """Decode and return lines of the docstring(s) for the object."""
name = self.objpath[-1] name = self.objpath[-1]
__slots__ = safe_getattr(self.parent, '__slots__', []) __slots__ = safe_getattr(self.parent, '__slots__', [])
@ -1553,14 +1484,12 @@ class SlotsAttributeDocumenter(AttributeDocumenter):
return [] return []
def get_documenters(app): def get_documenters(app: Sphinx) -> Dict[str, Type[Documenter]]:
# type: (Sphinx) -> Dict[str, Type[Documenter]]
"""Returns registered Documenter classes""" """Returns registered Documenter classes"""
return app.registry.documenters return app.registry.documenters
def autodoc_attrgetter(app, obj, name, *defargs): def autodoc_attrgetter(app: Sphinx, obj: Any, name: str, *defargs) -> Any:
# type: (Sphinx, Any, str, Any) -> Any
"""Alternative getattr() for types""" """Alternative getattr() for types"""
for typ, func in app.registry.autodoc_attrgettrs.items(): for typ, func in app.registry.autodoc_attrgettrs.items():
if isinstance(obj, typ): if isinstance(obj, typ):
@ -1569,8 +1498,7 @@ def autodoc_attrgetter(app, obj, name, *defargs):
return safe_getattr(obj, name, *defargs) return safe_getattr(obj, name, *defargs)
def merge_autodoc_default_flags(app, config): def merge_autodoc_default_flags(app: Sphinx, config: Config) -> None:
# type: (Sphinx, Config) -> None
"""This merges the autodoc_default_flags to autodoc_default_options.""" """This merges the autodoc_default_flags to autodoc_default_options."""
if not config.autodoc_default_flags: if not config.autodoc_default_flags:
return return
@ -1602,8 +1530,7 @@ deprecated_alias('sphinx.ext.autodoc',
RemovedInSphinx40Warning) RemovedInSphinx40Warning)
def setup(app): def setup(app: Sphinx) -> Dict[str, Any]:
# type: (Sphinx) -> Dict[str, Any]
app.add_autodocumenter(ModuleDocumenter) app.add_autodocumenter(ModuleDocumenter)
app.add_autodocumenter(ClassDocumenter) app.add_autodocumenter(ClassDocumenter)
app.add_autodocumenter(ExceptionDocumenter) app.add_autodocumenter(ExceptionDocumenter)