Skip to content

Commit 2e3a0ac

Browse files
committed
feat: add documentation generator README and enhance lazy import scanning to support _LAZY_GROUPS and TOOL_MAPPINGS patterns.
1 parent be81fc5 commit 2e3a0ac

File tree

3 files changed

+139
-13
lines changed

3 files changed

+139
-13
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# PraisonAI Docs Generator
2+
3+
A powerful documentation generator for PraisonAI SDK reference documentation.
4+
5+
## Installation
6+
7+
```bash
8+
pip install praisonai-tools
9+
```
10+
11+
## Quick Start
12+
13+
### Using CLI
14+
15+
```bash
16+
# Generate documentation with default settings
17+
praisonai-tools docs-generate
18+
19+
# Generate with granular layout (separate pages for classes/functions)
20+
praisonai-tools docs-generate --layout granular
21+
22+
# Specify custom output directory
23+
praisonai-tools docs-generate --output /path/to/docs
24+
```
25+
26+
### Using Python Module
27+
28+
```bash
29+
# Run as module
30+
python -m praisonai_tools.docs_generator
31+
32+
# With options
33+
python -m praisonai_tools.docs_generator --layout granular
34+
```
35+
36+
### Direct Script Execution
37+
38+
```bash
39+
python generator.py --layout granular
40+
```
41+
42+
## Options
43+
44+
| Option | Description | Default |
45+
|--------|-------------|---------|
46+
| `--layout` | Documentation layout: `compact` or `granular` | `granular` |
47+
| `--output` | Output directory path | Auto-detected |
48+
49+
## Layouts
50+
51+
### Compact Layout
52+
- Single page per module
53+
- Classes and functions inline
54+
55+
### Granular Layout (Recommended)
56+
- Separate pages for each class and function
57+
- Module hub pages with links to components
58+
- Better navigation and searchability
59+
60+
## Features
61+
62+
- **Dynamic lazy-loading support**: Captures `_LAZY_IMPORTS`, `_LAZY_GROUPS`, `TOOL_MAPPINGS`
63+
- **Recursive scanning**: Scans all `__init__.py` files in package tree
64+
- **MDX output**: Mintlify-compatible MDX format
65+
- **Navigation generation**: Auto-updates `docs.json` navigation
66+
- **Icon support**: Maps modules to Font Awesome icons
67+
68+
## Supported Packages
69+
70+
- `praisonaiagents` (Python Core SDK)
71+
- `praisonai` (Python Wrapper)
72+
- TypeScript SDK (`praisonai-ts`)
73+
74+
## Output Structure
75+
76+
```
77+
docs/sdk/reference/
78+
├── praisonaiagents/
79+
│ ├── modules/ # Module hub pages
80+
│ ├── classes/ # Class pages
81+
│ └── functions/ # Function pages
82+
├── praisonai/
83+
│ └── ...
84+
└── typescript/
85+
└── ...
86+
```

praisonai_tools/docs_generator/generator.py

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -341,23 +341,63 @@ def __init__(self, package_path: Path, package_name: str):
341341
self._load_lazy_imports()
342342

343343
def _load_lazy_imports(self):
344-
"""Load _LAZY_IMPORTS from __init__.py if available."""
345-
init_file = self.package_path / "__init__.py"
346-
if not init_file.exists():
347-
return
344+
"""Load _LAZY_IMPORTS and _LAZY_GROUPS from all __init__.py files.
348345
349-
try:
350-
content = init_file.read_text()
351-
match = re.search(r'_LAZY_IMPORTS\s*=\s*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}', content, re.DOTALL)
352-
if not match:
353-
return
354-
346+
Recursively scans the package and all submodules for lazy import patterns.
347+
Supports two patterns:
348+
1. _LAZY_IMPORTS: flat dict of symbol -> (module, symbol)
349+
2. _LAZY_GROUPS: nested dict of group -> {symbol: (module, symbol)}
350+
"""
351+
# Scan all __init__.py files in the package
352+
init_files = list(self.package_path.rglob("__init__.py"))
353+
354+
for init_file in init_files:
355+
try:
356+
content = init_file.read_text()
357+
self._parse_lazy_patterns(content)
358+
except Exception:
359+
pass
360+
361+
def _parse_lazy_patterns(self, content: str):
362+
"""Parse various lazy loading patterns from file content.
363+
364+
Supports patterns:
365+
1. _LAZY_IMPORTS: flat dict of symbol -> (module, symbol)
366+
2. _LAZY_GROUPS: nested dict of group -> {symbol: (module, symbol)}
367+
3. TOOL_MAPPINGS: dict of symbol -> (module, class_or_none)
368+
4. __all__: explicit export list (fallback for inline __getattr__)
369+
"""
370+
# Pattern 1: _LAZY_IMPORTS (flat dict)
371+
match = re.search(r'_LAZY_IMPORTS\s*=\s*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}', content, re.DOTALL)
372+
if match:
355373
dict_content = match.group(1)
356374
pattern = r"'(\w+)':\s*\('([^']+)',\s*'([^']+)'\)"
357375
for m in re.finditer(pattern, dict_content):
358376
self._lazy_imports[m.group(1)] = (m.group(2), m.group(3))
359-
except Exception:
360-
pass
377+
378+
# Pattern 2: _LAZY_GROUPS (nested dict used by hooks, etc.)
379+
match = re.search(r'_LAZY_GROUPS\s*=\s*\{(.+?)\n\}', content, re.DOTALL)
380+
if match:
381+
groups_content = match.group(1)
382+
# Parse all symbol -> (module, symbol) pairs within groups
383+
pattern = r"'(\w+)':\s*\('([^']+)',\s*'([^']+)'\)"
384+
for m in re.finditer(pattern, groups_content):
385+
symbol_name = m.group(1)
386+
module_path = m.group(2)
387+
self._lazy_imports[symbol_name] = (module_path, symbol_name)
388+
389+
# Pattern 3: TOOL_MAPPINGS (used by tools/__init__.py)
390+
match = re.search(r'TOOL_MAPPINGS\s*=\s*\{(.+?)\n\}', content, re.DOTALL)
391+
if match:
392+
mappings_content = match.group(1)
393+
# Parse 'symbol': ('.module', None) or 'symbol': ('.module', 'ClassName')
394+
pattern = r"'(\w+)':\s*\('([^']+)',\s*(?:None|'([^']*)')\)"
395+
for m in re.finditer(pattern, mappings_content):
396+
symbol_name = m.group(1)
397+
self._lazy_imports[symbol_name] = (m.group(2), symbol_name)
398+
399+
400+
361401

362402
def get_modules(self) -> List[str]:
363403
"""Get list of modules to document."""

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "praisonai-tools"
3-
version = "0.2.11"
3+
version = "0.2.12"
44
description = "Extended tools for PraisonAI Agents"
55
authors = [
66
{name = "Mervin Praison"}

0 commit comments

Comments
 (0)