mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #8481 from tk0miya/8480_slots_attributes
Fix #8480: autoattribute could not create document for __slots__ attributes
This commit is contained in:
commit
c941b9cb14
3
CHANGES
3
CHANGES
@ -16,6 +16,7 @@ Deprecated
|
||||
* The ``follow_wrapped`` argument of ``sphinx.util.inspect.signature()``
|
||||
* ``sphinx.ext.autodoc.Documenter.get_object_members()``
|
||||
* ``sphinx.ext.autodoc.DataDeclarationDocumenter``
|
||||
* ``sphinx.ext.autodoc.SlotsAttributeDocumenter``
|
||||
* ``sphinx.ext.autodoc.TypeVarDocumenter``
|
||||
* ``sphinx.ext.autodoc.importer._getannotations()``
|
||||
* ``sphinx.pycode.ModuleAnalyzer.parse()``
|
||||
@ -52,6 +53,8 @@ Bugs fixed
|
||||
type annotated variables
|
||||
* #8443: autodoc: autoattribute directive can't create document for PEP-526
|
||||
based uninitalized variables
|
||||
* #8480: autodoc: autoattribute could not create document for __slots__
|
||||
attributes
|
||||
* #8452: autodoc: autodoc_type_aliases doesn't work when autodoc_typehints is
|
||||
set to "description"
|
||||
* #8460: autodoc: autodata and autoattribute directives do not display type
|
||||
|
@ -41,6 +41,11 @@ The following is a list of deprecated interfaces.
|
||||
- 5.0
|
||||
- ``sphinx.ext.autodoc.DataDocumenter``
|
||||
|
||||
* - ``sphinx.ext.autodoc.SlotsAttributeDocumenter``
|
||||
- 3.4
|
||||
- 5.0
|
||||
- ``sphinx.ext.autodoc.AttributeDocumenter``
|
||||
|
||||
* - ``sphinx.ext.autodoc.TypeVarDocumenter``
|
||||
- 3.4
|
||||
- 5.0
|
||||
|
@ -1702,7 +1702,9 @@ class ExceptionDocumenter(ClassDocumenter):
|
||||
|
||||
class DataDocumenterMixinBase:
|
||||
# define types of instance variables
|
||||
parent = None # type: Any
|
||||
object = None # type: Any
|
||||
objpath = None # type: List[str]
|
||||
|
||||
def should_suppress_directive_header(self) -> bool:
|
||||
"""Check directive header should be suppressed."""
|
||||
@ -2097,7 +2099,54 @@ class SingledispatchMethodDocumenter(MethodDocumenter):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class AttributeDocumenter(NewTypeMixin, TypeVarMixin, # type: ignore
|
||||
class SlotsMixin(DataDocumenterMixinBase):
|
||||
"""
|
||||
Mixin for AttributeDocumenter to provide the feature for supporting __slots__.
|
||||
"""
|
||||
|
||||
def isslotsattribute(self) -> bool:
|
||||
"""Check the subject is an attribute in __slots__."""
|
||||
try:
|
||||
__slots__ = inspect.getslots(self.parent)
|
||||
if __slots__ and self.objpath[-1] in __slots__:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except (AttributeError, ValueError):
|
||||
return False
|
||||
|
||||
def import_object(self, raiseerror: bool = False) -> bool:
|
||||
ret = super().import_object(raiseerror) # type: ignore
|
||||
if self.isslotsattribute():
|
||||
self.object = SLOTSATTR
|
||||
|
||||
return ret
|
||||
|
||||
def should_suppress_directive_header(self) -> bool:
|
||||
if self.object is SLOTSATTR:
|
||||
self._datadescriptor = True
|
||||
return True
|
||||
else:
|
||||
return super().should_suppress_directive_header()
|
||||
|
||||
def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]:
|
||||
if self.object is SLOTSATTR:
|
||||
try:
|
||||
__slots__ = inspect.getslots(self.parent)
|
||||
if __slots__ and __slots__.get(self.objpath[-1]):
|
||||
docstring = prepare_docstring(__slots__[self.objpath[-1]])
|
||||
return [docstring]
|
||||
else:
|
||||
return []
|
||||
except (AttributeError, ValueError) as exc:
|
||||
logger.warning(__('Invalid __slots__ found on %s. Ignored.'),
|
||||
(self.parent.__qualname__, exc), type='autodoc')
|
||||
return []
|
||||
else:
|
||||
return super().get_doc(encoding, ignore) # type: ignore
|
||||
|
||||
|
||||
class AttributeDocumenter(NewTypeMixin, SlotsMixin, TypeVarMixin, # type: ignore
|
||||
DocstringStripSignatureMixin, ClassLevelDocumenter):
|
||||
"""
|
||||
Specialized Documenter subclass for attributes.
|
||||
@ -2333,52 +2382,10 @@ class SlotsAttributeDocumenter(AttributeDocumenter):
|
||||
# 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 SLOTSATTR members."""
|
||||
return member is SLOTSATTR
|
||||
|
||||
def import_object(self, raiseerror: bool = False) -> bool:
|
||||
"""Never import anything."""
|
||||
# disguise as an attribute
|
||||
self.objtype = 'attribute'
|
||||
self._datadescriptor = True
|
||||
|
||||
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.module, _, _, self.parent = ret
|
||||
return True
|
||||
except ImportError as exc:
|
||||
if raiseerror:
|
||||
raise
|
||||
else:
|
||||
logger.warning(exc.args[0], type='autodoc', subtype='import_object')
|
||||
self.env.note_reread()
|
||||
return False
|
||||
|
||||
def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]:
|
||||
"""Decode and return lines of the docstring(s) for the object."""
|
||||
if ignore is not None:
|
||||
warnings.warn("The 'ignore' argument to autodoc.%s.get_doc() is deprecated."
|
||||
% self.__class__.__name__,
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
warnings.warn("%s is deprecated." % self.__class__.__name__,
|
||||
RemovedInSphinx50Warning, stacklevel=2)
|
||||
name = self.objpath[-1]
|
||||
|
||||
try:
|
||||
__slots__ = inspect.getslots(self.parent)
|
||||
if __slots__ and isinstance(__slots__.get(name, None), str):
|
||||
docstring = prepare_docstring(__slots__[name])
|
||||
return [docstring]
|
||||
else:
|
||||
return []
|
||||
except (AttributeError, ValueError) as exc:
|
||||
logger.warning(__('Invalid __slots__ found on %s. Ignored.'),
|
||||
(self.parent.__qualname__, exc), type='autodoc')
|
||||
return []
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class NewTypeAttributeDocumenter(AttributeDocumenter):
|
||||
@ -2435,7 +2442,6 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_autodocumenter(AttributeDocumenter)
|
||||
app.add_autodocumenter(PropertyDocumenter)
|
||||
app.add_autodocumenter(InstanceAttributeDocumenter)
|
||||
app.add_autodocumenter(SlotsAttributeDocumenter)
|
||||
app.add_autodocumenter(NewTypeAttributeDocumenter)
|
||||
|
||||
app.add_config_value('autoclass_content', 'class', True, ENUM('both', 'class', 'init'))
|
||||
|
@ -91,13 +91,13 @@ def setup_documenters(app: Any) -> None:
|
||||
InstanceAttributeDocumenter, MethodDocumenter,
|
||||
ModuleDocumenter, NewTypeAttributeDocumenter,
|
||||
NewTypeDataDocumenter, PropertyDocumenter,
|
||||
SingledispatchFunctionDocumenter, SlotsAttributeDocumenter)
|
||||
SingledispatchFunctionDocumenter)
|
||||
documenters = [
|
||||
ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter,
|
||||
FunctionDocumenter, MethodDocumenter, NewTypeAttributeDocumenter,
|
||||
NewTypeDataDocumenter, AttributeDocumenter, InstanceAttributeDocumenter,
|
||||
DecoratorDocumenter, PropertyDocumenter, SlotsAttributeDocumenter,
|
||||
GenericAliasDocumenter, SingledispatchFunctionDocumenter,
|
||||
DecoratorDocumenter, PropertyDocumenter, GenericAliasDocumenter,
|
||||
SingledispatchFunctionDocumenter,
|
||||
] # type: List[Type[Documenter]]
|
||||
for documenter in documenters:
|
||||
app.registry.add_documenter(documenter.objtype, documenter)
|
||||
|
@ -72,6 +72,41 @@ def test_autoattribute_instance_variable(app):
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autoattribute_slots_variable_list(app):
|
||||
actual = do_autodoc(app, 'attribute', 'target.slots.Foo.attr')
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:attribute:: Foo.attr',
|
||||
' :module: target.slots',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autoattribute_slots_variable_dict(app):
|
||||
actual = do_autodoc(app, 'attribute', 'target.slots.Bar.attr1')
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:attribute:: Bar.attr1',
|
||||
' :module: target.slots',
|
||||
'',
|
||||
' docstring of attr1',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autoattribute_slots_variable_str(app):
|
||||
actual = do_autodoc(app, 'attribute', 'target.slots.Baz.attr')
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:attribute:: Baz.attr',
|
||||
' :module: target.slots',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autoattribute_NewType(app):
|
||||
actual = do_autodoc(app, 'attribute', 'target.typevar.Class.T6')
|
||||
|
Loading…
Reference in New Issue
Block a user