diff options
author | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2020-04-27 22:48:02 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-27 22:48:02 +0900 |
commit | 1cffff2a3024a8aeb4a7f9af9a10198d1d97c76c (patch) | |
tree | 293c037149d690b57fdefe2ac37c4569957a5610 | |
parent | 7a40ed0f271057b668076593db1d9a9d68baf8d3 (diff) | |
parent | 65c9df83033ef248c57e1405d99a35a3751f2ed8 (diff) | |
download | sphinx-git-1cffff2a3024a8aeb4a7f9af9a10198d1d97c76c.tar.gz |
Merge pull request #7487 from thomascobb/singledispatch_autofunction
Support singledispatch autodoc directives
-rw-r--r-- | sphinx/ext/autodoc/__init__.py | 72 | ||||
-rw-r--r-- | tests/test_autodoc.py | 32 |
2 files changed, 59 insertions, 45 deletions
diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 7b3028b12..3e8b2d765 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1078,30 +1078,15 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ def add_directive_header(self, sig: str) -> None: sourcename = self.get_sourcename() - super().add_directive_header(sig) + 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) - -class SingledispatchFunctionDocumenter(FunctionDocumenter): - """ - Specialized Documenter subclass for singledispatch'ed functions. - """ - objtype = 'singledispatch_function' - directivetype = 'function' - member_order = 30 - - # before FunctionDocumenter - priority = FunctionDocumenter.priority + 1 - - @classmethod - def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any - ) -> bool: - return (super().can_document_member(member, membername, isattr, parent) and - inspect.is_singledispatch_function(member)) - - def add_directive_header(self, sig: str) -> None: + def add_singledispatch_directive_header(self, sig: str) -> None: sourcename = self.get_sourcename() # intercept generated directive headers @@ -1141,6 +1126,14 @@ class SingledispatchFunctionDocumenter(FunctionDocumenter): func.__signature__ = sig.replace(parameters=params) # type: ignore +class SingledispatchFunctionDocumenter(FunctionDocumenter): + """ + Used to be a specialized Documenter subclass for singledispatch'ed functions. + + Retained for backwards compatibility, now does the same as the FunctionDocumenter + """ + + class DecoratorDocumenter(FunctionDocumenter): """ Specialized Documenter subclass for decorator functions. @@ -1475,7 +1468,11 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: return args def add_directive_header(self, sig: str) -> None: - super().add_directive_header(sig) + 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() obj = self.parent.__dict__.get(self.object_name, self.object) @@ -1491,28 +1488,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: def document_members(self, all_members: bool = False) -> None: pass - -class SingledispatchMethodDocumenter(MethodDocumenter): - """ - Specialized Documenter subclass for singledispatch'ed methods. - """ - objtype = 'singledispatch_method' - directivetype = 'method' - member_order = 50 - - # before MethodDocumenter - priority = MethodDocumenter.priority + 1 - - @classmethod - def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any - ) -> bool: - if super().can_document_member(member, membername, isattr, parent) and parent.object: - meth = parent.object.__dict__.get(membername) - return inspect.is_singledispatch_method(meth) - else: - return False - - def add_directive_header(self, sig: str) -> None: + def add_singledispatch_directive_header(self, sig: str) -> None: sourcename = self.get_sourcename() # intercept generated directive headers @@ -1553,6 +1529,14 @@ class SingledispatchMethodDocumenter(MethodDocumenter): func.__signature__ = sig.replace(parameters=params) # type: ignore +class SingledispatchMethodDocumenter(MethodDocumenter): + """ + Used to be a specialized Documenter subclass for singledispatch'ed methods. + + Retained for backwards compatibility, now does the same as the MethodDocumenter + """ + + class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): # type: ignore """ Specialized Documenter subclass for attributes. @@ -1771,10 +1755,8 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_autodocumenter(DataDocumenter) app.add_autodocumenter(DataDeclarationDocumenter) app.add_autodocumenter(FunctionDocumenter) - app.add_autodocumenter(SingledispatchFunctionDocumenter) app.add_autodocumenter(DecoratorDocumenter) app.add_autodocumenter(MethodDocumenter) - app.add_autodocumenter(SingledispatchMethodDocumenter) app.add_autodocumenter(AttributeDocumenter) app.add_autodocumenter(PropertyDocumenter) app.add_autodocumenter(InstanceAttributeDocumenter) diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index 7cdb074d2..51ae3ddc3 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -1603,6 +1603,21 @@ def test_singledispatch(): ] +@pytest.mark.usefixtures('setup_test') +def test_singledispatch_autofunction(): + options = {} + actual = do_autodoc(app, 'function', 'target.singledispatch.func', options) + assert list(actual) == [ + '', + '.. py:function:: func(arg, kwarg=None)', + ' func(arg: int, kwarg=None)', + ' func(arg: str, kwarg=None)', + ' :module: target.singledispatch', + '', + ' A function for general use.', + '', + ] + @pytest.mark.skipif(sys.version_info < (3, 8), reason='singledispatchmethod is available since python3.8') @pytest.mark.usefixtures('setup_test') @@ -1630,6 +1645,23 @@ def test_singledispatchmethod(): ] +@pytest.mark.skipif(sys.version_info < (3, 8), + reason='singledispatchmethod is available since python3.8') +@pytest.mark.usefixtures('setup_test') +def test_singledispatchmethod_automethod(): + options = {} + actual = do_autodoc(app, 'method', 'target.singledispatchmethod.Foo.meth', options) + assert list(actual) == [ + '', + '.. py:method:: Foo.meth(arg, kwarg=None)', + ' Foo.meth(arg: int, kwarg=None)', + ' Foo.meth(arg: str, kwarg=None)', + ' :module: target.singledispatchmethod', + '', + ' A method for general use.', + '', + ] + @pytest.mark.usefixtures('setup_test') @pytest.mark.skipif(pyximport is None, reason='cython is not installed') def test_cython(): |