File: fancy_include.py

package info (click to toggle)
python-multipletau 0.3.3%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 380 kB
  • sloc: python: 1,557; makefile: 15
file content (104 lines) | stat: -rw-r--r-- 2,786 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
"""Include single scripts with doc string, code, and image

Use case
--------
There is an "examples" directory in the root of a repository,
e.g. 'include_doc_code_img_path = "../examples"' in conf.py
(default). An example is a file ("an_example.py") that consists
of a doc string at the beginning of the file, the example code,
and, optionally, an image file (png, jpg) ("an_example.png").


Configuration
-------------
In conf.py, set the parameter

   fancy_include_path = "../examples"

to wherever the included files reside.


Usage
-----
The directive

   .. fancy_include:: an_example.py

will display the doc string formatted with the first line as a
heading, a code block with line numbers, and the image file.
"""
import io
import os.path as op

from docutils.statemachine import ViewList
from docutils.parsers.rst import Directive
from sphinx.util.nodes import nested_parse_with_titles
from docutils import nodes


class IncludeDirective(Directive):
    required_arguments = 1
    optional_arguments = 0

    def run(self):
        path = self.state.document.settings.env.config.fancy_include_path
        full_path = op.join(path, self.arguments[0])

        with io.open(full_path, "r") as myfile:
            text = myfile.read()

        # add reference
        name = op.basename(full_path)[:-3]
        rst = [".. _example_{}:".format(name),
               "",
               ]

        # add docstring
        source = text.split('"""')
        doc = source[1].split("\n")
        doc.insert(1, "~" * len(doc[0]))  # make title heading

        code = source[2].split("\n")

        for line in doc:
            rst.append(line)

        # image
        for ext in [".png", ".jpg"]:
            image_path = full_path[:-3] + ext
            if op.exists(image_path):
                break
        else:
            image_path = ""
        if image_path:
            rst.append(".. figure:: {}".format(image_path))
            rst.append("")

        # download file
        rst.append(":download:`{}<{}>`".format(
            op.basename(full_path), full_path))

        # code
        rst.append("")
        rst.append(".. code-block:: python")
        rst.append("   :linenos:")
        rst.append("")
        for line in code:
            rst.append("   {}".format(line))
        rst.append("")

        vl = ViewList(rst, "fakefile.rst")
        # Create a node.
        node = nodes.section()
        node.document = self.state.document
        # Parse the rst.
        nested_parse_with_titles(self.state, vl, node)
        return node.children


def setup(app):
    app.add_config_value('fancy_include_path', "examples", 'html')

    app.add_directive('fancy_include', IncludeDirective)

    return {'version': '0.1'}   # identifies the version of our extension