summaryrefslogtreecommitdiff
path: root/sphinx/transforms/post_transforms/compat.py
blob: 9a03ff6b534489826e5a26dfa803d67b2321daad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# -*- coding: utf-8 -*-
"""
    sphinx.transforms.post_transforms.compat
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Post transforms for compatibility

    :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
    :license: BSD, see LICENSE for details.
"""

import warnings

from docutils import nodes
from docutils.writers.docutils_xml import XMLTranslator

from sphinx.addnodes import math_block, displaymath
from sphinx.deprecation import RemovedInSphinx30Warning
from sphinx.transforms import SphinxTransform
from sphinx.util import logging

if False:
    # For type annotation
    from typing import Any, Callable, Dict, Iterable, List, Tuple  # NOQA
    from docutils.parsers.rst.states import Inliner  # NOQA
    from docutils.writers.html4css1 import Writer  # NOQA
    from sphinx.application import Sphinx  # NOQA
    from sphinx.builders import Builder  # NOQA
    from sphinx.environment import BuildEnvironment  # NOQA

logger = logging.getLogger(__name__)


class MathNodeMigrator(SphinxTransform):
    """Migrate a math node to docutils'.

    For a long time, Sphinx uses an original node for math. Since 1.8,
    Sphinx starts to use a math node of docutils'.  This transform converts
    old and new nodes to keep compatibility.
    """
    default_priority = 999

    def apply(self):
        # type: () -> None
        for node in self.document.traverse(nodes.math):
            # case: old styled ``math`` node generated by old extensions
            if len(node) == 0:
                warnings.warn("math node for Sphinx was replaced by docutils'. "
                              "Please use ``docutils.nodes.math`` instead.",
                              RemovedInSphinx30Warning)
                equation = node['latex']
                node += nodes.Text(equation, equation)

        translator = self.app.builder.get_translator_class()
        if hasattr(translator, 'visit_displaymath') and translator != XMLTranslator:
            # case: old translators which does not support ``math_block`` node
            warnings.warn("Translator for %s does not support math_block node'. "
                          "Please update your extension." % translator,
                          RemovedInSphinx30Warning)
            for node in self.document.traverse(math_block):
                alt = displaymath(latex=node.astext(),
                                  number=node.get('number'),
                                  label=node.get('label'),
                                  nowrap=node.get('nowrap'),
                                  docname=node.get('docname'))
                node.replace(alt)
        else:
            # case: old styled ``displaymath`` node generated by old extensions
            for node in self.document.traverse(math_block):
                if len(node) == 0:
                    warnings.warn("math node for Sphinx was replaced by docutils'. "
                                  "Please use ``docutils.nodes.math_block`` instead.",
                                  RemovedInSphinx30Warning)
                    if isinstance(node, displaymath):
                        newnode = nodes.math_block('', node['latex'], **node.attributes)
                        node.replace_self(newnode)
                    else:
                        latex = node['latex']
                        node += nodes.Text(latex, latex)


def setup(app):
    # type: (Sphinx) -> Dict[unicode, Any]
    app.add_post_transform(MathNodeMigrator)

    return {
        'version': 'builtin',
        'parallel_read_safe': True,
        'parallel_write_safe': True,
    }