admindocs modifies docutils behavior on import

Recently, I’ve run into an issue that our test suite failed in some cases, apparently it was caused by tests ordering. If the API tests were executed before others, we got a weird error on parsing some of the reStructuredText, most notably if it contained something like :tag:`foo` :

Traceback (most recent call last):
  File "/home/nijel/weblate/weblate/test.py", line 14, in <module>
    parser.parse(":tag:`foo`", document)
  File "/home/nijel/weblate/weblate/.venv/lib/python3.11/site-packages/docutils/parsers/rst/__init__.py", line 184, in parse
    self.statemachine.run(inputlines, document, inliner=self.inliner)
  File "/home/nijel/weblate/weblate/.venv/lib/python3.11/site-packages/docutils/parsers/rst/states.py", line 169, in run
    results = StateMachineWS.run(self, input_lines, input_offset,
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/nijel/weblate/weblate/.venv/lib/python3.11/site-packages/docutils/statemachine.py", line 239, in run
    result = state.eof(context)
             ^^^^^^^^^^^^^^^^^^
  File "/home/nijel/weblate/weblate/.venv/lib/python3.11/site-packages/docutils/parsers/rst/states.py", line 2727, in eof
    self.blank(None, context, None)
  File "/home/nijel/weblate/weblate/.venv/lib/python3.11/site-packages/docutils/parsers/rst/states.py", line 2718, in blank
    paragraph, literalnext = self.paragraph(
                             ^^^^^^^^^^^^^^^
  File "/home/nijel/weblate/weblate/.venv/lib/python3.11/site-packages/docutils/parsers/rst/states.py", line 416, in paragraph
    textnodes, messages = self.inline_text(text, lineno)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/nijel/weblate/weblate/.venv/lib/python3.11/site-packages/docutils/parsers/rst/states.py", line 425, in inline_text
    nodes, messages = self.inliner.parse(text, lineno,
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/nijel/weblate/weblate/.venv/lib/python3.11/site-packages/docutils/parsers/rst/states.py", line 649, in parse
    before, inlines, remaining, sysmessages = method(self, match,
                                              ^^^^^^^^^^^^^^^^^^^
  File "/home/nijel/weblate/weblate/.venv/lib/python3.11/site-packages/docutils/parsers/rst/states.py", line 792, in interpreted_or_phrase_ref
    nodelist, messages = self.interpreted(rawsource, escaped, role,
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/nijel/weblate/weblate/.venv/lib/python3.11/site-packages/docutils/parsers/rst/states.py", line 889, in interpreted
    nodes, messages2 = role_fn(role, rawsource, text, lineno, self)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/nijel/weblate/weblate/.venv/lib/python3.11/site-packages/django/contrib/admindocs/utils.py", line 116, in _role
    inliner.document.settings.link_base,
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Values' object has no attribute 'link_base'

Digging deeper, this turned out to be the cause:

  1. We use django-rest-framework which imports simplify_regex from django.contrib.admindocs.views.
  2. This in turn imports django.contrib.admindocs.utils.
  3. This module does modify a global docutils parser in a way that it expects additional setting.

As an immediate workaround, we’ve added this setting to our docutils invocation to avoid the crash (weblate/weblate/checks/markup.py at 52ab91edd1ff2797da486ddac359688e7cc40744 · WeblateOrg/weblate · GitHub). This kind of works for us, as we are only interested in parsing reStructuredText and are rendering it at all.

Still, this is unfortunate that the side effects of importing django-rest-framework are there.

I’ve already reported this issue in several places, but it appears that this forum is the place to get additional feedback from the Django community on how to address this. I will post links to related issues in an additional post as I’m new user here can can only add two links in the post…

1 Like

The root cause being that the docutils only have a global directives registry and this is an issue known for years and apparently difficult to address:

https://sourceforge.net/p/docutils/feature-requests/38/

django-rest-framework issue:

Django ticket:

https://code.djangoproject.com/ticket/36124

The django-rest-framework maintainer come up with a proposal to limit impact of this by moving the regex helpers to a standalone module: