Ejemplo n.º 1
0
 def test_generates_doc_for_handler(self):
     # generate_api_docs() yields HandlerDocumentation objects for the
     # handlers passed in.
     resource = self.make_resource()
     docs = list(generate_api_docs([resource]))
     self.assertEqual(1, len(docs))
     [doc] = docs
     self.assertIsInstance(doc, HandlerDocumentation)
     self.assertIs(type(resource.handler), doc.handler)
Ejemplo n.º 2
0
 def test_handler_without_resource_uri(self):
     # generate_api_docs() raises an exception if a handler does not have a
     # resource_uri attribute.
     resource = OperationsResource(BaseHandler)
     docs = generate_api_docs([resource])
     error = self.assertRaises(AssertionError, list, docs)
     self.assertEqual(
         "Missing resource_uri in %s" % type(resource.handler).__name__,
         str(error))
Ejemplo n.º 3
0
 def test_generates_doc_for_multiple_handlers(self):
     # generate_api_docs() yields HandlerDocumentation objects for the
     # handlers passed in.
     resources = [self.make_resource() for _ in range(5)]
     docs = list(generate_api_docs(resources))
     sorted_handlers = sorted(
         [type(resource.handler) for resource in resources],
         key=lambda handler_class: handler_class.__name__)
     self.assertEqual(sorted_handlers, [doc.handler for doc in docs])
Ejemplo n.º 4
0
 def test_handlers_have_section_title(self):
     from maasserver import urls_api as urlconf
     resources = find_api_resources(urlconf)
     handlers = []
     for doc in generate_api_docs(resources):
         handlers.append(doc.handler)
     handlers_missing_section_name = [
         handler.__name__ for handler in handlers
         if not hasattr(handler, 'api_doc_section_name')
     ]
     self.assertEqual(
         [], handlers_missing_section_name,
         "%d handlers are missing an api_doc_section_name field." %
         len(handlers_missing_section_name))
Ejemplo n.º 5
0
def render_api_docs():
    """Render ReST documentation for the REST API.

    This module's docstring forms the head of the documentation; details of
    the API methods follow.

    :return: Documentation, in ReST, for the API.
    :rtype: :class:`unicode`
    """
    from maasserver import urls_api as urlconf

    module = sys.modules[__name__]
    output = StringIO()
    line = partial(print, file=output)

    line(getdoc(module))
    line()
    line()
    line('Operations')
    line('``````````')
    line()

    def export_key(export):
        """Return a sortable key for an export.

        `op` is often `None`, which cannot be compared to non-`None`
        operations.
        """
        (http_method, op), function = export
        if op is None:
            return http_method, "", function
        else:
            return http_method, op, function

    resources = find_api_resources(urlconf)
    for doc in generate_api_docs(resources):
        uri_template = doc.resource_uri_template
        exports = doc.handler.exports.items()
        # Derive a section title from the name of the handler class.
        section_name = doc.handler.api_doc_section_name
        line(section_name)
        line('=' * len(section_name))
        line(dedent(doc.handler.__doc__).strip())
        line()
        line()
        for (http_method, op), function in sorted(exports, key=export_key):
            operation = " op=%s" % op if op is not None else ""
            subsection = "``%s %s%s``" % (http_method, uri_template, operation)
            line("%s\n%s\n" % (subsection, '#' * len(subsection)))
            line()
            docstring = getdoc(function)
            if docstring is not None:
                for docline in dedent(docstring).splitlines():
                    if docline.strip() == '':
                        # Blank line.  Don't indent.
                        line()
                    else:
                        # Print documentation line, indented.
                        line(docline)
                line()
    line()
    line()
    line(generate_power_types_doc())
    line()
    line()
    line(generate_pod_types_doc())

    return output.getvalue()
Ejemplo n.º 6
0
def render_api_docs():
    """Render ReST documentation for the REST API.


    This module's docstring forms the head of the documentation; details of
    the API methods follow.

    :return: Documentation, in ReST, for the API.
    :rtype: :class:`unicode`
    """
    from maasserver import urls_api as urlconf

    module = sys.modules[__name__]
    output = StringIO()
    line = partial(print, file=output)

    line(getdoc(module))
    line()
    line()
    line("Operations")
    line("``````````")
    line()

    def export_key(export):
        """Return a sortable key for an export.

        `op` is often `None`, which cannot be compared to non-`None`
        operations.
        """
        (http_method, op), function = export
        if op is None:
            return http_method, "", function
        else:
            return http_method, op, function

    annotation_parser = APIDocstringParser()
    templates = APITemplateRenderer()
    resources = find_api_resources(urlconf)
    for doc in generate_api_docs(resources):
        uri_template = doc.resource_uri_template
        exports = doc.handler.exports.items()
        # Derive a section title from the name of the handler class.
        section_name = doc.handler.api_doc_section_name
        line(section_name)
        line("=" * len(section_name))
        # Note:
        # The following dedent is useless in the following situation:
        #
        # def somefunc(foo)
        #     """No indent here
        #
        #     Here, there is an indent, so dedent doesn't do
        #     anything.
        #    """
        #
        # This fixes the problem:
        #
        # def somefunc(foo)
        #     """
        #     Indent here
        #
        #     Now dedent works because the entire docstring appears
        #     to be indented.
        #    """
        #
        # This also works because the dedent version is the same
        # as the non-dented version:
        #
        # def somefunc(foo)
        #     """No indent here"""
        #
        line(dedent(doc.handler.__doc__).strip())
        line()
        line()
        for (http_method, op), function in sorted(exports, key=export_key):
            operation = " op=%s" % op if op is not None else ""
            subsection = "``%s %s%s``" % (http_method, uri_template, operation)
            docstring = getdoc(function)
            if docstring is not None:
                if APIDocstringParser.is_annotated_docstring(docstring):
                    operation = "op=%s" % op if op is not None else ""
                    annotation_parser.parse(
                        docstring, http_method, uri_template, operation
                    )
                    line(
                        templates.apply_template(
                            os.path.dirname(__file__) + "/tmpl-apidoc.rst",
                            annotation_parser,
                        )
                    )
                else:
                    line("%s\n%s\n" % (subsection, "#" * len(subsection)))
                    line()
                    for docline in dedent(docstring).splitlines():
                        if docline.strip() == "":
                            # Blank line.  Don't indent.
                            line()
                        else:
                            # Print documentation line, indented.
                            line(docline)
                line()
            else:
                line("%s\n%s\n" % (subsection, "#" * len(subsection)))
                line()

    line()
    line()
    line(generate_power_types_doc())
    line()
    line()
    line(generate_pod_types_doc())

    return output.getvalue()