Skip to content

Commit

Permalink
feat: Support latest Griffe, add auto-summaries and cross-references
Browse files Browse the repository at this point in the history
  • Loading branch information
pawamoy committed Jan 3, 2024
1 parent 6005423 commit e744fac
Show file tree
Hide file tree
Showing 32 changed files with 813 additions and 250 deletions.
4 changes: 4 additions & 0 deletions docs/insiders/changelog.md
Expand Up @@ -2,6 +2,10 @@

## griffe2md Insiders

### 1.2.0 <small>September 05, 2023</small> { id="1.2.0" }

- Support latest Griffe, add auto-summaries and cross-references

### 1.0.1 <small>May 12, 2023</small> { id="1.0.1" }

- Add missing jinja2 dependency
Expand Down
118 changes: 103 additions & 15 deletions src/griffe2md/main.py
Expand Up @@ -5,7 +5,7 @@
import re
import sys
from pathlib import Path
from typing import IO
from typing import IO, TYPE_CHECKING

import mdformat
from griffe.docstrings import Parser
Expand All @@ -14,6 +14,9 @@

from griffe2md import rendering

if TYPE_CHECKING:
from griffe import Object


def _output(text: str, to: IO | str | None = None) -> None:
if isinstance(to, str):
Expand All @@ -25,40 +28,125 @@ def _output(text: str, to: IO | str | None = None) -> None:
to.write(text)


def render_package_docs(package: str, config: dict | None = None) -> str:
"""Render docs for a given package.
def prepare_context(obj: Object, config: dict | None = None) -> dict:
"""Prepare Jinja context.
Parameters:
package: The package to render docs for.
config: The rendering configuration.
obj: A Griffe object.
config: The configuration options.
Returns:
Markdown.
The Jinja context.
"""
config = config or dict(rendering.default_config)
if config["filters"]:
config["filters"] = [(re.compile(filtr.lstrip("!")), filtr.startswith("!")) for filtr in config["filters"]]
parser = config["docstring_style"] and Parser(config["docstring_style"])
loader = GriffeLoader(docstring_parser=parser)
module = loader.load_module(package)
loader.resolve_aliases()
env = Environment(

heading_level = config["heading_level"]
try:
config["members_order"] = rendering.Order(config["members_order"])
except ValueError as error:
choices = "', '".join(item.value for item in rendering.Order)
raise ValueError(
f"Unknown members_order '{config['members_order']}', choose between '{choices}'.",
) from error

summary = config["summary"]
if summary is True:
config["summary"] = {
"attributes": True,
"functions": True,
"classes": True,
"modules": True,
}
elif summary is False:
config["summary"] = {
"attributes": False,
"functions": False,
"classes": False,
"modules": False,
}
else:
config["summary"] = {
"attributes": summary.get("attributes", False),
"functions": summary.get("functions", False),
"classes": summary.get("classes", False),
"modules": summary.get("modules", False),
}

return {
"config": config,
obj.kind.value: obj,
"heading_level": heading_level,
"root": True,
}


def prepare_env(env: Environment | None = None) -> Environment:
"""Prepare Jinja environment.
Parameters:
env: A Jinja environment.
Returns:
The Jinja environment.
"""
env = env or Environment(
autoescape=False, # noqa: S701
loader=FileSystemLoader([Path(__file__).parent / "templates"]),
auto_reload=False,
)
env.filters["any"] = rendering.do_any
env.filters["filter_objects"] = rendering.do_filter_objects
env.filters["heading"] = rendering.do_heading
env.filters["order_members"] = rendering.do_order_members
env.filters["as_attributes_section"] = rendering.do_as_attributes_section
env.filters["as_classes_section"] = rendering.do_as_classes_section
env.filters["as_functions_section"] = rendering.do_as_functions_section
env.filters["as_modules_section"] = rendering.do_as_modules_section
env.filters["filter_objects"] = rendering.do_filter_objects
env.filters["format_code"] = rendering.do_format_code
env.filters["format_signature"] = rendering.do_format_signature
env.filters["format_attribute"] = rendering.do_format_attribute
env.filters["order_members"] = rendering.do_order_members
env.filters["split_path"] = rendering.do_split_path
env.filters["stash_crossref"] = lambda ref, length: ref

rendered = env.get_template("module.md").render(module=module, root=True, config=config, heading_level=2)
return env


def render_object_docs(obj: Object, config: dict | None = None) -> str:
"""Render docs for a given object.
Parameters:
obj: The Griffe object to render docs for.
config: The rendering configuration.
Returns:
Markdown.
"""
env = prepare_env()
context = prepare_context(obj, config)
rendered = env.get_template(f"{obj.kind.value}.md.jinja").render(**context)
return mdformat.text(rendered)


def render_package_docs(package: str, config: dict | None = None) -> str:
"""Render docs for a given package.
Parameters:
package: The package (name) to render docs for.
config: The rendering configuration.
Returns:
Markdown.
"""
config = config or dict(rendering.default_config)
parser = config["docstring_style"] and Parser(config["docstring_style"])
loader = GriffeLoader(docstring_parser=parser)
module = loader.load_module(package)
loader.resolve_aliases()
return render_object_docs(module, config)


def write_package_docs(package: str, config: dict | None = None, output: IO | str | None = None) -> None:
"""Write docs for a given package to a file or stdout.
Expand Down

0 comments on commit e744fac

Please sign in to comment.