From 236a89e62b2a45f16d8324197639dd59c1059fe6 Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Fri, 11 Feb 2022 10:06:08 +0300 Subject: [PATCH] cleanup docs.py --- tools/batools/docs.py | 293 +----------------------------------------- 1 file changed, 1 insertion(+), 292 deletions(-) diff --git a/tools/batools/docs.py b/tools/batools/docs.py index a436eab1..c45b23af 100755 --- a/tools/batools/docs.py +++ b/tools/batools/docs.py @@ -6,33 +6,15 @@ from __future__ import annotations import sys import os -import inspect from dataclasses import dataclass from pathlib import Path from typing import TYPE_CHECKING -from enum import Enum from efro.error import CleanError from efro.terminal import Clr if TYPE_CHECKING: - from types import ModuleType - from typing import Optional, Callable, Any, Sequence - -CATEGORY_STRING = 'Category:' - -DO_STYLES = False -DO_CSS_CLASSES = False - -STYLE_PAD_L0 = ' style="padding-left: 0px;"' if DO_STYLES else '' -STYLE_PAD_L30 = ' style="padding-left: 30px;"' if DO_STYLES else '' -STYLE_PAD_L60 = ' style="padding-left: 60px;"' if DO_STYLES else '' - - -class CategoryType(Enum): - """Self explanatory.""" - FUNCTION = 0 - CLASS = 1 + from typing import Optional @dataclass @@ -43,29 +25,6 @@ class AttributeInfo: docs: Optional[str] = None -@dataclass -class FunctionInfo: - """Info about a function/method.""" - name: str - category: Optional[str] = None - method_class: Optional[str] = None - docs: Optional[str] = None - is_class_method: bool = False - - -@dataclass -class ClassInfo: - """Info about a class of functions/classes.""" - name: str - category: str - methods: list[FunctionInfo] - inherited_methods: list[FunctionInfo] - attributes: list[AttributeInfo] - parents: list[str] - docs: Optional[str] - enum_values: Optional[list[str]] - - def parse_docs_attrs(attrs: list[AttributeInfo], docs: str) -> str: """Given a docs str, parses attribute descriptions contained within.""" docs_lines = docs.splitlines() @@ -112,256 +71,6 @@ def parse_docs_attrs(attrs: list[AttributeInfo], docs: str) -> str: return docs -def _get_defining_class(cls: type, name: str) -> Optional[type]: - for i in cls.mro()[1:]: - if hasattr(i, name): - return i - return None - - -def _get_bases(cls: type) -> list[str]: - bases = [] - for par in cls.mro()[1:]: - if par is not object: - bases.append(par.__module__ + '.' + par.__name__) - return bases - - -def _split_into_paragraphs(docs: str, filter_type: str, indent: int) -> str: - indent_str = str(indent) + 'px' - - # Ok, now break into paragraphs (2 newlines denotes a new paragraph). - paragraphs = docs.split('\n\n') - docs = '' - for i, par in enumerate(paragraphs): - - # For function/method signatures, indent lines after the first so - # our big multi-line function signatures are readable. - if (filter_type in ['function', 'method'] and i == 0 - and len(par.split('(')) > 1 - and par.strip().split('(')[0].replace('.', '').replace( - '_', '').isalnum()): - style = (' style="padding-left: ' + str(indent + 50) + - 'px; text-indent: -50px;"') if DO_STYLES else '' - style2 = ' style="color: #666677;"' if DO_STYLES else '' - docs += f'' - - # Also, signatures seem to have quotes around annotations. - # Let's just strip them all out. This will look wrong if - # we have a string as a default value though, so don't - # in that case. - if " = '" not in par and ' = "' not in par: - par = par.replace("'", '') - docs += par - docs += '

\n\n' - - # Emphasize a few specific lines. - elif par.strip() in [ - 'Conditions:', 'Available Conditions:', 'Actions:', - 'Available Actions:', 'Play Types:', - 'Available Setting Options:', 'Available Values:', 'Usage:' - ]: - style = (' style="padding-left: ' + indent_str + - ';"' if DO_STYLES else '') - docs += f'' - docs += par - docs += '

\n\n' - - elif par.lower().strip().startswith(CATEGORY_STRING.lower()): - style = (' style="padding-left: ' + indent_str + - ';"' if DO_STYLES else '') - docs += f'' - docs += par - docs += '

\n\n' - - elif par.strip().startswith('#'): - p_lines = par.split('\n') - for it2, line in enumerate(p_lines): - if line.strip().startswith('#'): - style = (' style="color: #008800;"' if DO_STYLES else '') - p_lines[it2] = (f'' + line + - '') - par = '\n'.join(p_lines) - style = (' style="padding-left: ' + indent_str + - ';"' if DO_STYLES else '') - docs += f'' - docs += par - docs += '\n\n' - else: - style = (' style="padding-left: ' + indent_str + - ';"' if DO_STYLES else '') - docs += f'' - docs += par - docs += '

