def add_content(_wrapped, self, *args, **kwds):
     if not self._datadescriptor and self.analyzer and self.objpath:
         attr_docs = self.analyzer.find_attr_docs()
         key = ('.'.join(self.objpath[:-1]), self.objpath[-1])
         if key not in attr_docs:
             # look for parent class w/ correct attr
             if hasattr(self.parent, "__mro__"):
                 for basecls in self.parent.__mro__[1:]:
                     try:
                         analyzer = ModuleAnalyzer.for_module(basecls.__module__)
                         base_attr_docs = analyzer.find_attr_docs()
                     except PycodeError as err:
                         continue
                     # FIXME: need qualname or equivalent for basecls
                     base_key = (basecls.__name__, self.objpath[-1])
                     if base_key in base_attr_docs:
                         # insert data into existing analyzer
                         # XXX: might be prettier way to handle this,
                         #      (esp so actual source file was reported)
                         #      but would have to duplicate much of add_content()
                         attr_docs[key] = base_attr_docs[base_key]
                         break
     return _wrapped(self, *args, **kwds)
 def add_content(_wrapped, self, *args, **kwds):
     if not self._datadescriptor and self.analyzer and self.objpath:
         attr_docs = self.analyzer.find_attr_docs()
         key = ('.'.join(self.objpath[:-1]), self.objpath[-1])
         if key not in attr_docs:
             # look for parent class w/ correct attr
             if hasattr(self.parent, "__mro__"):
                 for basecls in self.parent.__mro__[1:]:
                     try:
                         analyzer = ModuleAnalyzer.for_module(
                             basecls.__module__)
                         base_attr_docs = analyzer.find_attr_docs()
                     except PycodeError as err:
                         continue
                     # FIXME: need qualname or equivalent for basecls
                     base_key = (basecls.__name__, self.objpath[-1])
                     if base_key in base_attr_docs:
                         # insert data into existing analyzer
                         # XXX: might be prettier way to handle this,
                         #      (esp so actual source file was reported)
                         #      but would have to duplicate much of add_content()
                         attr_docs[key] = base_attr_docs[base_key]
                         break
     return _wrapped(self, *args, **kwds)
