Merge pull request #8504 from tk0miya/deprecate_GenericAliasDocumenter

Fix #8503: autoattribute could not create document for a GenericAlias
This commit is contained in:
Takeshi KOMIYA 2020-11-29 12:50:19 +09:00 committed by GitHub
commit aa84eea08b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 128 additions and 34 deletions

View File

@ -16,6 +16,7 @@ Deprecated
* The ``follow_wrapped`` argument of ``sphinx.util.inspect.signature()`` * The ``follow_wrapped`` argument of ``sphinx.util.inspect.signature()``
* ``sphinx.ext.autodoc.Documenter.get_object_members()`` * ``sphinx.ext.autodoc.Documenter.get_object_members()``
* ``sphinx.ext.autodoc.DataDeclarationDocumenter`` * ``sphinx.ext.autodoc.DataDeclarationDocumenter``
* ``sphinx.ext.autodoc.GenericAliasDocumenter``
* ``sphinx.ext.autodoc.InstanceAttributeDocumenter`` * ``sphinx.ext.autodoc.InstanceAttributeDocumenter``
* ``sphinx.ext.autodoc.SlotsAttributeDocumenter`` * ``sphinx.ext.autodoc.SlotsAttributeDocumenter``
* ``sphinx.ext.autodoc.TypeVarDocumenter`` * ``sphinx.ext.autodoc.TypeVarDocumenter``
@ -60,6 +61,8 @@ Bugs fixed
based uninitalized variables based uninitalized variables
* #8480: autodoc: autoattribute could not create document for __slots__ * #8480: autodoc: autoattribute could not create document for __slots__
attributes attributes
* #8503: autodoc: autoattribute could not create document for a GenericAlias as
class attributes correctly
* #8452: autodoc: autodoc_type_aliases doesn't work when autodoc_typehints is * #8452: autodoc: autodoc_type_aliases doesn't work when autodoc_typehints is
set to "description" set to "description"
* #8460: autodoc: autodata and autoattribute directives do not display type * #8460: autodoc: autodata and autoattribute directives do not display type

View File

@ -41,6 +41,11 @@ The following is a list of deprecated interfaces.
- 5.0 - 5.0
- ``sphinx.ext.autodoc.DataDocumenter`` - ``sphinx.ext.autodoc.DataDocumenter``
* - ``sphinx.ext.autodoc.GenericAliasDocumenter``
- 3.4
- 5.0
- ``sphinx.ext.autodoc.DataDocumenter``
* - ``sphinx.ext.autodoc.InstanceAttributeDocumenter`` * - ``sphinx.ext.autodoc.InstanceAttributeDocumenter``
- 3.4 - 3.4
- 5.0 - 5.0

View File

