mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Add sphinx.util.inspect:isattributedescriptor()
This commit is contained in:
parent
91fac1a0c3
commit
d41cae328e
@ -1340,17 +1340,14 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def can_document_member(cls, member, membername, isattr, parent):
|
def can_document_member(cls, member, membername, isattr, parent):
|
||||||
# type: (Any, str, bool, Any) -> bool
|
# type: (Any, str, bool, Any) -> bool
|
||||||
non_attr_types = (type, MethodDescriptorType)
|
if inspect.isattributedescriptor(member):
|
||||||
isdatadesc = inspect.isdescriptor(member) and not \
|
return True
|
||||||
cls.is_function_or_method(member) and not \
|
elif (not isinstance(parent, ModuleDocumenter) and
|
||||||
isinstance(member, non_attr_types) and not \
|
not inspect.isroutine(member) and
|
||||||
type(member).__name__ == "instancemethod"
|
not isinstance(member, type)):
|
||||||
# That last condition addresses an obscure case of C-defined
|
return True
|
||||||
# methods using a deprecated type in Python 3, that is not otherwise
|
else:
|
||||||
# exported anywhere by Python
|
return False
|
||||||
return isdatadesc or (not isinstance(parent, ModuleDocumenter) and
|
|
||||||
not inspect.isroutine(member) and
|
|
||||||
not isinstance(member, type))
|
|
||||||
|
|
||||||
def document_members(self, all_members=False):
|
def document_members(self, all_members=False):
|
||||||
# type: (bool) -> None
|
# type: (bool) -> None
|
||||||
@ -1361,8 +1358,7 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):
|
|||||||
ret = super().import_object()
|
ret = super().import_object()
|
||||||
if inspect.isenumattribute(self.object):
|
if inspect.isenumattribute(self.object):
|
||||||
self.object = self.object.value
|
self.object = self.object.value
|
||||||
if inspect.isdescriptor(self.object) and \
|
if inspect.isattributedescriptor(self.object):
|
||||||
not self.is_function_or_method(self.object):
|
|
||||||
self._datadescriptor = True
|
self._datadescriptor = True
|
||||||
else:
|
else:
|
||||||
# if it's not a data descriptor
|
# if it's not a data descriptor
|
||||||
|
@ -29,6 +29,17 @@ if False:
|
|||||||
# For type annotation
|
# For type annotation
|
||||||
from typing import Any, Callable, Mapping, List, Tuple, Type # NOQA
|
from typing import Any, Callable, Mapping, List, Tuple, Type # NOQA
|
||||||
|
|
||||||
|
if sys.version_info > (3, 7):
|
||||||
|
from types import (
|
||||||
|
ClassMethodDescriptorType,
|
||||||
|
MethodDescriptorType,
|
||||||
|
WrapperDescriptorType
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
ClassMethodDescriptorType = type(object.__init__)
|
||||||
|
MethodDescriptorType = type(str.join)
|
||||||
|
WrapperDescriptorType = type(dict.__dict__['fromkeys'])
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
memory_address_re = re.compile(r' at 0x[0-9a-f]{8,16}(?=>)', re.IGNORECASE)
|
memory_address_re = re.compile(r' at 0x[0-9a-f]{8,16}(?=>)', re.IGNORECASE)
|
||||||
@ -161,6 +172,34 @@ def isdescriptor(x):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def isattributedescriptor(obj):
|
||||||
|
# type: (Any) -> bool
|
||||||
|
"""Check if the object is an attribute like descriptor."""
|
||||||
|
if inspect.isdatadescriptor(object):
|
||||||
|
# data descriptor is kind of attribute
|
||||||
|
return True
|
||||||
|
elif isdescriptor(obj):
|
||||||
|
# non data descriptor
|
||||||
|
if isfunction(obj) or isbuiltin(obj) or inspect.ismethod(obj):
|
||||||
|
# attribute must not be either function, builtin and method
|
||||||
|
return False
|
||||||
|
elif inspect.isclass(obj):
|
||||||
|
# attribute must not be a class
|
||||||
|
return False
|
||||||
|
elif isinstance(obj, (ClassMethodDescriptorType,
|
||||||
|
MethodDescriptorType,
|
||||||
|
WrapperDescriptorType)):
|
||||||
|
# attribute must not be a method descriptor
|
||||||
|
return False
|
||||||
|
elif type(obj).__name__ == "instancemethod":
|
||||||
|
# attribute must not be an instancemethod (C-API)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def isfunction(obj):
|
def isfunction(obj):
|
||||||
# type: (Any) -> bool
|
# type: (Any) -> bool
|
||||||
"""Check if the object is function."""
|
"""Check if the object is function."""
|
||||||
|
@ -7,8 +7,12 @@
|
|||||||
:copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
|
:copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
|
||||||
:license: BSD, see LICENSE for details.
|
:license: BSD, see LICENSE for details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import _testcapi
|
||||||
|
import datetime
|
||||||
import functools
|
import functools
|
||||||
import sys
|
import sys
|
||||||
|
import types
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -432,3 +436,26 @@ def test_isdescriptor(app):
|
|||||||
assert inspect.isdescriptor(Base.meth) is True # method of class
|
assert inspect.isdescriptor(Base.meth) is True # method of class
|
||||||
assert inspect.isdescriptor(Base().meth) is True # method of instance
|
assert inspect.isdescriptor(Base().meth) is True # method of instance
|
||||||
assert inspect.isdescriptor(func) is True # function
|
assert inspect.isdescriptor(func) is True # function
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx(testroot='ext-autodoc')
|
||||||
|
def test_isattributedescriptor(app):
|
||||||
|
from target.methods import Base
|
||||||
|
|
||||||
|
class Descriptor:
|
||||||
|
def __get__(self, obj, typ=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
testinstancemethod = _testcapi.instancemethod(str.__repr__)
|
||||||
|
|
||||||
|
assert inspect.isattributedescriptor(Base.prop) is True # property
|
||||||
|
assert inspect.isattributedescriptor(Base.meth) is False # method
|
||||||
|
assert inspect.isattributedescriptor(Base.staticmeth) is False # staticmethod
|
||||||
|
assert inspect.isattributedescriptor(Base.classmeth) is False # classmetho
|
||||||
|
assert inspect.isattributedescriptor(Descriptor) is False # custom descriptor class # NOQA
|
||||||
|
assert inspect.isattributedescriptor(str.join) is False # MethodDescriptorType # NOQA
|
||||||
|
assert inspect.isattributedescriptor(object.__init__) is False # WrapperDescriptorType # NOQA
|
||||||
|
assert inspect.isattributedescriptor(dict.__dict__['fromkeys']) is False # ClassMethodDescriptorType # NOQA
|
||||||
|
assert inspect.isattributedescriptor(types.FrameType.f_locals) is True # GetSetDescriptorType # NOQA
|
||||||
|
assert inspect.isattributedescriptor(datetime.timedelta.days) is True # MemberDescriptorType # NOQA
|
||||||
|
assert inspect.isattributedescriptor(testinstancemethod) is False # instancemethod (C-API) # NOQA
|
||||||
|
Loading…
Reference in New Issue
Block a user