\n\n' - return docs - - -def _filter_type_settings(filter_type: str) -> tuple[Optional[Callable], int]: - get_category_href_func = None - if filter_type == 'class': - indent = 30 - get_category_href_func = _get_class_category_href - elif filter_type == 'method': - indent = 60 - elif filter_type == 'function': - indent = 30 - get_category_href_func = _get_function_category_href - elif filter_type == 'attribute': - indent = 60 - else: - raise Exception('invalid filter_type: ' + str(filter_type)) - return get_category_href_func, indent - - -def _get_defining_class_backwards(cls: type, name: str) -> Optional[type]: - mro = cls.mro() - mro.reverse() - for i in mro: - if hasattr(i, name): - return i - return None - - -def _get_module_classes(module: ModuleType) -> list[tuple[str, type]]: - names = dir(module) - - # Look for all public classes in the provided module. - class_objs = [ - getattr(module, name) for name in names if not name.startswith('_') - ] - class_objs = [ - c for c in class_objs if str(c).startswith(' bool: - method = getattr(cls, name) - - # Classmethods are already bound with the class as self. - # we need to just look at the im_func in that case - is_class_method = (inspect.ismethod(method) and method.__self__ is cls) - if is_class_method: - for mth in cls.mro()[1:]: - mth2 = getattr(mth, name, None) - if mth2 is not None: - if method.__func__ == mth2.__func__: - return True - else: - return any(method == getattr(i, name, None) for i in cls.mro()[1:]) - return False - - -def _get_function_category_href(c_name: str) -> str: - """Return a href for linking to the specified function category.""" - return 'function_category_' + c_name.replace('.', '_').replace(' ', '_') - - -def _get_class_category_href(c_name: str) -> str: - """Return a href for linking to the specified class category.""" - return 'class_category_' + c_name.replace('.', '_').replace(' ', '_') - - -def _get_class_href(c_name: str) -> str: - """Return a href for linking to the specified class.""" - return 'class_' + c_name.replace('.', '_') - - -def _get_function_href(f_name: str) -> str: - """Return a href for linking to the specified function.""" - return 'function_' + f_name.replace('.', '_') - - -def _get_method_href(c_name: str, f_name: str) -> str: - """Return a href for linking to the specified method.""" - return 'method_' + c_name.replace('.', '_') + '__' + f_name.replace( - '.', '_') - - -def _get_attribute_href(c_name: str, a_name: str) -> str: - return 'attr_' + c_name.replace('.', '_') + '__' + a_name.replace('.', '_') - - -def _get_category(docs: str, category_type: CategoryType) -> str: - """Parse the category name from a docstring.""" - category_lines = [ - l for l in docs.splitlines() - if l.lower().strip().startswith(CATEGORY_STRING.lower()) - ] - if category_lines: - category = category_lines[0].strip()[len(CATEGORY_STRING):].strip() - else: - category = { - CategoryType.CLASS: 'Misc Classes', - CategoryType.FUNCTION: 'Misc Functions' - }[category_type] - return category - - -def _print_child_classes(category_classes: list[ClassInfo], parent: str, - indent: int) -> str: - out = '' - valid_classes = [] - for cls in category_classes: - if cls.parents: - c_parent = cls.parents[0] - else: - c_parent = '' - - # If it has a parent not in this category, consider it to - # have no parent. - if c_parent != '': - found = False - for ctest in category_classes: - if c_parent == ctest.name: - found = True - break - if not found: - c_parent = '' - - # Print only if its parent matches what we want. - if c_parent == parent: - valid_classes.append(cls) - if valid_classes: - out += ' ' * indent + '
    \n' - for cls in valid_classes: - out += (' ' * indent + '
  • ' + cls.name + '
  • \n') - out += _print_child_classes(category_classes, cls.name, indent + 1) - if valid_classes: - out += ' ' * indent + '
\n' - return out - - -def _add_inner_classes(class_objs: Sequence[type], - classes_by_name: list[tuple[str, type]]) -> None: - # Ok, now go through all existing classes and look for classes - # defined within. - for cls in class_objs: - for name in dir(cls): - if name.startswith('_'): - continue - obj = getattr(cls, name) - if not inspect.isclass(obj): - continue - if _get_defining_class_backwards(cls, name) != cls: - continue - classes_by_name.append( - (cls.__module__ + '.' + cls.__name__ + '.' + name, obj)) - - def generate(projroot: str) -> None: """Main entry point.""" import pdoc