Merge pull request #7677 from tk0miya/refactor_singledispatch

refactor: autodoc: Remove magic mock from singledispatch processing
This commit is contained in:
Takeshi KOMIYA
2020-05-16 23:05:13 +09:00
committed by GitHub
2 changed files with 50 additions and 70 deletions

View File

@@ -16,7 +16,6 @@ import warnings
from inspect import Parameter
from types import ModuleType
from typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Union
from unittest.mock import patch
from docutils.statemachine import StringList
@@ -421,8 +420,15 @@ class Documenter:
directive = getattr(self, 'directivetype', self.objtype)
name = self.format_name()
sourcename = self.get_sourcename()
self.add_line('.. %s:%s:: %s%s' % (domain, directive, name, sig),
# one signature per line, indented by column
prefix = '.. %s:%s:: ' % (domain, directive)
for i, sig_line in enumerate(sig.split("\n")):
self.add_line('%s%s%s' % (prefix, name, sig_line),
sourcename)
if i == 0:
prefix = " " * len(prefix)
if self.options.noindex:
self.add_line(' :noindex:', sourcename)
if self.objpath:
@@ -1075,26 +1081,17 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
def add_directive_header(self, sig: str) -> None:
sourcename = self.get_sourcename()
if inspect.is_singledispatch_function(self.object):
self.add_singledispatch_directive_header(sig)
else:
super().add_directive_header(sig)
if inspect.iscoroutinefunction(self.object):
self.add_line(' :async:', sourcename)
def add_singledispatch_directive_header(self, sig: str) -> None:
sourcename = self.get_sourcename()
def format_signature(self, **kwargs: Any) -> str:
sig = super().format_signature(**kwargs)
sigs = [sig]
# intercept generated directive headers
# TODO: It is very hacky to use mock to intercept header generation
with patch.object(self, 'add_line') as add_line:
super().add_directive_header(sig)
# output first line of header
self.add_line(*add_line.call_args_list[0][0])
# inserts signature of singledispatch'ed functions
if inspect.is_singledispatch_function(self.object):
# append signature of singledispatch'ed functions
for typ, func in self.object.registry.items():
if typ is object:
pass # default implementation. skipped.
@@ -1103,13 +1100,9 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
documenter = FunctionDocumenter(self.directive, '')
documenter.object = func
self.add_line(' %s%s' % (self.format_name(),
documenter.format_signature()),
sourcename)
sigs.append(documenter.format_signature())
# output remains of directive header
for call in add_line.call_args_list[1:]:
self.add_line(*call[0])
return "\n".join(sigs)
def annotate_to_first_argument(self, func: Callable, typ: Type) -> None:
"""Annotate type hint to the first argument of function if needed."""
@@ -1487,10 +1480,6 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
return args
def add_directive_header(self, sig: str) -> None:
meth = self.parent.__dict__.get(self.objpath[-1])
if inspect.is_singledispatch_method(meth):
self.add_singledispatch_directive_header(sig)
else:
super().add_directive_header(sig)
sourcename = self.get_sourcename()
@@ -1509,19 +1498,13 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
def document_members(self, all_members: bool = False) -> None:
pass
def add_singledispatch_directive_header(self, sig: str) -> None:
sourcename = self.get_sourcename()
def format_signature(self, **kwargs: Any) -> str:
sig = super().format_signature(**kwargs)
sigs = [sig]
# intercept generated directive headers
# TODO: It is very hacky to use mock to intercept header generation
with patch.object(self, 'add_line') as add_line:
super().add_directive_header(sig)
# output first line of header
self.add_line(*add_line.call_args_list[0][0])
# inserts signature of singledispatch'ed functions
meth = self.parent.__dict__.get(self.objpath[-1])
if inspect.is_singledispatch_method(meth):
# append signature of singledispatch'ed functions
for typ, func in meth.dispatcher.registry.items():
if typ is object:
pass # default implementation. skipped.
@@ -1531,14 +1514,10 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
documenter = MethodDocumenter(self.directive, '')
documenter.parent = self.parent
documenter.object = func
documenter.objpath = self.objpath
self.add_line(' %s%s' % (self.format_name(),
documenter.format_signature()),
sourcename)
documenter.objpath = [None]
sigs.append(documenter.format_signature())
# output remains of directive header
for call in add_line.call_args_list[1:]:
self.add_line(*call[0])
return "\n".join(sigs)
def annotate_to_first_argument(self, func: Callable, typ: Type) -> None:
"""Annotate type hint to the first argument of function if needed."""

View File

@@ -252,6 +252,7 @@ def test_get_doc(app):
def getdocl(objtype, obj):
inst = app.registry.documenters[objtype](directive, 'tmp')
inst.parent = object # dummy
inst.object = obj
inst.objpath = [obj.__name__]
inst.doc_as_attr = False