示例#3
0
    def get_grouped_documenters(self, all_members=False):
        """Method to return the member documenters

        This method is somewhat like a combination of the
        :meth:`sphinx.ext.autodoc.ModuleDocumenter.generate` method and the
        :meth:`sphinx.ext.autodoc.ModuleDocumenter.document_members` method.
        Hence it initializes this instance by importing the object, etc. and
        it finds the documenters to use for the autosummary option in the same
        style as the document_members does it.

        Returns
        -------
        dict
            dictionary whose keys are determined by the :attr:`member_sections`
            dictionary and whose values are lists of tuples. Each tuple
            consists of a documenter and a boolean to identify whether a module
            check should be made describes an attribute or not. The dictionary
            can be used in the
            :meth:`AutoSummDirective.get_items_from_documenters` method

        Notes
        -----
        If a :class:`sphinx.ext.autodoc.Documenter.member_order` value is not
        in the :attr:`member_sections` dictionary, it will be put into an
        additional `Miscellaneous` section."""
        self.parse_name()
        self.import_object()
        # If there is no real module defined, figure out which to use.
        # The real module is used in the module analyzer to look up the module
        # where the attribute documentation would actually be found in.
        # This is used for situations where you have a module that collects the
        # functions and classes of internal submodules.
        self.real_modname = None or self.get_real_modname()

        # try to also get a source code analyzer for attribute docs
        try:
            self.analyzer = ModuleAnalyzer.for_module(self.real_modname)
            # parse right now, to get PycodeErrors on parsing (results will
            # be cached anyway)
            self.analyzer.find_attr_docs()
        except PycodeError as err:
            logger.debug('[autodocsumm] module analyzer failed: %s', err)
            # no source file -- e.g. for builtin and C modules
            self.analyzer = None
            # at least add the module.__file__ as a dependency
            if hasattr(self.module, '__file__') and self.module.__file__:
                self.directive.filename_set.add(self.module.__file__)
        else:
            self.directive.filename_set.add(self.analyzer.srcname)

        self.env.temp_data['autodoc:module'] = self.modname
        if self.objpath:
            self.env.temp_data['autodoc:class'] = self.objpath[0]

        # set the members from the autosummary member options
        options_save = {}
        for option in member_options.intersection(self.option_spec):
            autopt = 'autosummary-' + option
            if getattr(self.options, autopt):
                options_save[option] = getattr(self.options, option)
                self.options[option] = getattr(self.options, autopt)

        want_all = all_members or self.options.inherited_members or \
            self.options.members is ALL
        # find out which members are documentable
        members_check_module, members = self.get_object_members(want_all)

        # remove members given by exclude-members
        if self.options.exclude_members:
            members = [(membername, member) for (membername, member) in members
                       if membername not in self.options.exclude_members]

        # document non-skipped members
        memberdocumenters = []
        if sphinx_version < [1, 7]:
            registry = AutodocRegistry._registry
        else:
            registry = get_documenters(self.env.app)
        for (mname, member, isattr) in self.filter_members(members, want_all):
            classes = [cls for cls in six.itervalues(registry)
                       if cls.can_document_member(member, mname, isattr, self)]
            if not classes:
                # don't know how to document this member
                continue
            # prefer the documenter with the highest priority
            classes.sort(key=lambda cls: cls.priority)
            # give explicitly separated module name, so that members
            # of inner classes can be documented
            full_mname = self.modname + '::' + \
                '.'.join(self.objpath + [mname])

            documenter = classes[-1](self.directive, full_mname, self.indent)
            memberdocumenters.append((documenter,
                                      members_check_module and not isattr))
        documenters = OrderedDict()
        for e in memberdocumenters:
            section = self.member_sections.get(
                e[0].member_order, 'Miscellaneous')
            if self.env.app:
                e[0].parse_name()
                e[0].import_object()
                user_section = self.env.app.emit_firstresult(
                    'autodocsumm-grouper', self.objtype, e[0].object_name,
                    e[0].object, section, self.object)
                section = user_section or section
            documenters.setdefault(section, []).append(e)
        self.options.update(options_save)
        return documenters
示例#4
0
    def get_items_from_documenters(self, documenters):
        """Return the items needed for creating the tables

        This method creates the items that are used by the
        :meth:`sphinx.ext.autosummary.Autosummary.get_table` method by what is
        taken from the values of the
        :meth:`AutoSummModuleDocumenter.get_grouped_documenters` method.

        Returns
        -------
        list
            A list containing tuples like
            ``(name, signature, summary_string, real_name)`` that can be used
            for the :meth:`sphinx.ext.autosummary.Autosummary.get_table`
            method."""

        items = []

        max_item_chars = 50
        base_documenter = self.autosummary_documenter
        try:
            base_documenter.analyzer = ModuleAnalyzer.for_module(
                    base_documenter.real_modname)
            attr_docs = base_documenter.analyzer.find_attr_docs()
        except PycodeError as err:
            logger.debug('[autodocsumm] module analyzer failed: %s', err)
            # no source file -- e.g. for builtin and C modules
            base_documenter.analyzer = None
            attr_docs = {}
            # at least add the module.__file__ as a dependency
            if (hasattr(base_documenter.module, '__file__') and
                    base_documenter.module.__file__):
                base_documenter.directive.filename_set.add(
                    base_documenter.module.__file__)
        else:
            base_documenter.directive.filename_set.add(
                base_documenter.analyzer.srcname)

        for documenter, check_module in documenters:
            documenter.parse_name()
            documenter.import_object()
            documenter.real_modname = documenter.get_real_modname()
            real_name = documenter.fullname
            display_name = documenter.object_name
            if display_name is None:  # for instance attributes
                display_name = documenter.objpath[-1]
            if check_module and not documenter.check_module():
                continue

            # -- Grab the signature

            sig = documenter.format_signature()
            if not sig:
                sig = ''
            else:
                max_chars = max(10, max_item_chars - len(display_name))
                sig = mangle_signature(sig, max_chars=max_chars)
