diff --git a/rest_framework/compat.py b/rest_framework/compat.py index 5508f6c05..950012c2e 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -383,6 +383,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..9a3086b7a 100644 --- a/rest_framework/tests/description.py +++ b/rest_framework/tests/description.py @@ -1,6 +1,7 @@ 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 @@ -111,3 +112,11 @@ class TestViewNamesAndDescriptions(TestCase): 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) + + def test_restructuredtext(self): + """Ensure restructuredtext to HTML works as expected.""" + if apply_restructuredtext: + # 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)