예제 #1
0
def test_ismock():
    with mock(['sphinx.unknown']):
        mod1 = import_module('sphinx.unknown')
        mod2 = import_module('sphinx.application')

        class Inherited(mod1.Class):
            pass

        assert ismock(mod1) is True
        assert ismock(mod1.Class) is True
        assert ismock(Inherited) is False

        assert ismock(mod2) is False
        assert ismock(mod2.Sphinx) is False
예제 #2
0
파일: typing.py 프로젝트: jfbu/sphinx
def restify(cls: Optional[Type],
            mode: str = 'fully-qualified-except-typing') -> str:
    """Convert python class to a reST reference.

    :param mode: Specify a method how annotations will be stringified.

                 'fully-qualified-except-typing'
                     Show the module name and qualified name of the annotation except
                     the "typing" module.
                 'smart'
                     Show the name of the annotation.
    """
    from sphinx.ext.autodoc.mock import ismock, ismockmodule  # lazy loading
    from sphinx.util import inspect  # lazy loading

    if mode == 'smart':
        modprefix = '~'
    else:
        modprefix = ''

    try:
        if cls is None or cls is NoneType:
            return ':py:obj:`None`'
        elif cls is Ellipsis:
            return '...'
        elif isinstance(cls, str):
            return cls
        elif ismockmodule(cls):
            return ':py:class:`%s%s`' % (modprefix, cls.__name__)
        elif ismock(cls):
            return ':py:class:`%s%s.%s`' % (modprefix, cls.__module__,
                                            cls.__name__)
        elif is_invalid_builtin_class(cls):
            return ':py:class:`%s%s`' % (modprefix,
                                         INVALID_BUILTIN_CLASSES[cls])
        elif inspect.isNewType(cls):
            if sys.version_info > (3, 10):
                # newtypes have correct module info since Python 3.10+
                return ':py:class:`%s%s.%s`' % (modprefix, cls.__module__,
                                                cls.__name__)
            else:
                return ':py:class:`%s`' % cls.__name__
        elif UnionType and isinstance(cls, UnionType):
            if len(cls.__args__) > 1 and None in cls.__args__:
                args = ' | '.join(restify(a, mode) for a in cls.__args__ if a)
                return 'Optional[%s]' % args
            else:
                return ' | '.join(restify(a, mode) for a in cls.__args__)
        elif cls.__module__ in ('__builtin__', 'builtins'):
            if hasattr(cls, '__args__'):
                return ':py:class:`%s`\\ [%s]' % (
                    cls.__name__,
                    ', '.join(restify(arg, mode) for arg in cls.__args__),
                )
            else:
                return ':py:class:`%s`' % cls.__name__
        else:
            return _restify_py37(cls, mode)
    except (AttributeError, TypeError):
        return inspect.object_description(cls)
예제 #3
0
    def import_object(self, raiseerror: bool = False) -> bool:
        """Overrides the default object importing method"""

        success = False

        with mock(self.config.autodoc_mock_imports):
            try:
                ret = importer.import_object(
                    self.modname,
                    self.objpath,
                    self.objtype,
                    attrgetter=self.get_attr,
                    warningiserror=self.config.autodoc_warningiserror,
                )

                self.module, self.parent, self.object_name, self.object = ret

                if ismock(self.object):
                    self.object = undecorate(self.object)

                success = True

            except ImportError as exc:
                if raiseerror:
                    raise

                logger.warning(exc.args[0],
                               type="autodoc",
                               subtype="import_object")
                self.env.note_reread()
                success = False

        return success
예제 #4
0
def get_class_members(subject: Any, objpath: List[str],
                      attrgetter: Callable) -> Dict[str, "ObjectMember"]:
    """Get members and attributes of target class."""
    from sphinx.ext.autodoc import INSTANCEATTR, ObjectMember

    # the members directly defined in the class
    obj_dict = attrgetter(subject, '__dict__', {})

    members = {}  # type: Dict[str, ObjectMember]

    # enum members
    if isenumclass(subject):
        for name, value in subject.__members__.items():
            if name not in members:
                members[name] = ObjectMember(name, value, class_=subject)

        superclass = subject.__mro__[1]
        for name in obj_dict:
            if name not in superclass.__dict__:
                value = safe_getattr(subject, name)
                members[name] = ObjectMember(name, value, class_=subject)

    # members in __slots__
    try:
        __slots__ = getslots(subject)
        if __slots__:
            from sphinx.ext.autodoc import SLOTSATTR

            for name, docstring in __slots__.items():
                members[name] = ObjectMember(name,
                                             SLOTSATTR,
                                             class_=subject,
                                             docstring=docstring)
    except (TypeError, ValueError):
        pass

    # other members
    for name in dir(subject):
        try:
            value = attrgetter(subject, name)
            if ismock(value):
                value = undecorate(value)

            unmangled = unmangle(subject, name)
            if unmangled and unmangled not in members:
                if name in obj_dict:
                    members[unmangled] = ObjectMember(unmangled,
                                                      value,
                                                      class_=subject)
                else:
                    members[unmangled] = ObjectMember(unmangled, value)
        except AttributeError:
            continue

    try:
        for cls in getmro(subject):
            try:
                modname = safe_getattr(cls, '__module__')
                qualname = safe_getattr(cls, '__qualname__')
                analyzer = ModuleAnalyzer.for_module(modname)
                analyzer.analyze()
            except AttributeError:
                qualname = None
                analyzer = None
            except PycodeError:
                analyzer = None

            # annotation only member (ex. attr: int)
            for name in getannotations(cls):
                name = unmangle(cls, name)
                if name and name not in members:
                    if analyzer and (qualname, name) in analyzer.attr_docs:
                        docstring = '\n'.join(analyzer.attr_docs[qualname,
                                                                 name])
                    else:
                        docstring = None

                    members[name] = ObjectMember(name,
                                                 INSTANCEATTR,
                                                 class_=cls,
                                                 docstring=docstring)

            # append instance attributes (cf. self.attr1) if analyzer knows
            if analyzer:
                for (ns, name), docstring in analyzer.attr_docs.items():
                    if ns == qualname and name not in members:
                        members[name] = ObjectMember(
                            name,
                            INSTANCEATTR,
                            class_=cls,
                            docstring='\n'.join(docstring))
    except AttributeError:
        pass

    return members
예제 #5
0
def stringify(annotation: Any, mode: str = 'fully-qualified-except-typing') -> str:
    """Stringify type annotation object.

    :param mode: Specify a method how annotations will be stringified.

                 'fully-qualified-except-typing'
                     Show the module name and qualified name of the annotation except
                     the "typing" module.
                 'smart'
                     Show the name of the annotation.
                 'fully-qualified'
                     Show the module name and qualified name of the annotation.
    """
    from sphinx.ext.autodoc.mock import ismock, ismockmodule  # lazy loading
    from sphinx.util import inspect  # lazy loading

    if mode == 'smart':
        modprefix = '~'
    else:
        modprefix = ''

    if isinstance(annotation, str):
        if annotation.startswith("'") and annotation.endswith("'"):
            # might be a double Forward-ref'ed type.  Go unquoting.
            return annotation[1:-1]
        else:
            return annotation
    elif isinstance(annotation, TypeVar):
        if (annotation.__module__ == 'typing' and
                mode in ('fully-qualified-except-typing', 'smart')):
            return annotation.__name__
        else:
            return modprefix + '.'.join([annotation.__module__, annotation.__name__])
    elif inspect.isNewType(annotation):
        if sys.version_info > (3, 10):
            # newtypes have correct module info since Python 3.10+
            return modprefix + '%s.%s' % (annotation.__module__, annotation.__name__)
        else:
            return annotation.__name__
    elif not annotation:
        return repr(annotation)
    elif annotation is NoneType:
        return 'None'
    elif ismockmodule(annotation):
        return modprefix + annotation.__name__
    elif ismock(annotation):
        return modprefix + '%s.%s' % (annotation.__module__, annotation.__name__)
    elif is_invalid_builtin_class(annotation):
        return modprefix + INVALID_BUILTIN_CLASSES[annotation]
    elif str(annotation).startswith('typing.Annotated'):  # for py310+
        pass
    elif (getattr(annotation, '__module__', None) == 'builtins' and
          getattr(annotation, '__qualname__', None)):
        if hasattr(annotation, '__args__'):  # PEP 585 generic
            return repr(annotation)
        else:
            return annotation.__qualname__
    elif annotation is Ellipsis:
        return '...'

    if sys.version_info >= (3, 7):  # py37+
        return _stringify_py37(annotation, mode)
    else:
        return _stringify_py36(annotation, mode)
