Example #1
0
def get_documenter(app: Sphinx, obj: Any, parent: Any) -> "Type[Documenter]":
    """Get an autodoc.Documenter class suitable for documenting the given
    object.

    *obj* is the Python object to be documented, and *parent* is an
    another Python object (e.g. a module or a class) to which *obj*
    belongs to.
    """
    from sphinx.ext.autodoc import DataDocumenter, ModuleDocumenter

    if inspect.ismodule(obj):
        # ModuleDocumenter.can_document_member always returns False
        return ModuleDocumenter

    # Construct a fake documenter for *parent*
    if parent is not None:
        parent_doc_cls = get_documenter(app, parent, None)
    else:
        parent_doc_cls = ModuleDocumenter

    if hasattr(parent, '__name__'):
        parent_doc = parent_doc_cls(FakeDirective(), parent.__name__)
    else:
        parent_doc = parent_doc_cls(FakeDirective(), "")

    # Get the corrent documenter class for *obj*
    classes = [cls for cls in get_documenters(app).values()
               if cls.can_document_member(obj, '', False, parent_doc)]
    if classes:
        classes.sort(key=lambda cls: cls.priority)
        return classes[-1]
    else:
        return DataDocumenter
Example #2
0
def setup(app):
    """setup function for using this module as a sphinx extension"""
    app.setup_extension('sphinx.ext.autosummary')
    app.setup_extension('sphinx.ext.autodoc')

    # make sure to allow inheritance when registering new documenters
    if sphinx_version < [1, 7]:
        registry = AutodocRegistry._registry
    else:
        registry = get_documenters(app)
    for cls in [
            AutoSummClassDocumenter, AutoSummModuleDocumenter,
            CallableAttributeDocumenter, NoDataDataDocumenter,
            NoDataAttributeDocumenter
    ]:
        if not issubclass(registry.get(cls.objtype), cls):
            try:
                # we use add_documenter because this does not add a new
                # directive
                app.add_documenter(cls)
            except AttributeError:
                app.add_autodocumenter(cls)

    # directives
    app.add_directive('automodule', AutoSummDirective, override=True)
    app.add_directive('autoclass', AutoSummDirective, override=True)

    # group event
    app.add_event('autodocsumm-grouper')

    # config value
    app.add_config_value('autodata_content', 'class', True)
    app.add_config_value('document_data', True, True)
    app.add_config_value('not_document_data', [], True)
    return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
Example #3
0
def setup(app):
    """setup function for using this module as a sphinx extension"""
    app.setup_extension('sphinx.ext.autosummary')
    app.setup_extension('sphinx.ext.autodoc')
    app.add_directive('autoclasssumm', AutoDocSummDirective)
    app.add_directive('automodulesumm', AutoDocSummDirective)

    AUTODOC_DEFAULT_OPTIONS.extend(
        [option for option in AutoSummModuleDocumenter.option_spec
         if option not in AUTODOC_DEFAULT_OPTIONS])

    AUTODOC_DEFAULT_OPTIONS.extend(
        [option for option in AutoSummClassDocumenter.option_spec
         if option not in AUTODOC_DEFAULT_OPTIONS])

    # make sure to allow inheritance when registering new documenters
    registry = get_documenters(app)
    for cls in [AutoSummClassDocumenter, AutoSummModuleDocumenter,
                CallableAttributeDocumenter, NoDataDataDocumenter,
                NoDataAttributeDocumenter]:
        if not issubclass(registry.get(cls.objtype), cls):
            app.add_autodocumenter(cls, override=True)

    # group event
    app.add_event('autodocsumm-grouper')

    # config value
    app.add_config_value('autodata_content', 'class', True)
    app.add_config_value('document_data', True, True)
    app.add_config_value('not_document_data', [], True)
    return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
