Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

nickfrez / api-browser   python

Repository URL to install this package:

/ api_browser / renderers.py

# -*- coding: utf-8 -*-
"""
###################################################
Django Rest Framework Renderers for the API Browser
###################################################

Renderers and utilities for rendering the API Browser.

"""

from __future__ import print_function

from django.utils import safestring

# from rest_framework import status
from rest_framework import renderers as drf_renderers

from . import config
from . import formatting
from . import highlight


def get_view_name(view_cls, suffix=None):
    """Return the display name for an APIView.

    Converts camelcase to space-separated and replaces underscores with spaces.

    .. NOTE:: This name is used in the browsable API, and in OPTIONS responses.

    Parameters
    ----------
    view_cls
        The view class to get the name for.
    suffix: str
        DEPRECATED?: A suffix to add to the end of the generated name.
        ``get_view_name`` doesn't seem to ever be called with a suffix
        argument in the Django Rest Framework code.

    Returns
    -------
    str
        The display name for the view.

    """
    name = view_cls.__name__
    if name.endswith('View') and name != 'View':
        name = name[:-4]
    if name.endswith('ViewSet') and name != 'ViewSet':
        name = name[:-7]
    name = formatting.camelcase_to_space_separated(name)
    name = ' '.join(name.split('_'))
    if suffix:
        name += ' ' + suffix

    return name


def get_view_description(view_cls, html=False):
    """Return a textual description of the view parsed as ReStructured Text.

    .. NOTE:: This description is used in the browsable API, and in OPTIONS
              responses.

    """
    description = view_cls.__doc__ or ''
    description = formatting.dedent_docstring(description)
    if html:
        rendered = formatting.restructured_text_to_html(description)
        return safestring.mark_safe(rendered['body'])
    return description


class APIBrowserRenderer(drf_renderers.BrowsableAPIRenderer):
    """Render for the API Browser (text/html).

    The API Browser is similar in concept to the
    `Django Rest Framework Browsable API
    <http://www.django-rest-framework.org/topics/browsable-api/>`_.

    Differences:

    - API Browser uses Pygments for code highlighting and linkifying.
    - API Browser includes serializer metadata in the documentation.
    - API Browser parses docstrings with reStructuredText instead of Markdown.
    - (future) API Browser frontend is not based on Bootstrap.
    - (future) API Browser outputs metadata as JSON Schema.

    """

    media_type = 'text/html'
    format = config.get('FORMAT_SUFFIX')
    template = config.get('TEMPLATE')
    filter_template = config.get('FILTER_TEMPLATE')
    form_renderer_class = drf_renderers.HTMLFormRenderer
    charset = 'utf-8'

    def get_description(self, view, status_code):
        """Get the description for a view.

        The DRF version does not display documentation for unauthenticated
        users (if the endpoint requires login).  This version **does** display
        documentation.

        """
        if config.get('ALWAYS_DISPLAY_DOCUMENTATION'):
            return view.get_view_description(html=True)
        if status_code in (status.HTTP_401_UNAUTHORIZED,
                           status.HTTP_403_FORBIDDEN):
            return ''
        return view.get_view_description(html=True)

    def get_content(self, renderer, data,
                    accepted_media_type, renderer_context):
        """
        Get the content as if it had been rendered by the default
        non-documenting renderer.
        """
        if not renderer:
            return '[No renderers were found]'

        renderer_context['indent'] = 4
        content = renderer.render(data, accepted_media_type, renderer_context)

        render_style = getattr(renderer, 'render_style', 'text')
        assert render_style in ['text', 'binary'], 'Expected .render_style ' \
            '"text" or "binary", but got "%s"' % render_style
        if render_style == 'binary':
            return '[%d bytes of binary content]' % len(content)

        highlighted_content = highlight.highlight_and_hyperlink_json(content)

        return highlighted_content
        # return content

    def get_context(self, data, accepted_media_type, renderer_context):
        context = super(APIBrowserRenderer, self).get_context(
            data, accepted_media_type, renderer_context)

        view = renderer_context.get('view')
        request = renderer_context.get('request')
        metadata = view.metadata_class().determine_metadata(request, view)
        context['metadata_renders'] = metadata.get('renders')
        context['metadata_parses'] = metadata.get('parses')
        context['metadata_actions'] = metadata.get('actions')
        context['metadata'] = metadata

        context['pygments_css'] = highlight.get_styles('trac')
        return context