@ -1701,6 +1701,25 @@ class DataDocumenterMixinBase:
pass pass
class GenericAliasMixin(DataDocumenterMixinBase):
"""
Mixin for DataDocumenter and AttributeDocumenter to provide the feature for
supporting GenericAliases.
"""
def should_suppress_directive_header(self) -> bool:
return (inspect.isgenericalias(self.object) or
super().should_suppress_directive_header())
def update_content(self, more_content: StringList) -> None:
if inspect.isgenericalias(self.object):
alias = stringify_typehint(self.object)
more_content.append(_('alias of %s') % alias, '')
more_content.append('', '')
super().update_content(more_content)
class NewTypeMixin(DataDocumenterMixinBase): class NewTypeMixin(DataDocumenterMixinBase):
""" """
Mixin for DataDocumenter and AttributeDocumenter to provide the feature for Mixin for DataDocumenter and AttributeDocumenter to provide the feature for
@ -1801,8 +1820,8 @@ class UninitializedGlobalVariableMixin(DataDocumenterMixinBase):
super().add_content(more_content, no_docstring=no_docstring) # type: ignore super().add_content(more_content, no_docstring=no_docstring) # type: ignore
class DataDocumenter(NewTypeMixin, TypeVarMixin, UninitializedGlobalVariableMixin, class DataDocumenter(GenericAliasMixin, NewTypeMixin, TypeVarMixin,
ModuleLevelDocumenter): UninitializedGlobalVariableMixin, ModuleLevelDocumenter):
""" """
Specialized Documenter subclass for data items. Specialized Documenter subclass for data items.
""" """
@ -1863,32 +1882,6 @@ class DataDocumenter(NewTypeMixin, TypeVarMixin, UninitializedGlobalVariableMixi
super().add_content(more_content, no_docstring=no_docstring) super().add_content(more_content, no_docstring=no_docstring)
class GenericAliasDocumenter(DataDocumenter):
"""
Specialized Documenter subclass for GenericAliases.
"""
objtype = 'genericalias'
directivetype = 'data'
priority = DataDocumenter.priority + 1
@classmethod
def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
) -> bool:
return inspect.isgenericalias(member)
def add_directive_header(self, sig: str) -> None:
self.options = Options(self.options)
self.options['annotation'] = SUPPRESS
super().add_directive_header(sig)
def add_content(self, more_content: Optional[StringList], no_docstring: bool = False
) -> None:
name = stringify_typehint(self.object)
content = StringList([_('alias of %s') % name], source='')
super().add_content(content)
class NewTypeDataDocumenter(DataDocumenter): class NewTypeDataDocumenter(DataDocumenter):
""" """
Specialized Documenter subclass for NewTypes. Specialized Documenter subclass for NewTypes.
@ -2102,8 +2095,8 @@ class SlotsMixin(DataDocumenterMixinBase):
return super().get_doc(encoding, ignore) # type: ignore return super().get_doc(encoding, ignore) # type: ignore
class AttributeDocumenter(NewTypeMixin, SlotsMixin, TypeVarMixin, # type: ignore class AttributeDocumenter(GenericAliasMixin, NewTypeMixin, SlotsMixin, # type: ignore
DocstringStripSignatureMixin, ClassLevelDocumenter): TypeVarMixin, DocstringStripSignatureMixin, ClassLevelDocumenter):
""" """
Specialized Documenter subclass for attributes. Specialized Documenter subclass for attributes.
""" """
@ -2324,6 +2317,7 @@ def migrate_autodoc_member_order(app: Sphinx, config: Config) -> None:
# for compatibility # for compatibility
from sphinx.ext.autodoc.deprecated import DataDeclarationDocumenter # NOQA from sphinx.ext.autodoc.deprecated import DataDeclarationDocumenter # NOQA
from sphinx.ext.autodoc.deprecated import GenericAliasDocumenter # NOQA
from sphinx.ext.autodoc.deprecated import InstanceAttributeDocumenter # NOQA from sphinx.ext.autodoc.deprecated import InstanceAttributeDocumenter # NOQA
from sphinx.ext.autodoc.deprecated import SingledispatchFunctionDocumenter # NOQA from sphinx.ext.autodoc.deprecated import SingledispatchFunctionDocumenter # NOQA
from sphinx.ext.autodoc.deprecated import SingledispatchMethodDocumenter # NOQA from sphinx.ext.autodoc.deprecated import SingledispatchMethodDocumenter # NOQA
@ -2336,7 +2330,6 @@ def setup(app: Sphinx) -> Dict[str, Any]:
app.add_autodocumenter(ClassDocumenter) app.add_autodocumenter(ClassDocumenter)
app.add_autodocumenter(ExceptionDocumenter) app.add_autodocumenter(ExceptionDocumenter)
app.add_autodocumenter(DataDocumenter) app.add_autodocumenter(DataDocumenter)
app.add_autodocumenter(GenericAliasDocumenter)
app.add_autodocumenter(NewTypeDataDocumenter) app.add_autodocumenter(NewTypeDataDocumenter)
app.add_autodocumenter(FunctionDocumenter) app.add_autodocumenter(FunctionDocumenter)
app.add_autodocumenter(DecoratorDocumenter) app.add_autodocumenter(DecoratorDocumenter)

View File

@ -109,3 +109,18 @@ class SlotsAttributeDocumenter(AttributeDocumenter):
warnings.warn("%s is deprecated." % self.__class__.__name__, warnings.warn("%s is deprecated." % self.__class__.__name__,
RemovedInSphinx50Warning, stacklevel=2) RemovedInSphinx50Warning, stacklevel=2)
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
class GenericAliasDocumenter(DataDocumenter):
"""
Specialized Documenter subclass for GenericAliases.
"""
objtype = 'genericalias'
directivetype = 'data'
priority = DataDocumenter.priority + 1 # type: ignore
def __init__(self, *args: Any, **kwargs: Any) -> None:
warnings.warn("%s is deprecated." % self.__class__.__name__,
RemovedInSphinx50Warning, stacklevel=2)
super().__init__(*args, **kwargs)

View File