Example #4
0
def get_documenter(app, obj, parent):
    # type: (Sphinx, Any, Any) -> Type[Documenter]
    """Get an autodoc.Documenter class suitable for documenting the given
    object.

    *obj* is the Python object to be documented, and *parent* is an
    another Python object (e.g. a module or a class) to which *obj*
    belongs to.
    """
    from sphinx.ext.autodoc import DataDocumenter, ModuleDocumenter

    if inspect.ismodule(obj):
        # ModuleDocumenter.can_document_member always returns False
        return ModuleDocumenter

    # Construct a fake documenter for *parent*
    if parent is not None:
        parent_doc_cls = get_documenter(app, parent, None)
    else:
        parent_doc_cls = ModuleDocumenter

    if hasattr(parent, '__name__'):
        parent_doc = parent_doc_cls(FakeDirective(), parent.__name__)
    else:
        parent_doc = parent_doc_cls(FakeDirective(), "")

    # Get the corrent documenter class for *obj*
    classes = [cls for cls in get_documenters(app).values()
               if cls.can_document_member(obj, '', False, parent_doc)]
    if classes:
        classes.sort(key=lambda cls: cls.priority)
        return classes[-1]
    else:
        return DataDocumenter
Example #5
0
def setup(app):

    registry = get_documenters(app)
    for cls in [CodeReadMethodDocumenter, CodeReadFunctionDocumenter]:
        if not issubclass(registry.get(cls.objtype), cls):
            app.add_autodocumenter(cls, override=True)

    return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
Example #6
0
def get_documenter(*args):
    # type: (Any) -> Type[Documenter]
    """Get an autodoc.Documenter class suitable for documenting the given
    object.

    *obj* is the Python object to be documented, and *parent* is an
    another Python object (e.g. a module or a class) to which *obj*
    belongs to.
    """
    from sphinx.ext.autodoc import DataDocumenter, ModuleDocumenter
    if len(args) == 3:
        # new style arguments: (app, obj, parent)
        app, obj, parent = args
    else:
        # old style arguments: (obj, parent)
        app = _app
        obj, parent = args
        warnings.warn(
            'the interface of get_documenter() has been changed. '
            'Please give application object as first argument.',
            RemovedInSphinx20Warning,
            stacklevel=2)

    if inspect.ismodule(obj):
        # ModuleDocumenter.can_document_member always returns False
        return ModuleDocumenter

    # Construct a fake documenter for *parent*
    if parent is not None:
        parent_doc_cls = get_documenter(app, parent, None)
    else:
        parent_doc_cls = ModuleDocumenter

    if hasattr(parent, '__name__'):
        parent_doc = parent_doc_cls(FakeDirective(), parent.__name__)
    else:
        parent_doc = parent_doc_cls(FakeDirective(), "")

    # Get the corrent documenter class for *obj*
    classes = [
        cls for cls in get_documenters(app).values()
        if cls.can_document_member(obj, '', False, parent_doc)
    ]
    if classes:
        classes.sort(key=lambda cls: cls.priority)
        return classes[-1]
    else:
        return DataDocumenter
Example #7
0
    def run(self):
        # type: () -> List[nodes.Node]
        reporter = self.state.document.reporter

        try:
            source, lineno = reporter.get_source_and_line(
                self.lineno)  # type: ignore
        except AttributeError:
            source, lineno = (None, None)
        logger.debug('[autodoc] %s:%s: input:\n%s', source, lineno,
                     self.block_text)

        # look up target Documenter
        objtype = self.name[4:]  # strip prefix (auto-).
        doccls = get_documenters(self.env.app)[objtype]

        # process the options with the selected documenter's option_spec
        try:
            documenter_options = process_documenter_options(
                doccls, self.config, self.options)
        except (KeyError, ValueError, TypeError) as exc:
            # an option is either unknown or has a wrong type
            logger.error(
                'An option to %s is either unknown or has an invalid value: %s'
                % (self.name, exc),
                location=(source, lineno))
            return []

        # generate the output
        params = DocumenterBridge(self.env, reporter, documenter_options,
                                  lineno)
        documenter = doccls(params, self.arguments[0])
        documenter.generate(more_content=self.content)
        if not params.result:
            return []

        logger.debug('[autodoc] output:\n%s', '\n'.join(params.result))

        # record all filenames as dependencies -- this will at least
        # partially make automatic invalidation possible
        for fn in params.filename_set:
            self.state.document.settings.record_dependencies.add(fn)

        result = parse_generated_content(self.state, params.result, documenter)
        return result