#                sig = sig.replace('*', r'\*')

            # -- Grab the documentation

            no_docstring = False
            if documenter.objpath:
                key = ('.'.join(documenter.objpath[:-1]),
                       documenter.objpath[-1])
                try:
                    doc = attr_docs[key]
                    no_docstring = True
                except KeyError:
                    pass
            if not no_docstring:
                documenter.add_content(None)
                doc = documenter.get_doc()
                if doc:
                    doc = doc[0]
                else:
                    continue

            while doc and not doc[0].strip():
                doc.pop(0)

            # If there's a blank line, then we can assume the first sentence /
            # paragraph has ended, so anything after shouldn't be part of the
            # summary
            for i, piece in enumerate(doc):
                if not piece.strip():
                    doc = doc[:i]
                    break

            # Try to find the "first sentence", which may span multiple lines
            m = re.search(r"^([A-Z].*?\.)(?:\s|$)", " ".join(doc).strip())
            if m:
                summary = m.group(1).strip()
            elif doc:
                summary = doc[0].strip()
            else:
                summary = ''

            items.append((display_name, sig, summary, real_name))
        return items
示例#5
0
    def get_items_from_documenters(self, documenters):
        """Return the items needed for creating the tables

        This method creates the items that are used by the
        :meth:`sphinx.ext.autosummary.Autosummary.get_table` method by what is
        taken from the values of the
        :meth:`AutoSummModuleDocumenter.get_grouped_documenters` method.

        Returns
        -------
        list
            A list containing tuples like
            ``(name, signature, summary_string, real_name)`` that can be used
            for the :meth:`sphinx.ext.autosummary.Autosummary.get_table`
            method."""

        items = []

        max_item_chars = 50
        base_documenter = self.autosummary_documenter
        base_documenter.analyzer = ModuleAnalyzer.for_module(
                base_documenter.real_modname)
        attr_docs = base_documenter.analyzer.find_attr_docs()

        for documenter, check_module in documenters:
            documenter.parse_name()
            documenter.import_object()
            documenter.real_modname = documenter.get_real_modname()
            real_name = documenter.fullname
            display_name = documenter.object_name
            if check_module and not documenter.check_module():
                continue

            # -- Grab the signature

            sig = documenter.format_signature()
            if not sig:
                sig = ''
            else:
                max_chars = max(10, max_item_chars - len(display_name))
                sig = mangle_signature(sig, max_chars=max_chars)
                sig = sig.replace('*', r'\*')

            # -- Grab the documentation

            no_docstring = False
            if documenter.objpath:
                key = ('.'.join(documenter.objpath[:-1]),
                       documenter.objpath[-1])
                try:
                    doc = attr_docs[key]
                    no_docstring = True
                except KeyError:
                    pass
            if not no_docstring:
                documenter.add_content(None)
                doc = documenter.get_doc()
                if doc:
                    doc = doc[0]
                else:
                    continue

            while doc and not doc[0].strip():
                doc.pop(0)

            # If there's a blank line, then we can assume the first sentence /
            # paragraph has ended, so anything after shouldn't be part of the
            # summary
            for i, piece in enumerate(doc):
                if not piece.strip():
                    doc = doc[:i]
                    break

            # Try to find the "first sentence", which may span multiple lines
            m = re.search(r"^([A-Z].*?\.)(?:\s|$)", " ".join(doc).strip())
            if m:
                summary = m.group(1).strip()
            elif doc:
                summary = doc[0].strip()
            else:
                summary = ''

            items.append((display_name, sig, summary, real_name))
        return items
