2023-06-12 17:13:09 -07:00

123 lines
3.5 KiB
Python
Executable File

# Released under the MIT License. See LICENSE for details.
#
"""Documentation generation functionality."""
from __future__ import annotations
import os
from dataclasses import dataclass
from pathlib import Path
from typing import TYPE_CHECKING
from efro.terminal import Clr
if TYPE_CHECKING:
pass
@dataclass
class AttributeInfo:
"""Info about an attribute of a class."""
name: str
attr_type: str | None = None
docs: str | None = None
def parse_docs_attrs(attrs: list[AttributeInfo], docs: str) -> str:
"""Given a docs str, parses attribute descriptions contained within."""
docs_lines = docs.splitlines()
attr_line = None
for i, line in enumerate(docs_lines):
if line.strip() in ['Attributes:', 'Attrs:']:
attr_line = i
break
if attr_line is not None:
# Docs is now everything *up to* this.
docs = '\n'.join(docs_lines[:attr_line])
# Go through remaining lines creating attrs and docs for each.
cur_attr: AttributeInfo | None = None
for i in range(attr_line + 1, len(docs_lines)):
line = docs_lines[i].strip()
# A line with a single alphanumeric word preceding a colon
# is a new attr.
splits = line.split(' ', maxsplit=1)
if splits[0].replace('_', '').isalnum() and splits[-1].endswith(
':'
):
if cur_attr is not None:
attrs.append(cur_attr)
cur_attr = AttributeInfo(name=splits[0])
if len(splits) == 2:
# Remove brackets and convert from
# (type): to type.
cur_attr.attr_type = splits[1][1:-2]
# Any other line gets tacked onto the current attr.
else:
if cur_attr is not None:
if cur_attr.docs is None:
cur_attr.docs = ''
cur_attr.docs += line + '\n'
# Finish out last.
if cur_attr is not None:
attrs.append(cur_attr)
for attr in attrs:
if attr.docs is not None:
attr.docs = attr.docs.strip()
return docs
def generate_pdoc(projroot: str) -> None:
"""Generate a set of pdoc documentation."""
from batools import apprun
del projroot # Unused.
# Assemble and launch an app and do our docs generation from there.
apprun.python_command(
'import batools.docs; batools.docs._run_pdoc_in_engine()',
purpose='pdocs generation',
include_project_tools=True,
)
def _run_pdoc_in_engine() -> None:
import time
import pdoc
from batools.version import get_current_version
starttime = time.monotonic()
# Tell pdoc to go through all the modules we've got in
# ba_data/python.
modulenames = sorted(
n.removesuffix('.py')
for n in os.listdir('src/assets/ba_data/python')
if not n.startswith('.')
)
assert modulenames
templatesdir = Path('src/assets/pdoc/templates')
assert templatesdir.is_dir()
version, buildnum = get_current_version()
pdoc.render.env.globals['ba_version'] = version
pdoc.render.env.globals['ba_build'] = buildnum
pdoc.render.configure(
search=True,
show_source=True,
template_directory=Path('src/assets/pdoc/templates'),
)
pdoc.pdoc(*modulenames, output_directory=Path('build/docs_pdoc'))
duration = time.monotonic() - starttime
print(f'{Clr.GRN}Generated pdoc documentation in {duration:.1f}s.{Clr.RST}')