File: utils.py

package info (click to toggle)
sphinxcontrib-restbuilder 0.3-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 640 kB
  • sloc: python: 1,048; makefile: 20; sh: 6
file content (136 lines) | stat: -rw-r--r-- 4,281 bytes parent folder | download | duplicates (3)
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
from os.path import join
try:
    from itertools import zip_longest
except ImportError:
    # Python 2.7 support.
    from itertools import izip_longest as zip_longest
import io

import docutils
from docutils.frontend import OptionParser
from docutils.nodes import Text, Element, system_message
from docutils.parsers.rst import Parser
from docutils.utils import new_document
from docutils.core import publish_from_doctree
from sphinx.application import Sphinx

# sphinx.util.docutils requires Sphinx 1.5 and up.
try:
    from sphinx.util.docutils import docutils_namespace
except ImportError:
    # Attempt to support Sphinx 1.4 and thus the old Debian Stretch (oldstable)
    from copy import copy
    from contextlib import contextmanager
    from docutils.parsers.rst import directives, roles
    @contextmanager
    def docutils_namespace():
        """Create namespace for reST parsers."""
        try:
            _directives = copy(directives._directives)
            _roles = copy(roles._roles)
            yield
        finally:
            directives._directives = _directives
            roles._roles = _roles


def build_sphinx(src_dir, output_dir, files=None, config={}):
    doctrees_dir = join(output_dir, '.doctrees')

    filenames = []
    force_all = True

    default_config = {
        'extensions': ['sphinxcontrib.restbuilder'],
        'master_doc': 'index',
    }
    default_config.update(config)
    config = default_config

    if files:
        force_all = False
        filenames = [join(src_dir, file + '.rst') for file in files]
        config['master_doc'] = files[0]

    with docutils_namespace():
        app = Sphinx(
            src_dir,
            None,
            output_dir,
            doctrees_dir,
            'rst',
            confoverrides=config,
            verbosity=0,
        )

        app.build(force_all=force_all, filenames=filenames)


def assert_node_equal(output, expected):
    assert type(output) == type(expected)
    if isinstance(output, Text):
        output_text = output.replace('\r\n', ' ')
        output_text = output_text.replace('\n', ' ')
        expected_text = expected.replace('\r\n', ' ')
        expected_text = expected_text.replace('\n', ' ')
        assert output_text == expected_text
    elif isinstance(output, system_message):
        assert len(output.children) == len(expected.children)
        # Don't check specifics of system_messages (warnings)
        # E.g. the line number may be off
    elif isinstance(output, Element):
        assert len(output.children) == len(expected.children)
        assert output.attributes == expected.attributes
    else:
        raise AssertionError


def assert_doc_equal(output_doc, expected_doc):
    """
    Can be used to compare two documents, ignoring any whitespace changes
    """
    for output, expected in zip_longest(
        output_doc.traverse(include_self=False), expected_doc.traverse(include_self=False)
    ):
        assert_node_equal(output, expected)


def parse_doc(dir, file):
    parser = Parser()
    with io.open(join(dir, file + '.rst'), encoding='utf-8') as fh:
        doc = new_document(
            file,
            OptionParser(
                components=(docutils.parsers.rst.Parser,)
            ).get_default_values(),
        )
        parser.parse(
            fh.read(),
            doc,
        )
        return doc


def run_parse_test(src_dir, expected_dir, output_dir, subdir, files):
    src_dir = join(src_dir, subdir)
    expected_dir = join(expected_dir, subdir)
    output_dir = join(output_dir, subdir)
    build_sphinx(src_dir, output_dir, files)

    for file in files:
        output_doc = parse_doc(output_dir, file)
        expected_doc = parse_doc(expected_dir, file)
        try:
            assert_doc_equal(output_doc, expected_doc)
        except AssertionError:
            # output XML version of doctree for easier debugging
            with open(join(output_dir, file + '.output.xml'), 'wb') as fw:
                fw.write(publish_from_doctree(output_doc, writer_name='xml'))
            with open(join(output_dir, file + '.expected.xml'), 'wb') as fw:
                fw.write(publish_from_doctree(expected_doc, writer_name='xml'))
            raise



if __name__ == '__main__':
    pass