[autodoc] add support for singledispatchmethod class methods (#11284)

This commit is contained in:
Bénédikt Tran 2024-03-14 12:26:35 +01:00 committed by GitHub
parent dbb4da375f
commit c86e90842f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 87 additions and 1 deletions

View File

@ -93,6 +93,9 @@ Bugs fixed
* #11474: Fix doctrees caching causing files not be rebuilt in some cases,
e.g., when :confval:`numfig` is ``True``.
Patch by Bénédikt Tran.
* #11278: autodoc: Fix rendering of :class:`functools.singledispatchmethod`
combined with :func:`@classmethod <classmethod>`.
Patch by Bénédikt Tran.
Testing
-------

View File

@ -2229,7 +2229,8 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
self.add_line(' :abstractmethod:', sourcename)
if inspect.iscoroutinefunction(obj) or inspect.isasyncgenfunction(obj):
self.add_line(' :async:', sourcename)
if inspect.isclassmethod(obj):
if (inspect.isclassmethod(obj) or
inspect.is_singledispatch_method(obj) and inspect.isclassmethod(obj.func)):
self.add_line(' :classmethod:', sourcename)
if inspect.isstaticmethod(obj, cls=self.parent, name=self.object_name):
self.add_line(' :staticmethod:', sourcename)
@ -2261,6 +2262,8 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
if typ is object:
pass # default implementation. skipped.
else:
if inspect.isclassmethod(func):
func = func.__func__
dispatchmeth = self.annotate_to_first_argument(func, typ)
if dispatchmeth:
documenter = MethodDocumenter(self.directive, '')

View File

@ -0,0 +1,31 @@
from functools import singledispatchmethod
class Foo:
"""docstring"""
@singledispatchmethod
@classmethod
def class_meth(cls, arg, kwarg=None):
"""A class method for general use."""
pass
@class_meth.register(int)
@class_meth.register(float)
@classmethod
def _class_meth_int(cls, arg, kwarg=None):
"""A class method for numbers."""
pass
@class_meth.register(str)
@classmethod
def _class_meth_str(cls, arg, kwarg=None):
"""A class method for str."""
pass
@class_meth.register
@classmethod
def _class_meth_dict(cls, arg: dict, kwarg=None):
"""A class method for dict."""
# This function tests for specifying type through annotations
pass

View File

@ -2111,6 +2111,55 @@ def test_singledispatchmethod_automethod(app):
]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_singledispatchmethod_classmethod(app):
options = {"members": None}
actual = do_autodoc(app, 'module', 'target.singledispatchmethod_classmethod', options)
assert list(actual) == [
'',
'.. py:module:: target.singledispatchmethod_classmethod',
'',
'',
'.. py:class:: Foo()',
' :module: target.singledispatchmethod_classmethod',
'',
' docstring',
'',
'',
' .. py:method:: Foo.class_meth(arg, kwarg=None)',
' Foo.class_meth(arg: float, kwarg=None)',
' Foo.class_meth(arg: int, kwarg=None)',
' Foo.class_meth(arg: str, kwarg=None)',
' Foo.class_meth(arg: dict, kwarg=None)',
' :module: target.singledispatchmethod_classmethod',
' :classmethod:',
'',
' A class method for general use.',
'',
]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_singledispatchmethod_classmethod_automethod(app):
options = {}
actual = do_autodoc(app, 'method', 'target.singledispatchmethod_classmethod.Foo.class_meth', options)
assert list(actual) == [
'',
'.. py:method:: Foo.class_meth(arg, kwarg=None)',
' Foo.class_meth(arg: float, kwarg=None)',
' Foo.class_meth(arg: int, kwarg=None)',
' Foo.class_meth(arg: str, kwarg=None)',
' Foo.class_meth(arg: dict, kwarg=None)',
' :module: target.singledispatchmethod_classmethod',
' :classmethod:',
'',
' A class method for general use.',
'',
]
@pytest.mark.skipif(sys.version_info[:2] >= (3, 13),
reason='Cython does not support Python 3.13 yet.')
@pytest.mark.skipif(pyximport is None, reason='cython is not installed')