예제 #1
0
    def test_resource_uri_in_docs_matches_handlers_idea_of_resource_uri(self):
        # Sigh. Piston asks handlers for resource_uri information, but also
        # makes use of Django's URL patterns to figure out resource_uri
        # templates for the documentation. Here we check that they match up.
        formatter = string.Formatter()

        def gen_handlers(resource):
            if resource.anonymous is not None:
                yield resource.anonymous
            if resource.handler is not None:
                yield resource.handler

        handlers = chain.from_iterable(
            map(gen_handlers, find_api_resources(urlconf))
        )

        mismatches = []

        for handler in map(type, handlers):
            if hasattr(handler, "resource_uri"):
                resource_uri_params = handler.resource_uri()[1]
                resource_uri_template = generate_doc(
                    handler
                ).resource_uri_template

                fields_expected = tuple(resource_uri_params)
                fields_observed = tuple(
                    fname
                    for _, fname, _, _ in formatter.parse(
                        resource_uri_template
                    )
                    if fname is not None
                )

                if fields_observed != fields_expected:
                    mismatches.append(
                        (handler, fields_expected, fields_observed)
                    )

        if len(mismatches) != 0:
            messages = (
                "{handler.__module__}.{handler.__name__} has mismatched "
                "fields:\n  expected: {expected}\n  observed: {observed}"
                "".format(
                    handler=handler,
                    expected=" ".join(expected),
                    observed=" ".join(observed),
                )
                for handler, expected, observed in mismatches
            )
            messages = chain(
                messages,
                [
                    "Amend the URL patterns for these handlers/resources so that "
                    "the observed fields match what is expected."
                ],
            )
            self.fail("\n--\n".join(messages))
예제 #2
0
파일: test_doc.py 프로젝트: ocni-dtu/maas
 def test_urlpatterns_with_resource(self):
     # Resources for handlers with resource_uri attributes are discovered
     # in a urlconf module and returned. The type of resource_uri is not
     # checked; it must only be present and not None.
     handler = type("\\m/", (BaseHandler,), {"resource_uri": True})
     resource = Resource(handler)
     module = self.make_module()
     module.urlpatterns = [url("^metal", resource)]
     self.assertSetEqual({resource}, find_api_resources(module))
예제 #3
0
파일: test_doc.py 프로젝트: ocni-dtu/maas
 def test_nested_urlpatterns_with_handler(self):
     # Resources are found in nested urlconfs.
     handler = type("\\m/", (BaseHandler,), {"resource_uri": True})
     resource = Resource(handler)
     module = self.make_module()
     submodule = self.make_module()
     submodule.urlpatterns = [url("^metal", resource)]
     module.urlpatterns = [url("^genre/", include(submodule))]
     self.assertSetEqual({resource}, find_api_resources(module))
예제 #4
0
파일: test_doc.py 프로젝트: ocni-dtu/maas
 def test_urlpatterns_with_resource_hidden(self):
     # Resources for handlers with resource_uri attributes are discovered
     # in a urlconf module and returned, unless hidden = True.
     handler = type(
         "\\m/", (BaseHandler,), {"resource_uri": True, "hidden": True}
     )
     resource = Resource(handler)
     module = self.make_module()
     module.urlpatterns = [url("^metal", resource)]
     self.assertSetEqual(set(), find_api_resources(module))
예제 #5
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))
예제 #6
0
파일: test_doc.py 프로젝트: ocni-dtu/maas
 def test_urlpatterns_with_resource_for_incomplete_handler(self):
     # Resources for handlers that don't specify resource_uri are ignored.
     module = self.make_module()
     module.urlpatterns = [url("^foo", BaseHandler)]
     self.assertSetEqual(set(), find_api_resources(module))
예제 #7
0
파일: test_doc.py 프로젝트: ocni-dtu/maas
 def test_urlpatterns_empty(self):
     # No resources are found in empty modules.
     module = self.make_module()
     module.urlpatterns = []
     self.assertSetEqual(set(), find_api_resources(module))
예제 #8
0
파일: test_doc.py 프로젝트: ocni-dtu/maas
    def test_smoke(self):
        # Resources are found for the MAAS API.
        from maasserver import urls_api as urlconf

        self.assertNotEqual(set(), find_api_resources(urlconf))
예제 #9
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()
예제 #10
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()