@ -87,15 +87,14 @@ AutosummaryEntry = NamedTuple('AutosummaryEntry', [('name', str),
def setup_documenters(app: Any) -> None: def setup_documenters(app: Any) -> None:
from sphinx.ext.autodoc import (AttributeDocumenter, ClassDocumenter, DataDocumenter, from sphinx.ext.autodoc import (AttributeDocumenter, ClassDocumenter, DataDocumenter,
DecoratorDocumenter, ExceptionDocumenter, DecoratorDocumenter, ExceptionDocumenter,
FunctionDocumenter, GenericAliasDocumenter, FunctionDocumenter, MethodDocumenter, ModuleDocumenter,
MethodDocumenter, ModuleDocumenter,
NewTypeAttributeDocumenter, NewTypeDataDocumenter, NewTypeAttributeDocumenter, NewTypeDataDocumenter,
PropertyDocumenter, SingledispatchFunctionDocumenter) PropertyDocumenter, SingledispatchFunctionDocumenter)
documenters = [ documenters = [
ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter, ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter,
FunctionDocumenter, MethodDocumenter, NewTypeAttributeDocumenter, FunctionDocumenter, MethodDocumenter, NewTypeAttributeDocumenter,
NewTypeDataDocumenter, AttributeDocumenter, DecoratorDocumenter, PropertyDocumenter, NewTypeDataDocumenter, AttributeDocumenter, DecoratorDocumenter, PropertyDocumenter,
GenericAliasDocumenter, SingledispatchFunctionDocumenter, SingledispatchFunctionDocumenter,
] # type: List[Type[Documenter]] ] # type: List[Type[Documenter]]
for documenter in documenters: for documenter in documenters:
app.registry.add_documenter(documenter.objtype, documenter) app.registry.add_documenter(documenter.objtype, documenter)

View File

@ -4,3 +4,8 @@ from typing import Callable, List
T = List[int] T = List[int]
C = Callable[[int], None] # a generic alias not having a doccomment C = Callable[[int], None] # a generic alias not having a doccomment
class Class:
#: A list of int
T = List[int]

View File

@ -1701,6 +1701,15 @@ def test_autodoc_GenericAlias(app):
'.. py:module:: target.genericalias', '.. py:module:: target.genericalias',
'', '',
'', '',
'.. py:class:: Class()',
' :module: target.genericalias',
'',
'',
' .. py:attribute:: Class.T',
' :module: target.genericalias',
'',
' alias of :class:`List`\\ [:class:`int`]',
'',
'.. py:attribute:: T', '.. py:attribute:: T',
' :module: target.genericalias', ' :module: target.genericalias',
'', '',
@ -1712,12 +1721,25 @@ def test_autodoc_GenericAlias(app):
'.. py:module:: target.genericalias', '.. py:module:: target.genericalias',
'', '',
'', '',
'.. py:class:: Class()',
' :module: target.genericalias',
'',
'',
' .. py:attribute:: Class.T',
' :module: target.genericalias',
'',
' A list of int',
'',
' alias of List[int]',
'',
'',
'.. py:data:: T', '.. py:data:: T',
' :module: target.genericalias', ' :module: target.genericalias',
'', '',
' A list of int', ' A list of int',
'', '',
' alias of List[int]', ' alias of List[int]',
'',
] ]

View File

@ -107,6 +107,32 @@ def test_autoattribute_slots_variable_str(app):
] ]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autoattribute_GenericAlias(app):
actual = do_autodoc(app, 'attribute', 'target.genericalias.Class.T')
if sys.version_info < (3, 7):
assert list(actual) == [
'',
'.. py:attribute:: Class.T',
' :module: target.genericalias',
' :value: typing.List[int]',
'',
' A list of int',
'',
]
else:
assert list(actual) == [
'',
'.. py:attribute:: Class.T',
' :module: target.genericalias',
'',
' A list of int',
'',
' alias of List[int]',
'',
]
@pytest.mark.sphinx('html', testroot='ext-autodoc') @pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autoattribute_NewType(app): def test_autoattribute_NewType(app):
actual = do_autodoc(app, 'attribute', 'target.typevar.Class.T6') actual = do_autodoc(app, 'attribute', 'target.typevar.Class.T6')

View File

@ -75,6 +75,32 @@ def test_autodata_type_comment(app):
] ]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodata_GenericAlias(app):
actual = do_autodoc(app, 'data', 'target.genericalias.T')
if sys.version_info < (3, 7):
assert list(actual) == [
'',
'.. py:data:: T',
' :module: target.genericalias',
' :value: typing.List[int]',
'',
' A list of int',
'',
]
else:
assert list(actual) == [
'',
'.. py:data:: T',
' :module: target.genericalias',
'',
' A list of int',
'',
' alias of List[int]',
'',
]
@pytest.mark.sphinx('html', testroot='ext-autodoc') @pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodata_NewType(app): def test_autodata_NewType(app):
actual = do_autodoc(app, 'data', 'target.typevar.T6') actual = do_autodoc(app, 'data', 'target.typevar.T6')