예제 #6
0
파일: importer.py 프로젝트: varphone/sphinx
def get_class_members(
        subject: Any,
        objpath: List[str],
        attrgetter: Callable,
        inherit_docstrings: bool = True) -> Dict[str, "ObjectMember"]:
    """Get members and attributes of target class."""
    from sphinx.ext.autodoc import INSTANCEATTR, ObjectMember

    # the members directly defined in the class
    obj_dict = attrgetter(subject, '__dict__', {})

    members: Dict[str, ObjectMember] = {}

    # enum members
    if isenumclass(subject):
        for name, value in subject.__members__.items():
            if name not in members:
                members[name] = ObjectMember(name, value, class_=subject)

        superclass = subject.__mro__[1]
        for name in obj_dict:
            if name not in superclass.__dict__:
                value = safe_getattr(subject, name)
                members[name] = ObjectMember(name, value, class_=subject)

    # members in __slots__
    try:
        __slots__ = getslots(subject)
        if __slots__:
            from sphinx.ext.autodoc import SLOTSATTR

            for name, docstring in __slots__.items():
                members[name] = ObjectMember(name,
                                             SLOTSATTR,
                                             class_=subject,
                                             docstring=docstring)
    except (TypeError, ValueError):
        pass

    # other members
    for name in dir(subject):
        try:
            value = attrgetter(subject, name)
            if ismock(value):
                value = undecorate(value)

            unmangled = unmangle(subject, name)
            if unmangled and unmangled not in members:
                if name in obj_dict:
                    members[unmangled] = ObjectMember(unmangled,
                                                      value,
                                                      class_=subject)
                else:
                    members[unmangled] = ObjectMember(unmangled, value)
        except AttributeError:
            continue

    try:
        for cls in getmro(subject):
            try:
                modname = safe_getattr(cls, '__module__')
                qualname = safe_getattr(cls, '__qualname__')
                analyzer = ModuleAnalyzer.for_module(modname)
                analyzer.analyze()
            except AttributeError:
                qualname = None
                analyzer = None
            except PycodeError:
                analyzer = None

            # annotation only member (ex. attr: int)
            for name in getannotations(cls):
                name = unmangle(cls, name)
                if name and name not in members:
                    if analyzer and (qualname, name) in analyzer.attr_docs:
                        docstring = '\n'.join(analyzer.attr_docs[qualname,
                                                                 name])
                    else:
                        docstring = None

                    members[name] = ObjectMember(name,
                                                 INSTANCEATTR,
                                                 class_=cls,
                                                 docstring=docstring)

            # append or complete instance attributes (cf. self.attr1) if analyzer knows
            if analyzer:
                for (ns, name), docstring in analyzer.attr_docs.items():
                    if ns == qualname and name not in members:
                        # otherwise unknown instance attribute
                        members[name] = ObjectMember(
                            name,
                            INSTANCEATTR,
                            class_=cls,
                            docstring='\n'.join(docstring))
                    elif (ns == qualname and docstring
                          and isinstance(members[name], ObjectMember)
                          and not members[name].docstring):
                        if cls != subject and not inherit_docstrings:
                            # If we are in the MRO of the class and not the class itself,
                            # and we do not want to inherit docstrings, then skip setting
                            # the docstring below
                            continue
                        # attribute is already known, because dir(subject) enumerates it.
                        # But it has no docstring yet
                        members[name].docstring = '\n'.join(docstring)
    except AttributeError:
        pass

    return members