示例#6
0
    def get_grouped_documenters(self, all_members=False):
        """Method to return the member documenters

        This method is somewhat like a combination of the
        :meth:`sphinx.ext.autodoc.ModuleDocumenter.generate` method and the
        :meth:`sphinx.ext.autodoc.ModuleDocumenter.document_members` method.
        Hence it initializes this instance by importing the object, etc. and
        it finds the documenters to use for the autosummary option in the same
        style as the document_members does it.

        Returns
        -------
        dict
            dictionary whose keys are determined by the :attr:`member_sections`
            dictionary and whose values are lists of tuples. Each tuple
            consists of a documenter and a boolean to identify whether a module
            check should be made describes an attribute or not. The dictionary
            can be used in the
            :meth:`AutoSummDirective.get_items_from_documenters` method

        Notes
        -----
        If a :class:`sphinx.ext.autodoc.Documenter.member_order` value is not
        in the :attr:`member_sections` dictionary, it will be put into an
        additional `Miscallaneous` section."""
        self.parse_name()
        self.import_object()
        # If there is no real module defined, figure out which to use.
        # The real module is used in the module analyzer to look up the module
        # where the attribute documentation would actually be found in.
        # This is used for situations where you have a module that collects the
        # functions and classes of internal submodules.
        self.real_modname = None or self.get_real_modname()

        if not self.options.get('show-formatoptions') or not hasattr(
                self.object, '_get_formatoptions'):
            def is_not_fmt(docu_tuple):
                return True
        else:
            fmt_keys = list(self.object._get_formatoptions())

            def is_not_fmt(docu_tuple):
                return docu_tuple[0].name.split('.')[-1] not in fmt_keys

        # try to also get a source code analyzer for attribute docs
        try:
            self.analyzer = ModuleAnalyzer.for_module(self.real_modname)
            # parse right now, to get PycodeErrors on parsing (results will
            # be cached anyway)
            self.analyzer.find_attr_docs()
        except PycodeError as err:
            self.env.app.debug('[autodoc] module analyzer failed: %s', err)
            # no source file -- e.g. for builtin and C modules
            self.analyzer = None
            # at least add the module.__file__ as a dependency
            if hasattr(self.module, '__file__') and self.module.__file__:
                self.directive.filename_set.add(self.module.__file__)
        else:
            self.directive.filename_set.add(self.analyzer.srcname)

        self.env.temp_data['autodoc:module'] = self.modname
        if self.objpath:
            self.env.temp_data['autodoc:class'] = self.objpath[0]

        want_all = all_members or self.options.inherited_members or \
            self.options.members is ALL
        # find out which members are documentable
        members_check_module, members = self.get_object_members(want_all)

        # remove members given by exclude-members
        if self.options.exclude_members:
            members = [(membername, member) for (membername, member) in members
                       if membername not in self.options.exclude_members]

        # document non-skipped members
        memberdocumenters = []
        for (mname, member, isattr) in self.filter_members(members, want_all):
            classes = [cls for cls in six.itervalues(AutoDirective._registry)
                       if cls.can_document_member(member, mname, isattr, self)]
            if not classes:
                # don't know how to document this member
                continue
            # prefer the documenter with the highest priority
            classes.sort(key=lambda cls: cls.priority)
            # give explicitly separated module name, so that members
            # of inner classes can be documented
            full_mname = self.modname + '::' + \
                '.'.join(self.objpath + [mname])
            documenter = classes[-1](self.directive, full_mname, self.indent)
            memberdocumenters.append((documenter,
                                      members_check_module and not isattr))
        documenters = self.member_sections.copy()
        for section, order in six.iteritems(documenters):
            documenters[section] = sorted(
                (e for e in memberdocumenters
                 if e[0].member_order == order and is_not_fmt(e)),
                key=lambda e: e[0].member_order)
        fmts = defaultdict(set)
        for e in filterfalse(is_not_fmt, memberdocumenters):
            e[0].parse_name()
            e[0].import_object()
            fmts[e[0].object.groupname].add(e)
        for gname, l in sorted(fmts.items()):
            documenters[gname] = sorted(
                l, key=lambda e: e[0].object.key)
        remaining = sorted(
            (e for e in memberdocumenters
             if e[0].member_order not in six.itervalues(self.member_sections)),
            key=lambda e: e[0].name.split('::')[-1])
        if remaining:
            documenters['Miscallaneous'] = remaining
        return documenters