-
Notifications
You must be signed in to change notification settings - Fork 229
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The renderer (and associated functions) is temporarily included in here as it gets tested. Later on, it will be upstreamed to quartodoc.
- Loading branch information
Showing
5 changed files
with
737 additions
and
137 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,154 +1,36 @@ | ||
from __future__ import annotations | ||
|
||
import html | ||
import typing | ||
from pathlib import Path | ||
from textwrap import indent | ||
|
||
from _renderers.numpydoc import NumpyDocRenderer | ||
from _renderers.utils import shortcode | ||
from griffe import dataclasses as dc | ||
from griffe import expressions as expr | ||
from griffe.docstrings import dataclasses as ds | ||
from numpydoc.docscrape import NumpyDocString | ||
from plum import dispatch | ||
from quartodoc import MdRenderer | ||
from quartodoc import ast as qast | ||
from quartodoc.layout import DocClass | ||
from quartodoc.renderers.base import convert_rst_link_to_md, sanitize | ||
from tabulate import tabulate | ||
|
||
# from quartodoc.renderers import NumpyDocRenderer | ||
from quartodoc.pandoc.blocks import Blocks, Header | ||
|
||
DOC_DIR = Path(__file__).parent | ||
EXAMPLES_DIR = DOC_DIR / "plotnine_examples" | ||
|
||
DOCSTRING_TPL = """\ | ||
{rendered} | ||
Examples | ||
-------- | ||
{examples} | ||
""" | ||
|
||
INDENT = " " * 4 | ||
PARAM_TPL = """\ | ||
<code class="python">{name}{annotation}{default}</code> | ||
:{indented_description} | ||
""" | ||
|
||
# NOTE: https://github.com/mkdocstrings/griffe/pull/194 | ||
# will break this module. | ||
|
||
|
||
class Renderer(MdRenderer): | ||
class Renderer(NumpyDocRenderer): | ||
style = "plotnine" | ||
|
||
@dispatch | ||
def render(self, el: DocClass): # type: ignore | ||
return super().render(el) | ||
|
||
@dispatch | ||
def render(self, el: dc.Object | dc.Alias): # type: ignore # noqa: F811 | ||
rendered = super().render(el) | ||
|
||
converted = convert_rst_link_to_md(rendered) | ||
|
||
example_path = EXAMPLES_DIR / "examples" / (el.name + ".ipynb") | ||
if example_path.exists(): | ||
rel_path = Path("..") / example_path.relative_to(DOC_DIR) | ||
example = "{{< embed" f" {rel_path} " "echo=true >}}" | ||
return DOCSTRING_TPL.format(rendered=converted, examples=example) | ||
|
||
return converted | ||
|
||
@dispatch | ||
def render( # type: ignore | ||
self, el: qast.DocstringSectionSeeAlso # noqa: F811 | ||
): | ||
lines = el.value.split("\n") | ||
|
||
# each entry in result has form: | ||
# ([('func1', '<directive>), ...], <description>) | ||
parsed = NumpyDocString("")._parse_see_also(lines) | ||
|
||
result = [] | ||
for funcs, description in parsed: | ||
links = [f"[{name}](`{name}`)" for name, role in funcs] | ||
|
||
str_links = ", ".join(links) | ||
|
||
if description: | ||
str_description = "<br>".join(description) | ||
result.append(f"{str_links}: {str_description}") | ||
else: | ||
result.append(str_links) | ||
|
||
return "* " + "\n* ".join(result) | ||
|
||
@dispatch | ||
def render_annotation(self, el: None): # type: ignore | ||
return "" | ||
|
||
@dispatch | ||
def render_annotation(self, el: expr.Expression): # type: ignore | ||
# an expression is essentially a list[expr.Name | str] | ||
# e.g. Optional[TagList] | ||
# -> [Name(source="Optional", ...), "[", Name(...), "]"] | ||
|
||
return "".join([self.render_annotation(a) for a in el]) | ||
|
||
@dispatch | ||
def render_annotation(self, el: expr.Name): # type: ignore | ||
# e.g. Name(source="Optional", full="typing.Optional") | ||
return f"[{el.source}](`{el.full}`)" | ||
|
||
@dispatch | ||
def render_annotation(self, el: str): | ||
""" | ||
Override base class so that no escaping is done | ||
def render(self, el: dc.Object | dc.Alias): | ||
""" | ||
return sanitize(el) | ||
|
||
@dispatch | ||
def summarize(self, el: dc.Object | dc.Alias): | ||
result = super().summarize(el) | ||
return html.escape(result) | ||
|
||
@dispatch | ||
def signature(self, el: dc.Object | dc.Alias): | ||
# Informative geom and stat signatures are generated dynamically and | ||
# are part of the docstring. quartoc has empty signatures because it | ||
# (or griffe) cannot pickup those of the base class. | ||
skip = el.name.startswith("geom_") or el.name.startswith("stat_") | ||
if skip: | ||
return "" | ||
return super().signature(el) # type: ignore | ||
|
||
# parameters ---- | ||
@dispatch | ||
def render(self, el: ds.DocstringParameter) -> str: # type: ignore # noqa: F811 | ||
""" | ||
Return parameter docstring as a definition term & description | ||
output-format: quarto/pandoc | ||
""" | ||
annotation = self.render_annotation(el.annotation) # type: ignore | ||
kwargs = { | ||
"name": el.name, | ||
"annotation": f": {annotation}" if annotation else "", | ||
"default": f" = {el.default}" if el.default else "", | ||
"indented_description": indent(el.description, INDENT), | ||
} | ||
return PARAM_TPL.format(**kwargs) | ||
|
||
@dispatch | ||
def render(self, el: ds.DocstringSectionParameters) -> str: | ||
""" | ||
Return parameters docstring as a definition list | ||
output-format: quarto/pandoc | ||
Override method to embed examples notebook after the docstring | ||
""" | ||
definitions = [ | ||
self.render(ds_parameter) # type: ignore | ||
for ds_parameter in el.value | ||
] | ||
return "\n".join(definitions) | ||
docstring_qmd = super().render(el) | ||
notebook = EXAMPLES_DIR / "examples" / f"{el.name}.ipynb" | ||
if not notebook.exists(): | ||
return docstring_qmd | ||
|
||
# path from the references directory where the qmd files | ||
# are placed | ||
relpath = Path("..") / notebook.relative_to(DOC_DIR) | ||
embed_notebook = shortcode("embed", f"{relpath}", echo="true") | ||
header = Header(self.header_level + 1, "Examples") | ||
return str(Blocks([docstring_qmd, header, embed_notebook])) |
Empty file.
Oops, something went wrong.