build_search_index.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. #!/usr/bin/env python3
  2. import ast
  3. import json
  4. import os
  5. from pathlib import Path
  6. from typing import Optional, Union
  7. from icecream import ic
  8. from nicegui import app, ui
  9. dir_path = os.path.dirname(os.path.abspath(__file__))
  10. os.chdir(dir_path)
  11. class DemoVisitor(ast.NodeVisitor):
  12. def __init__(self, topic: Optional[str] = None) -> None:
  13. super().__init__()
  14. self.topic = topic
  15. def visit_FunctionDef(self, node: ast.FunctionDef) -> None:
  16. if node.name == 'main_demo':
  17. docstring = ast.get_docstring(node)
  18. if docstring is None:
  19. api = getattr(ui, self.topic) if hasattr(ui, self.topic) else getattr(app, self.topic)
  20. docstring = api.__doc__ or api.__init__.__doc__
  21. lines = docstring.splitlines()
  22. self.add_to_search_index(lines[0], lines[1:], main=True)
  23. for decorator in node.decorator_list:
  24. if isinstance(decorator, ast.Call):
  25. function = decorator.func
  26. if isinstance(function, ast.Name) and function.id == 'text_demo':
  27. title = decorator.args[0].s
  28. content = decorator.args[1].s.splitlines()
  29. self.add_to_search_index(title, content)
  30. self.generic_visit(node)
  31. def add_to_search_index(self, title: str, content: Union[str, list], main: bool = False) -> None:
  32. if isinstance(content, list):
  33. content_str = ' '.join([l.strip() for l in content]).strip()
  34. else:
  35. content_str = content
  36. anchor = title.lower().replace(' ', '_')
  37. url = f'/documentation/{self.topic or ""}'
  38. if not main:
  39. url += f'#{anchor}'
  40. if self.topic:
  41. title = f'{self.topic.replace("_", " ").title()}: {title}'
  42. documents.append({
  43. 'title': title,
  44. 'content': content_str,
  45. 'url': url
  46. })
  47. def generate_for(file: Path, topic: Optional[str] = None) -> None:
  48. with open(file, 'r') as source:
  49. tree = ast.parse(source.read())
  50. DemoVisitor(topic).visit(tree)
  51. documents = []
  52. generate_for(Path('./documentation.py'))
  53. for file in Path('./more_documentation').glob('*.py'):
  54. generate_for(file, file.stem.removesuffix('_documentation'))
  55. with open('static/search_index.json', 'w') as f:
  56. json.dump(documents, f, indent=2)