From bcd4c3f27d5bcf701337ac7c74c042d90792bdc3 Mon Sep 17 00:00:00 2001 From: Tai Lee Date: Tue, 18 Jun 2013 10:10:21 +1000 Subject: [PATCH] Fixed #6681 -- Don't break docutils when rendering reStructuredText. Don't set a global default interpreted role function for reStructuredText. Instead, use the `default-role` directive to change the default only within the `parse_rst()` function. Thanks Malcolm Tredinnick for the report. --- django/contrib/admindocs/utils.py | 16 ++++++++--- tests/admin_docs/tests.py | 44 +++++++++++++++++++++++++++++++ tests/admin_docs/urls.py | 3 ++- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/django/contrib/admindocs/utils.py b/django/contrib/admindocs/utils.py index c97d588c7d..f836253e71 100644 --- a/django/contrib/admindocs/utils.py +++ b/django/contrib/admindocs/utils.py @@ -67,9 +67,18 @@ def parse_rst(text, default_reference_context, thing_being_parsed=None): } if thing_being_parsed: thing_being_parsed = force_bytes("<%s>" % thing_being_parsed) - parts = docutils.core.publish_parts(text, source_path=thing_being_parsed, - destination_path=None, writer_name='html', - settings_overrides=overrides) + # Wrap ``text`` in some reST that sets the default role to ``cmsreference``, + # then restores it. + source = """ +.. default-role:: cmsreference + +%s + +.. default-role:: +""" + parts = docutils.core.publish_parts(source % text, + source_path=thing_being_parsed, destination_path=None, + writer_name='html', settings_overrides=overrides) return mark_safe(parts['fragment']) # @@ -100,7 +109,6 @@ def default_reference_role(name, rawtext, text, lineno, inliner, options=None, c if docutils_is_available: docutils.parsers.rst.roles.register_canonical_role('cmsreference', default_reference_role) - docutils.parsers.rst.roles.DEFAULT_INTERPRETED_ROLE = 'cmsreference' for name, urlbase in ROLES.items(): create_reference_role(name, urlbase) diff --git a/tests/admin_docs/tests.py b/tests/admin_docs/tests.py index aeb527c7b9..3ae3a42843 100644 --- a/tests/admin_docs/tests.py +++ b/tests/admin_docs/tests.py @@ -1,3 +1,11 @@ +import unittest + +try: + import docutils +except ImportError: + docutils = None + +from django.contrib.admindocs import utils from django.contrib.auth.models import User from django.test import TestCase from django.test.utils import override_settings @@ -43,3 +51,39 @@ class XViewMiddlewareTest(TestCase): user.save() response = self.client.head('/xview/class/') self.assertFalse('X-View' in response) + + +@unittest.skipUnless(docutils, "no docutils installed.") +class DefaultRoleTest(TestCase): + urls = 'admin_docs.urls' + + def test_parse_rst(self): + """ + Tests that ``django.contrib.admindocs.utils.parse_rst`` uses + ``cmsreference`` as the default role. + """ + markup = ('

' + 'title

\n') + self.assertEqual(utils.parse_rst('`title`', 'model'), + markup % 'models/title/') + self.assertEqual(utils.parse_rst('`title`', 'view'), + markup % 'views/title/') + self.assertEqual(utils.parse_rst('`title`', 'template'), + markup % 'templates/title/') + self.assertEqual(utils.parse_rst('`title`', 'filter'), + markup % 'filters/#title') + self.assertEqual(utils.parse_rst('`title`', 'tag'), + markup % 'tags/#title') + + def test_publish_parts(self): + """ + Tests that Django hasn't broken the default role for interpreted text + when ``publish_parts`` is used directly, by setting it to + ``cmsreference``. See #6681. + """ + self.assertNotEqual(docutils.parsers.rst.roles.DEFAULT_INTERPRETED_ROLE, + 'cmsreference') + source = 'reST, `interpreted text`, default role.' + markup = '

reST, interpreted text, default role.

\n' + parts = docutils.core.publish_parts(source=source, writer_name="html4css1") + self.assertEqual(parts['fragment'], markup) diff --git a/tests/admin_docs/urls.py b/tests/admin_docs/urls.py index 914b4836e0..08eaf03632 100644 --- a/tests/admin_docs/urls.py +++ b/tests/admin_docs/urls.py @@ -1,8 +1,9 @@ -from django.conf.urls import patterns +from django.conf.urls import include, patterns from . import views urlpatterns = patterns('', + (r'^admindocs/', include('django.contrib.admindocs.urls')), (r'^xview/func/$', views.xview_dec(views.xview)), (r'^xview/class/$', views.xview_dec(views.XViewClass.as_view())), )