mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #7677 from tk0miya/refactor_singledispatch
refactor: autodoc: Remove magic mock from singledispatch processing
This commit is contained in:
@@ -16,7 +16,6 @@ import warnings
|
|||||||
from inspect import Parameter
|
from inspect import Parameter
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
from typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Union
|
from typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Union
|
||||||
from unittest.mock import patch
|
|
||||||
|
|
||||||
from docutils.statemachine import StringList
|
from docutils.statemachine import StringList
|
||||||
|
|
||||||
@@ -421,8 +420,15 @@ class Documenter:
|
|||||||
directive = getattr(self, 'directivetype', self.objtype)
|
directive = getattr(self, 'directivetype', self.objtype)
|
||||||
name = self.format_name()
|
name = self.format_name()
|
||||||
sourcename = self.get_sourcename()
|
sourcename = self.get_sourcename()
|
||||||
self.add_line('.. %s:%s:: %s%s' % (domain, directive, name, sig),
|
|
||||||
sourcename)
|
# 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:
|
if self.options.noindex:
|
||||||
self.add_line(' :noindex:', sourcename)
|
self.add_line(' :noindex:', sourcename)
|
||||||
if self.objpath:
|
if self.objpath:
|
||||||
@@ -1075,41 +1081,28 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
|
|||||||
|
|
||||||
def add_directive_header(self, sig: str) -> None:
|
def add_directive_header(self, sig: str) -> None:
|
||||||
sourcename = self.get_sourcename()
|
sourcename = self.get_sourcename()
|
||||||
if inspect.is_singledispatch_function(self.object):
|
super().add_directive_header(sig)
|
||||||
self.add_singledispatch_directive_header(sig)
|
|
||||||
else:
|
|
||||||
super().add_directive_header(sig)
|
|
||||||
|
|
||||||
if inspect.iscoroutinefunction(self.object):
|
if inspect.iscoroutinefunction(self.object):
|
||||||
self.add_line(' :async:', sourcename)
|
self.add_line(' :async:', sourcename)
|
||||||
|
|
||||||
def add_singledispatch_directive_header(self, sig: str) -> None:
|
def format_signature(self, **kwargs: Any) -> str:
|
||||||
sourcename = self.get_sourcename()
|
sig = super().format_signature(**kwargs)
|
||||||
|
sigs = [sig]
|
||||||
|
|
||||||
# intercept generated directive headers
|
if inspect.is_singledispatch_function(self.object):
|
||||||
# TODO: It is very hacky to use mock to intercept header generation
|
# append signature of singledispatch'ed functions
|
||||||
with patch.object(self, 'add_line') as add_line:
|
for typ, func in self.object.registry.items():
|
||||||
super().add_directive_header(sig)
|
if typ is object:
|
||||||
|
pass # default implementation. skipped.
|
||||||
|
else:
|
||||||
|
self.annotate_to_first_argument(func, typ)
|
||||||
|
|
||||||
# output first line of header
|
documenter = FunctionDocumenter(self.directive, '')
|
||||||
self.add_line(*add_line.call_args_list[0][0])
|
documenter.object = func
|
||||||
|
sigs.append(documenter.format_signature())
|
||||||
|
|
||||||
# inserts signature of singledispatch'ed functions
|
return "\n".join(sigs)
|
||||||
for typ, func in self.object.registry.items():
|
|
||||||
if typ is object:
|
|
||||||
pass # default implementation. skipped.
|
|
||||||
else:
|
|
||||||
self.annotate_to_first_argument(func, typ)
|
|
||||||
|
|
||||||
documenter = FunctionDocumenter(self.directive, '')
|
|
||||||
documenter.object = func
|
|
||||||
self.add_line(' %s%s' % (self.format_name(),
|
|
||||||
documenter.format_signature()),
|
|
||||||
sourcename)
|
|
||||||
|
|
||||||
# output remains of directive header
|
|
||||||
for call in add_line.call_args_list[1:]:
|
|
||||||
self.add_line(*call[0])
|
|
||||||
|
|
||||||
def annotate_to_first_argument(self, func: Callable, typ: Type) -> None:
|
def annotate_to_first_argument(self, func: Callable, typ: Type) -> None:
|
||||||
"""Annotate type hint to the first argument of function if needed."""
|
"""Annotate type hint to the first argument of function if needed."""
|
||||||
@@ -1487,11 +1480,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|||||||
return args
|
return args
|
||||||
|
|
||||||
def add_directive_header(self, sig: str) -> None:
|
def add_directive_header(self, sig: str) -> None:
|
||||||
meth = self.parent.__dict__.get(self.objpath[-1])
|
super().add_directive_header(sig)
|
||||||
if inspect.is_singledispatch_method(meth):
|
|
||||||
self.add_singledispatch_directive_header(sig)
|
|
||||||
else:
|
|
||||||
super().add_directive_header(sig)
|
|
||||||
|
|
||||||
sourcename = self.get_sourcename()
|
sourcename = self.get_sourcename()
|
||||||
obj = self.parent.__dict__.get(self.object_name, self.object)
|
obj = self.parent.__dict__.get(self.object_name, self.object)
|
||||||
@@ -1509,36 +1498,26 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|||||||
def document_members(self, all_members: bool = False) -> None:
|
def document_members(self, all_members: bool = False) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def add_singledispatch_directive_header(self, sig: str) -> None:
|
def format_signature(self, **kwargs: Any) -> str:
|
||||||
sourcename = self.get_sourcename()
|
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])
|
meth = self.parent.__dict__.get(self.objpath[-1])
|
||||||
for typ, func in meth.dispatcher.registry.items():
|
if inspect.is_singledispatch_method(meth):
|
||||||
if typ is object:
|
# append signature of singledispatch'ed functions
|
||||||
pass # default implementation. skipped.
|
for typ, func in meth.dispatcher.registry.items():
|
||||||
else:
|
if typ is object:
|
||||||
self.annotate_to_first_argument(func, typ)
|
pass # default implementation. skipped.
|
||||||
|
else:
|
||||||
|
self.annotate_to_first_argument(func, typ)
|
||||||
|
|
||||||
documenter = MethodDocumenter(self.directive, '')
|
documenter = MethodDocumenter(self.directive, '')
|
||||||
documenter.parent = self.parent
|
documenter.parent = self.parent
|
||||||
documenter.object = func
|
documenter.object = func
|
||||||
documenter.objpath = self.objpath
|
documenter.objpath = [None]
|
||||||
self.add_line(' %s%s' % (self.format_name(),
|
sigs.append(documenter.format_signature())
|
||||||
documenter.format_signature()),
|
|
||||||
sourcename)
|
|
||||||
|
|
||||||
# output remains of directive header
|
return "\n".join(sigs)
|
||||||
for call in add_line.call_args_list[1:]:
|
|
||||||
self.add_line(*call[0])
|
|
||||||
|
|
||||||
def annotate_to_first_argument(self, func: Callable, typ: Type) -> None:
|
def annotate_to_first_argument(self, func: Callable, typ: Type) -> None:
|
||||||
"""Annotate type hint to the first argument of function if needed."""
|
"""Annotate type hint to the first argument of function if needed."""
|
||||||
|
|||||||
@@ -252,6 +252,7 @@ def test_get_doc(app):
|
|||||||
|
|
||||||
def getdocl(objtype, obj):
|
def getdocl(objtype, obj):
|
||||||
inst = app.registry.documenters[objtype](directive, 'tmp')
|
inst = app.registry.documenters[objtype](directive, 'tmp')
|
||||||
|
inst.parent = object # dummy
|
||||||
inst.object = obj
|
inst.object = obj
|
||||||
inst.objpath = [obj.__name__]
|
inst.objpath = [obj.__name__]
|
||||||
inst.doc_as_attr = False
|
inst.doc_as_attr = False
|
||||||
@@ -1658,8 +1659,8 @@ def test_singledispatch(app):
|
|||||||
'',
|
'',
|
||||||
'',
|
'',
|
||||||
'.. py:function:: func(arg, kwarg=None)',
|
'.. py:function:: func(arg, kwarg=None)',
|
||||||
' func(arg: int, kwarg=None)',
|
' func(arg: int, kwarg=None)',
|
||||||
' func(arg: str, kwarg=None)',
|
' func(arg: str, kwarg=None)',
|
||||||
' :module: target.singledispatch',
|
' :module: target.singledispatch',
|
||||||
'',
|
'',
|
||||||
' A function for general use.',
|
' A function for general use.',
|
||||||
@@ -1674,8 +1675,8 @@ def test_singledispatch_autofunction(app):
|
|||||||
assert list(actual) == [
|
assert list(actual) == [
|
||||||
'',
|
'',
|
||||||
'.. py:function:: func(arg, kwarg=None)',
|
'.. py:function:: func(arg, kwarg=None)',
|
||||||
' func(arg: int, kwarg=None)',
|
' func(arg: int, kwarg=None)',
|
||||||
' func(arg: str, kwarg=None)',
|
' func(arg: str, kwarg=None)',
|
||||||
' :module: target.singledispatch',
|
' :module: target.singledispatch',
|
||||||
'',
|
'',
|
||||||
' A function for general use.',
|
' A function for general use.',
|
||||||
@@ -1701,8 +1702,8 @@ def test_singledispatchmethod(app):
|
|||||||
'',
|
'',
|
||||||
'',
|
'',
|
||||||
' .. py:method:: Foo.meth(arg, kwarg=None)',
|
' .. py:method:: Foo.meth(arg, kwarg=None)',
|
||||||
' Foo.meth(arg: int, kwarg=None)',
|
' Foo.meth(arg: int, kwarg=None)',
|
||||||
' Foo.meth(arg: str, kwarg=None)',
|
' Foo.meth(arg: str, kwarg=None)',
|
||||||
' :module: target.singledispatchmethod',
|
' :module: target.singledispatchmethod',
|
||||||
'',
|
'',
|
||||||
' A method for general use.',
|
' A method for general use.',
|
||||||
@@ -1719,8 +1720,8 @@ def test_singledispatchmethod_automethod(app):
|
|||||||
assert list(actual) == [
|
assert list(actual) == [
|
||||||
'',
|
'',
|
||||||
'.. py:method:: Foo.meth(arg, kwarg=None)',
|
'.. py:method:: Foo.meth(arg, kwarg=None)',
|
||||||
' Foo.meth(arg: int, kwarg=None)',
|
' Foo.meth(arg: int, kwarg=None)',
|
||||||
' Foo.meth(arg: str, kwarg=None)',
|
' Foo.meth(arg: str, kwarg=None)',
|
||||||
' :module: target.singledispatchmethod',
|
' :module: target.singledispatchmethod',
|
||||||
'',
|
'',
|
||||||
' A method for general use.',
|
' A method for general use.',
|
||||||
|
|||||||
Reference in New Issue
Block a user