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
|