File: render.py

package info (click to toggle)
python-pdoc 16.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,080 kB
  • sloc: python: 5,260; javascript: 1,156; makefile: 18; sh: 3
file content (199 lines) | stat: -rw-r--r-- 7,081 bytes parent folder | download | duplicates (2)
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
from __future__ import annotations

import os
from pathlib import Path
import types
from typing import Literal
from typing import Mapping
from typing import cast
import warnings

import jinja2
from jinja2 import Environment
from jinja2 import FileSystemLoader

import pdoc.doc
import pdoc.docstrings
from pdoc.render_helpers import DefaultMacroExtension
from pdoc.render_helpers import defuse_unsafe_reprs
from pdoc.render_helpers import edit_url
from pdoc.render_helpers import format_signature
from pdoc.render_helpers import highlight
from pdoc.render_helpers import link
from pdoc.render_helpers import linkify
from pdoc.render_helpers import minify_css
from pdoc.render_helpers import root_module_name
from pdoc.render_helpers import to_html
from pdoc.render_helpers import to_markdown_with_context
from pdoc.search import make_index
from pdoc.search import precompile_index


def configure(
    *,
    docformat: Literal[
        "markdown", "google", "numpy", "restructuredtext"  # noqa: F821
    ] = "restructuredtext",
    include_undocumented: bool = True,
    edit_url_map: Mapping[str, str] | None = None,
    favicon: str | None = None,
    footer_text: str = "",
    logo: str | None = None,
    logo_link: str | None = None,
    math: bool = False,
    mermaid: bool = False,
    search: bool = True,
    show_source: bool = True,
    template_directory: Path | None = None,
):
    """
    Configure the rendering output.

    - `docformat` is the docstring flavor in use.
      pdoc prefers plain Markdown (the default), but also supports other formats.
    - `include_undocumented` controls whether members without a docstring are included in the output.
    - `edit_url_map` is a mapping from module names to URL prefixes. For example,

        ```json
        {"pdoc": "https://github.com/mitmproxy/pdoc/blob/main/pdoc/"}
        ```

      renders the "Edit on GitHub" button on this page. The URL prefix can be modified to pin a particular version.
    - `favicon` is an optional path/URL for a favicon image
    - `footer_text` is additional text that should appear in the navigation footer.
    - `logo` is an optional URL to the project's logo image
    - `logo_link` is an optional URL the logo should point to
    - `math` enables math rendering by including MathJax into the rendered documentation.
    - `mermaid` enables diagram rendering by including Mermaid.js into the rendered documentation.
    - `search` controls whether search functionality is enabled and a search index is built.
    - `show_source` controls whether a "View Source" button should be included in the output.
    - `template_directory` can be used to set an additional (preferred) directory
      for templates. You can find an example in the main documentation of `pdoc`
      or in `examples/custom-template`.
    """
    searchpath = _default_searchpath
    if template_directory:
        searchpath = [template_directory] + searchpath
    env.loader = FileSystemLoader(searchpath)

    env.globals["docformat"] = docformat
    env.globals["include_undocumented"] = include_undocumented
    env.globals["edit_url_map"] = edit_url_map or {}
    env.globals["math"] = math
    env.globals["mermaid"] = mermaid
    env.globals["show_source"] = show_source
    env.globals["favicon"] = favicon
    env.globals["logo"] = logo
    env.globals["logo_link"] = logo_link
    env.globals["footer_text"] = footer_text
    env.globals["search"] = search


@defuse_unsafe_reprs()
def html_module(
    module: pdoc.doc.Module,
    all_modules: Mapping[str, pdoc.doc.Module],
    mtime: str | None = None,
) -> str:
    """
    Renders the documentation for a `pdoc.doc.Module`.

    - `all_modules` contains all modules that are rendered in this invocation.
      This is used to determine which identifiers should be linked and which should not.
    - If `mtime` is given, include additional JavaScript on the page for live-reloading.
      This is only passed by `pdoc.web`.
    """
    return env.get_template("module.html.jinja2").render(
        module=module,
        all_modules=all_modules,
        root_module_name=root_module_name(all_modules),
        edit_url=edit_url(
            module.modulename,
            module.is_package,
            cast(Mapping[str, str], env.globals["edit_url_map"]),
        ),
        mtime=mtime,
    )


@defuse_unsafe_reprs()
def html_index(all_modules: Mapping[str, pdoc.doc.Module]) -> str:
    """Renders the module index."""
    return env.get_template("index.html.jinja2").render(
        all_modules=all_modules,
        root_module_name=root_module_name(all_modules),
    )


@defuse_unsafe_reprs()
def html_error(error: str, details: str = "") -> str:
    """Renders an error message."""
    return env.get_template("error.html.jinja2").render(
        error=error,
        details=details,
    )


@defuse_unsafe_reprs()
def search_index(all_modules: Mapping[str, pdoc.doc.Module]) -> str:
    """Renders the Elasticlunr.js search index."""
    if not env.globals["search"]:
        return ""
    # This is a rather terrible hack to determine if a given object is public and should be included in the index.
    module_template: jinja2.Template = env.get_template("module.html.jinja2")
    ctx: jinja2.runtime.Context = module_template.new_context(
        {"module": pdoc.doc.Module(types.ModuleType("")), "all_modules": all_modules}
    )
    for _ in module_template.root_render_func(ctx):  # type: ignore
        pass

    def is_public(x: pdoc.doc.Doc) -> bool:
        return bool(ctx["is_public"](x).strip())

    index = make_index(
        all_modules,
        is_public,
        cast(str, env.globals["docformat"]),
    )

    compile_js = Path(env.get_template("build-search-index.js").filename)  # type: ignore
    return env.get_template("search.js.jinja2").render(
        search_index=precompile_index(index, compile_js)
    )


@defuse_unsafe_reprs()
def repr_module(module: pdoc.doc.Module) -> str:
    """Renders `repr(pdoc.doc.Module)`, primarily used for tests and debugging."""
    return repr(module)


_default_searchpath = [
    Path(os.environ.get("XDG_CONFIG_HOME", "~/.config")).expanduser() / "pdoc",
    Path(__file__).parent / "templates",
    Path(__file__).parent / "templates" / "default",
    Path(__file__).parent / "templates" / "deprecated",
]

env = Environment(
    loader=FileSystemLoader(_default_searchpath),
    extensions=["jinja2.ext.loopcontrols", DefaultMacroExtension],
    autoescape=True,
    trim_blocks=True,
    lstrip_blocks=True,
)
"""
The Jinja2 environment used to render all templates.
You can modify this object to add custom filters and globals.
"""
env.filters["to_markdown"] = to_markdown_with_context
env.filters["to_html"] = to_html
env.filters["highlight"] = highlight
env.filters["format_signature"] = format_signature
env.filters["linkify"] = linkify
env.filters["link"] = link
env.filters["minify_css"] = minify_css
env.globals["__version__"] = pdoc.__version__
env.globals["env"] = os.environ
env.globals["warn"] = warnings.warn
configure()  # add default globals