mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #8444 from tk0miya/8443_autodata_for_pep526
Fix #8443: autodata directive does not support PEP-526 ivars
This commit is contained in:
commit
18b2707b2a
5
CHANGES
5
CHANGES
@ -14,6 +14,7 @@ Deprecated
|
||||
----------
|
||||
|
||||
* The ``follow_wrapped`` argument of ``sphinx.util.inspect.signature()``
|
||||
* ``sphinx.ext.autodoc.DataDeclarationDocumenter``
|
||||
* ``sphinx.util.requests.is_ssl_error()``
|
||||
|
||||
Features added
|
||||
@ -42,6 +43,10 @@ Bugs fixed
|
||||
is decorated
|
||||
* #8434: autodoc: :confval:`autodoc_type_aliases` does not effect to variables
|
||||
and attributes
|
||||
* #8443: autodoc: autodata directive can't create document for PEP-526 based
|
||||
type annotated variables
|
||||
* #8443: autodoc: autoattribute directive can't create document for PEP-526
|
||||
based uninitalized variables
|
||||
* #8419: html search: Do not load ``language_data.js`` in non-search pages
|
||||
|
||||
Testing
|
||||
|
@ -31,6 +31,11 @@ The following is a list of deprecated interfaces.
|
||||
- 5.0
|
||||
- N/A
|
||||
|
||||
* - ``sphinx.ext.autodoc.DataDeclarationDocumenter``
|
||||
- 3.4
|
||||
- 5.0
|
||||
- ``sphinx.ext.autodoc.DataDocumenter``
|
||||
|
||||
* - ``sphinx.util.requests.is_ssl_error()``
|
||||
- 3.4
|
||||
- 5.0
|
||||
|
@ -1687,6 +1687,28 @@ class DataDocumenter(ModuleLevelDocumenter):
|
||||
) -> bool:
|
||||
return isinstance(parent, ModuleDocumenter) and isattr
|
||||
|
||||
def import_object(self, raiseerror: bool = False) -> bool:
|
||||
try:
|
||||
return super().import_object(raiseerror=True)
|
||||
except ImportError as exc:
|
||||
# annotation only instance variable (PEP-526)
|
||||
try:
|
||||
self.parent = importlib.import_module(self.modname)
|
||||
annotations = get_type_hints(self.parent, None,
|
||||
self.config.autodoc_type_aliases)
|
||||
if self.objpath[-1] in annotations:
|
||||
self.object = UNINITIALIZED_ATTR
|
||||
return True
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
if raiseerror:
|
||||
raise
|
||||
else:
|
||||
logger.warning(exc.args[0], type='autodoc', subtype='import_object')
|
||||
self.env.note_reread()
|
||||
return False
|
||||
|
||||
def add_directive_header(self, sig: str) -> None:
|
||||
super().add_directive_header(sig)
|
||||
sourcename = self.get_sourcename()
|
||||
@ -1723,6 +1745,13 @@ class DataDocumenter(ModuleLevelDocumenter):
|
||||
return self.get_attr(self.parent or self.object, '__module__', None) \
|
||||
or self.modname
|
||||
|
||||
def add_content(self, more_content: Any, no_docstring: bool = False) -> None:
|
||||
if self.object is UNINITIALIZED_ATTR:
|
||||
# suppress docstring of the value
|
||||
super().add_content(more_content, no_docstring=True)
|
||||
else:
|
||||
super().add_content(more_content, no_docstring=no_docstring)
|
||||
|
||||
|
||||
class DataDeclarationDocumenter(DataDocumenter):
|
||||
"""
|
||||
@ -1736,30 +1765,10 @@ class DataDeclarationDocumenter(DataDocumenter):
|
||||
# must be higher than AttributeDocumenter
|
||||
priority = 11
|
||||
|
||||
@classmethod
|
||||
def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
|
||||
) -> bool:
|
||||
"""This documents only INSTANCEATTR members."""
|
||||
return (isinstance(parent, ModuleDocumenter) and
|
||||
isattr and
|
||||
member is INSTANCEATTR)
|
||||
|
||||
def import_object(self, raiseerror: bool = False) -> bool:
|
||||
"""Never import anything."""
|
||||
# disguise as a data
|
||||
self.objtype = 'data'
|
||||
self.object = UNINITIALIZED_ATTR
|
||||
try:
|
||||
# import module to obtain type annotation
|
||||
self.parent = importlib.import_module(self.modname)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
return True
|
||||
|
||||
def add_content(self, more_content: Any, no_docstring: bool = False) -> None:
|
||||
"""Never try to get a docstring from the object."""
|
||||
super().add_content(more_content, no_docstring=True)
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
warnings.warn("%s is deprecated." % self.__class__.__name__,
|
||||
RemovedInSphinx50Warning, stacklevel=2)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class GenericAliasDocumenter(DataDocumenter):
|
||||
@ -2026,6 +2035,22 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):
|
||||
|
||||
def isinstanceattribute(self) -> bool:
|
||||
"""Check the subject is an instance attribute."""
|
||||
# uninitialized instance variable (PEP-526)
|
||||
with mock(self.config.autodoc_mock_imports):
|
||||
try:
|
||||
ret = import_object(self.modname, self.objpath[:-1], 'class',
|
||||
attrgetter=self.get_attr,
|
||||
warningiserror=self.config.autodoc_warningiserror)
|
||||
self.parent = ret[3]
|
||||
annotations = get_type_hints(self.parent, None,
|
||||
self.config.autodoc_type_aliases)
|
||||
if self.objpath[-1] in annotations:
|
||||
self.object = UNINITIALIZED_ATTR
|
||||
return True
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# An instance variable defined inside __init__().
|
||||
try:
|
||||
analyzer = ModuleAnalyzer.for_module(self.modname)
|
||||
attr_docs = analyzer.find_attr_docs()
|
||||
@ -2036,7 +2061,9 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):
|
||||
|
||||
return False
|
||||
except PycodeError:
|
||||
return False
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
def import_object(self, raiseerror: bool = False) -> bool:
|
||||
try:
|
||||
@ -2272,7 +2299,6 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_autodocumenter(ClassDocumenter)
|
||||
app.add_autodocumenter(ExceptionDocumenter)
|
||||
app.add_autodocumenter(DataDocumenter)
|
||||
app.add_autodocumenter(DataDeclarationDocumenter)
|
||||
app.add_autodocumenter(GenericAliasDocumenter)
|
||||
app.add_autodocumenter(TypeVarDocumenter)
|
||||
app.add_autodocumenter(FunctionDocumenter)
|
||||
|
@ -85,8 +85,7 @@ AutosummaryEntry = NamedTuple('AutosummaryEntry', [('name', str),
|
||||
|
||||
|
||||
def setup_documenters(app: Any) -> None:
|
||||
from sphinx.ext.autodoc import (AttributeDocumenter, ClassDocumenter,
|
||||
DataDeclarationDocumenter, DataDocumenter,
|
||||
from sphinx.ext.autodoc import (AttributeDocumenter, ClassDocumenter, DataDocumenter,
|
||||
DecoratorDocumenter, ExceptionDocumenter,
|
||||
FunctionDocumenter, GenericAliasDocumenter,
|
||||
InstanceAttributeDocumenter, MethodDocumenter,
|
||||
@ -96,8 +95,7 @@ def setup_documenters(app: Any) -> None:
|
||||
ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter,
|
||||
FunctionDocumenter, MethodDocumenter, AttributeDocumenter,
|
||||
InstanceAttributeDocumenter, DecoratorDocumenter, PropertyDocumenter,
|
||||
SlotsAttributeDocumenter, DataDeclarationDocumenter, GenericAliasDocumenter,
|
||||
SingledispatchFunctionDocumenter,
|
||||
SlotsAttributeDocumenter, GenericAliasDocumenter, SingledispatchFunctionDocumenter,
|
||||
] # type: List[Type[Documenter]]
|
||||
for documenter in documenters:
|
||||
app.registry.add_documenter(documenter.objtype, documenter)
|
||||
|
@ -9,6 +9,8 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
from test_ext_autodoc import do_autodoc
|
||||
|
||||
@ -39,3 +41,31 @@ def test_autoattribute_novalue(app):
|
||||
' should be documented -- süß',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.')
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autoattribute_typed_variable(app):
|
||||
actual = do_autodoc(app, 'attribute', 'target.typed_vars.Class.attr2')
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:attribute:: Class.attr2',
|
||||
' :module: target.typed_vars',
|
||||
' :type: int',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.')
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autoattribute_instance_variable(app):
|
||||
actual = do_autodoc(app, 'attribute', 'target.typed_vars.Class.attr4')
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:attribute:: Class.attr4',
|
||||
' :module: target.typed_vars',
|
||||
' :type: int',
|
||||
'',
|
||||
' attr4',
|
||||
'',
|
||||
]
|
||||
|
@ -9,6 +9,8 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
from test_ext_autodoc import do_autodoc
|
||||
|
||||
@ -39,3 +41,34 @@ def test_autodata_novalue(app):
|
||||
' documentation for the integer',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.')
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autodata_typed_variable(app):
|
||||
actual = do_autodoc(app, 'data', 'target.typed_vars.attr2')
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:data:: attr2',
|
||||
' :module: target.typed_vars',
|
||||
' :type: str',
|
||||
'',
|
||||
' attr2',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.')
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autodata_type_comment(app):
|
||||
actual = do_autodoc(app, 'data', 'target.typed_vars.attr3')
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:data:: attr3',
|
||||
' :module: target.typed_vars',
|
||||
' :type: str',
|
||||
" :value: ''",
|
||||
'',
|
||||
' attr3',
|
||||
'',
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user