From 076dd62385d9bb63e74e20d31e490e9a48d952f9 Mon Sep 17 00:00:00 2001 From: Reinout van Rees Date: Thu, 20 Dec 2012 17:36:05 +0100 Subject: [PATCH] Rendering description with restructuredtext. If markdown is present, it takes precedence. Restructured text is only applied if docutils is available. --- rest_framework/compat.py | 14 ++++++++++++++ rest_framework/tests/description.py | 19 +++++++++++++++---- rest_framework/views.py | 4 +++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/rest_framework/compat.py b/rest_framework/compat.py index 86952fb8d..46a062326 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -377,6 +377,20 @@ try: except ImportError: apply_markdown = None +# Restructured text (docutils) is optional +try: + import docutils.core + + def apply_restructuredtext(text): + parts = docutils.core.publish_parts( + text, + writer_name='html', + settings_overrides={'initial_header_level': 2, + 'doctitle_xform': False}) + return parts['html_body'] + +except ImportError: + apply_restructuredtext = None # Yaml is optional try: diff --git a/rest_framework/tests/description.py b/rest_framework/tests/description.py index d958b8405..2c25dee10 100644 --- a/rest_framework/tests/description.py +++ b/rest_framework/tests/description.py @@ -1,6 +1,9 @@ +import unittest + from django.test import TestCase from rest_framework.views import APIView from rest_framework.compat import apply_markdown +from rest_framework.compat import apply_restructuredtext # We check that docstrings get nicely un-indented. DESCRIPTION = """an example docstring @@ -105,9 +108,17 @@ class TestViewNamesAndDescriptions(TestCase): pass self.assertEquals(MockView().get_description(), '') + @unittest.skipUnless(apply_markdown, 'markdown not installed') def test_markdown(self): """Ensure markdown to HTML works as expected""" - if apply_markdown: - gte_21_match = apply_markdown(DESCRIPTION) == MARKED_DOWN_gte_21 - lt_21_match = apply_markdown(DESCRIPTION) == MARKED_DOWN_lt_21 - self.assertTrue(gte_21_match or lt_21_match) + gte_21_match = apply_markdown(DESCRIPTION) == MARKED_DOWN_gte_21 + lt_21_match = apply_markdown(DESCRIPTION) == MARKED_DOWN_lt_21 + self.assertTrue(gte_21_match or lt_21_match) + + @unittest.skipUnless(apply_restructuredtext, 'docutils not installed') + def test_restructuredtext(self): + """Ensure restructuredtext to HTML works as expected.""" + # The output isn't tested verbatim because of small rendering changes + # between docutils versions. + self.assertTrue('

another header

' + in apply_restructuredtext(DESCRIPTION)) diff --git a/rest_framework/views.py b/rest_framework/views.py index 10bdd5a53..391512bbe 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -9,7 +9,7 @@ from django.utils.html import escape from django.utils.safestring import mark_safe from django.views.decorators.csrf import csrf_exempt from rest_framework import status, exceptions -from rest_framework.compat import View, apply_markdown +from rest_framework.compat import View, apply_markdown, apply_restructuredtext from rest_framework.response import Response from rest_framework.request import Request from rest_framework.settings import api_settings @@ -119,6 +119,8 @@ class APIView(View): # TODO: deprecate? if apply_markdown: description = apply_markdown(description) + elif apply_restructuredtext: + description = apply_restructuredtext(description) else: description = escape(description).replace('\n', '
') return mark_safe(description)