Example #8
0
def get_documenter(*args):
    # type: (Any) -> Type[Documenter]
    """Get an autodoc.Documenter class suitable for documenting the given
    object.

    *obj* is the Python object to be documented, and *parent* is an
    another Python object (e.g. a module or a class) to which *obj*
    belongs to.
    """
    from sphinx.ext.autodoc import DataDocumenter, ModuleDocumenter
    if len(args) == 3:
        # new style arguments: (app, obj, parent)
        app, obj, parent = args
    else:
        # old style arguments: (obj, parent)
        app = _app
        obj, parent = args
        warnings.warn('the interface of get_documenter() has been changed. '
                      'Please give application object as first argument.',
                      RemovedInSphinx20Warning)

    if inspect.ismodule(obj):
        # ModuleDocumenter.can_document_member always returns False
        return ModuleDocumenter

    # Construct a fake documenter for *parent*
    if parent is not None:
        parent_doc_cls = get_documenter(app, parent, None)
    else:
        parent_doc_cls = ModuleDocumenter

    if hasattr(parent, '__name__'):
        parent_doc = parent_doc_cls(FakeDirective(), parent.__name__)
    else:
        parent_doc = parent_doc_cls(FakeDirective(), "")

    # Get the corrent documenter class for *obj*
    classes = [cls for cls in get_documenters(app).values()
               if cls.can_document_member(obj, '', False, parent_doc)]
    if classes:
        classes.sort(key=lambda cls: cls.priority)
        return classes[-1]
    else:
        return DataDocumenter
Example #9
0
    def run(self):
        # type: () -> List[nodes.Node]
        env = self.state.document.settings.env
        reporter = self.state.document.reporter

        try:
            source, lineno = reporter.get_source_and_line(self.lineno)
        except AttributeError:
            source, lineno = (None, None)
        logger.debug('[autodoc] %s:%s: input:\n%s', source, lineno, self.block_text)

        # look up target Documenter
        objtype = self.name[4:]  # strip prefix (auto-).
        doccls = get_documenters(env.app)[objtype]

        # process the options with the selected documenter's option_spec
        try:
            documenter_options = process_documenter_options(doccls, env.config, self.options)
        except (KeyError, ValueError, TypeError) as exc:
            # an option is either unknown or has a wrong type
            logger.error('An option to %s is either unknown or has an invalid value: %s' %
                         (self.name, exc), location=(source, lineno))
            return []

        # generate the output
        params = DocumenterBridge(env, reporter, documenter_options, lineno)
        documenter = doccls(params, self.arguments[0])
        documenter.generate(more_content=self.content)
        if not params.result:
            return []

        logger.debug('[autodoc] output:\n%s', '\n'.join(params.result))

        # record all filenames as dependencies -- this will at least
        # partially make automatic invalidation possible
        for fn in params.filename_set:
            self.state.document.settings.record_dependencies.add(fn)

        result = parse_generated_content(self.state, params.result, documenter)
        return result
Example #10
0
 def autosummary_documenter(self):
     """Returns the AutosummaryDocumenter subclass that can be used"""
     try:
         return self._autosummary_documenter
     except AttributeError:
         pass
     objtype = self.name[4:]
     env = self.state.document.settings.env
     if sphinx_version < [1, 7]:
         doc_class = self._registry[objtype]
         params = self
     else:
         reporter = self.state.document.reporter
         try:
             lineno = reporter.get_source_and_line(self.lineno)[1]
         except AttributeError:
             lineno = None
         doc_class = get_documenters(self.env.app)[objtype]
         args = (self.state, ) if sphinx_version >= [2, 1] else ()
         params = DocumenterBridge(
             env, reporter,
             process_documenter_options(doc_class, env.config,
                                        self.options),
             lineno, *args)
     documenter = doc_class(params, self.arguments[0])
     if hasattr(documenter, 'get_grouped_documenters'):
         self._autosummary_documenter = documenter
         return documenter
     # in case the has been changed in the registry, we decide manually
     if objtype == 'module':
         documenter = AutoSummModuleDocumenter(params, self.arguments[0])
     elif objtype == 'class':
         documenter = AutoSummClassDocumenter(params, self.arguments[0])
     else:
         raise ValueError(
             "Could not find a valid documenter for the object type %s" % (
                 objtype))
     self._autosummary_documenter = documenter
     return documenter
Example #11
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