Skip to content

Commit 30eaa7a

Browse files
committed
cli changes
1 parent 0d2cb1d commit 30eaa7a

File tree

4 files changed

+177
-3
lines changed

4 files changed

+177
-3
lines changed

fern_cli.py

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Simple CLI wrapper for generating Fern documentation using autodoc2's built-in CLI.
4+
5+
Usage:
6+
python fern_cli.py /path/to/repo [--output /path/to/output] [--module module_name]
7+
8+
This is a simpler alternative to batch_fern_docs.py for single repositories.
9+
"""
10+
11+
import argparse
12+
import os
13+
import subprocess
14+
import sys
15+
from pathlib import Path
16+
17+
18+
def main():
19+
parser = argparse.ArgumentParser(
20+
description="Generate Fern-compatible documentation using autodoc2",
21+
formatter_class=argparse.RawDescriptionHelpFormatter,
22+
epilog="""
23+
Examples:
24+
# Process nemo-rl repository
25+
python fern_cli.py /tmp/nemo-rl --output /tmp/nemo-rl-docs --module nemo_rl
26+
27+
# Auto-detect module name and use default output
28+
python fern_cli.py ~/code/my-package
29+
30+
# Process with verbose output
31+
python fern_cli.py /path/to/repo --verbose
32+
"""
33+
)
34+
35+
parser.add_argument("repo_path", type=Path, help="Path to the repository to process")
36+
parser.add_argument("--output", "-o", type=Path, help="Output directory (default: {repo}/fern_docs)")
37+
parser.add_argument("--module", "-m", type=str, help="Module name (auto-detected if not provided)")
38+
parser.add_argument("--verbose", "-v", action="store_true", help="Show verbose output")
39+
parser.add_argument("--clean", "-c", action="store_true", help="Clean output directory first")
40+
41+
args = parser.parse_args()
42+
43+
# Resolve repo path
44+
repo_path = args.repo_path.expanduser().resolve()
45+
if not repo_path.exists():
46+
print(f"ERROR: Repository path does not exist: {repo_path}")
47+
return 1
48+
49+
# Determine output directory
50+
output_dir = args.output
51+
if output_dir is None:
52+
output_dir = repo_path / "fern_docs"
53+
else:
54+
output_dir = output_dir.expanduser().resolve()
55+
56+
# Determine module name
57+
module_name = args.module
58+
if module_name is None:
59+
# Look for Python packages in the repo
60+
package_dirs = [
61+
d for d in repo_path.iterdir()
62+
if d.is_dir() and (d / "__init__.py").exists()
63+
]
64+
if package_dirs:
65+
module_name = package_dirs[0].name
66+
print(f"Auto-detected module: {module_name}")
67+
else:
68+
module_name = repo_path.name
69+
print(f"No Python packages found, using repo name: {module_name}")
70+
71+
# Create output directory
72+
output_dir.mkdir(parents=True, exist_ok=True)
73+
if args.clean and output_dir.exists():
74+
import shutil
75+
shutil.rmtree(output_dir)
76+
output_dir.mkdir(parents=True)
77+
78+
# Set up environment to use our FernRenderer
79+
env = os.environ.copy()
80+
autodoc2_src = Path(__file__).parent / "src"
81+
if "PYTHONPATH" in env:
82+
env["PYTHONPATH"] = f"{autodoc2_src}:{env['PYTHONPATH']}"
83+
else:
84+
env["PYTHONPATH"] = str(autodoc2_src)
85+
86+
# Build the autodoc2 command
87+
cmd = [
88+
sys.executable, "-m", "autodoc2.cli", "write",
89+
str(repo_path),
90+
"--output", str(output_dir),
91+
"--module", module_name,
92+
]
93+
94+
if args.clean:
95+
cmd.append("--clean")
96+
97+
print(f"🔄 Processing: {repo_path}")
98+
print(f"📁 Output: {output_dir}")
99+
print(f"📦 Module: {module_name}")
100+
print(f"🔧 Command: {' '.join(cmd)}")
101+
print()
102+
103+
# Unfortunately, the current autodoc2 CLI doesn't support specifying renderer
104+
# So we need to create a temporary config or modify the approach
105+
print("⚠️ NOTE: This uses the default renderer (MyST).")
106+
print(" For Fern output, use batch_fern_docs.py instead.")
107+
print(" Running with MyST renderer...")
108+
print()
109+
110+
# Run the command
111+
try:
112+
result = subprocess.run(cmd, env=env, capture_output=not args.verbose)
113+
114+
if result.returncode == 0:
115+
print("✅ Documentation generated successfully!")
116+
print(f"📂 Output directory: {output_dir}")
117+
118+
# List generated files
119+
if output_dir.exists():
120+
md_files = list(output_dir.glob("**/*.md"))
121+
rst_files = list(output_dir.glob("**/*.rst"))
122+
all_files = md_files + rst_files
123+
124+
if all_files:
125+
print(f"📄 Generated {len(all_files)} files:")
126+
for file in sorted(all_files):
127+
rel_path = file.relative_to(output_dir)
128+
print(f" - {rel_path}")
129+
else:
130+
print("⚠️ No documentation files found in output directory")
131+
132+
return 0
133+
else:
134+
print("❌ Documentation generation failed!")
135+
if result.stderr:
136+
print("Error output:")
137+
print(result.stderr.decode())
138+
return 1
139+
140+
except FileNotFoundError:
141+
print("❌ autodoc2 CLI not found. Make sure autodoc2 is installed.")
142+
print(" Try: pip install -e .")
143+
return 1
144+
except KeyboardInterrupt:
145+
print("\n⏹️ Cancelled by user")
146+
return 1
147+
148+
149+
if __name__ == "__main__":
150+
sys.exit(main())

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ name = "autodoc2"
88
[project]
99
name = "sphinx-autodoc2-fern"
1010
dynamic = ["version", "description"]
11-
authors = [{name = "Ryan Paul", email = "your-email@example.com"}]
11+
authors = [{name = "Ryan Stephen", email = "ryanstep@buildwithfern.com"}]
1212
license = {file = "LICENSE"}
1313
classifiers = [
1414
"License :: OSI Approved :: MIT License",

src/autodoc2/cli.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ def write(
198198
# TODO read from config file, to populate config object
199199
output: Path = typer.Option("_autodoc", help="Folder to write to"),
200200
clean: bool = typer.Option(False, "-c", "--clean", help="Remove old files"),
201+
renderer: str = typer.Option("fern", "-r", "--renderer", help="Renderer to use: fern, rst, myst"),
201202
) -> None:
202203
"""Create sphinx files for a python module or package."""
203204
# gather the module
@@ -255,12 +256,27 @@ def _warn(msg: str, type_: WarningSubtypes) -> None:
255256
progress.console.print(f"[yellow]Warning[/yellow] {msg} [{type_.value}]")
256257

257258
config = Config()
259+
260+
# Set renderer based on CLI option
261+
if renderer == "rst":
262+
from autodoc2.render.rst_ import RstRenderer
263+
render_class = RstRenderer
264+
elif renderer == "myst":
265+
from autodoc2.render.myst_ import MystRenderer
266+
render_class = MystRenderer
267+
elif renderer == "fern":
268+
from autodoc2.render.fern_ import FernRenderer
269+
render_class = FernRenderer
270+
else:
271+
console.print(f"[red]Error[/red] Unknown renderer: {renderer}")
272+
raise typer.Exit(1)
273+
258274
for mod_name in to_write:
259275
progress.update(task, advance=1, description=mod_name)
260276
content = "\n".join(
261-
config.render_plugin(db, config, warn=_warn).render_item(mod_name)
277+
render_class(db, config, warn=_warn).render_item(mod_name)
262278
)
263-
out_path = output / (mod_name + config.render_plugin.EXTENSION)
279+
out_path = output / (mod_name + render_class.EXTENSION)
264280
paths.append(out_path)
265281
if out_path.exists() and out_path.read_text("utf8") == content:
266282
# Don't write the file if it hasn't changed

src/autodoc2/render/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
"""Renderers for the package."""
2+
3+
from autodoc2.render.base import RendererBase
4+
from autodoc2.render.fern_ import FernRenderer
5+
from autodoc2.render.myst_ import MystRenderer
6+
from autodoc2.render.rst_ import RstRenderer
7+
8+
__all__ = ["RendererBase", "FernRenderer", "MystRenderer", "RstRenderer"]

0 commit comments

Comments
 (0)