Skip to content

Commit cd59961

Browse files
cdeckerclaude
andcommitted
Add Python API documentation generation with pdoc3
This commit adds automated Python API documentation generation for all workspace packages using pdoc3: - Add contrib/api/generate-python-docs.py script to generate docs - Add Makefile targets: python-docs and python-docs-clean - Add GitHub Actions workflow for nightly documentation generation - Documents 5 packages: pyln.client, pyln.proto, pyln.grpc, pyln.testing, pyln.spec.bolt7 - Creates beautiful index page with cards linking to each package - Stores generated docs as artifacts with 90-day retention - Add pdoc3 and markdown to dev dependencies Bug fix: - Fix pyln-client version.py: __all__ must contain strings, not class objects This was causing "TypeError: attribute name must be string, not 'type'" in pdoc3 Documentation is generated to docs/python/ which is excluded from version control. Run 'make python-docs' to generate locally, or download from nightly workflow artifacts. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 54480cb commit cd59961

File tree

7 files changed

+294
-2
lines changed

7 files changed

+294
-2
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: Python API Docs (Nightly)
2+
3+
on:
4+
schedule:
5+
# Run at 3 AM UTC every day
6+
- cron: '0 3 * * *'
7+
# Allow manual triggers for testing
8+
workflow_dispatch:
9+
10+
concurrency:
11+
group: python-docs-${{ github.ref }}
12+
cancel-in-progress: true
13+
14+
jobs:
15+
generate-docs:
16+
name: Generate Python API Documentation
17+
runs-on: ubuntu-22.04
18+
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@v4
22+
23+
- name: Set up Python 3.10
24+
uses: actions/setup-python@v5
25+
with:
26+
python-version: "3.10"
27+
28+
- name: Install uv
29+
uses: astral-sh/setup-uv@v5
30+
31+
- name: Install dependencies
32+
run: |
33+
uv sync --all-extras
34+
35+
- name: Generate documentation
36+
run: |
37+
make python-docs
38+
39+
- name: Upload documentation artifact
40+
uses: actions/upload-artifact@v4
41+
with:
42+
name: python-api-docs
43+
path: docs/python
44+
retention-days: 90
45+
46+
- name: Add summary to job
47+
run: |
48+
echo "## Python API Documentation Generated" >> $GITHUB_STEP_SUMMARY
49+
echo "" >> $GITHUB_STEP_SUMMARY
50+
echo "📚 Documentation has been generated for the following packages:" >> $GITHUB_STEP_SUMMARY
51+
echo "" >> $GITHUB_STEP_SUMMARY
52+
echo "- pyln.client - Client library and plugin library" >> $GITHUB_STEP_SUMMARY
53+
echo "- pyln.proto - Lightning Network protocol implementation" >> $GITHUB_STEP_SUMMARY
54+
echo "- pyln.grpc - gRPC protocol definitions" >> $GITHUB_STEP_SUMMARY
55+
echo "- pyln.testing - Testing utilities" >> $GITHUB_STEP_SUMMARY
56+
echo "- pyln.spec.bolt7 - BOLT #7 specification implementation" >> $GITHUB_STEP_SUMMARY
57+
echo "" >> $GITHUB_STEP_SUMMARY
58+
echo "Download the artifact to view the complete API documentation." >> $GITHUB_STEP_SUMMARY

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ coverage
2727
# Coverage profiling data files
2828
*.profraw
2929
*.profdata
30+
# Generated Python API documentation
31+
docs/python
3032
ccan/config.h
3133
__pycache__
3234
config.vars

Makefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,15 @@ coverage-clang-clean:
689689

690690
.PHONY: coverage-clang-collect coverage-clang-report coverage-clang coverage-clang-clean
691691

692+
# Python API documentation targets
693+
python-docs:
694+
@./contrib/api/generate-python-docs.py
695+
696+
python-docs-clean:
697+
rm -rf docs/python
698+
699+
.PHONY: python-docs python-docs-clean
700+
692701
# We make libwallycore.la a dependency, so that it gets built normally, without ncc.
693702
# Ncc can't handle the libwally source code (yet).
694703
ncc: ${TARGET_DIR}/libwally-core-build/src/libwallycore.la
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Generate Python API documentation for all workspace packages using pdoc3.
4+
5+
This script generates HTML documentation for all Python packages in the
6+
Core Lightning workspace and creates an index page linking to all of them.
7+
"""
8+
9+
import os
10+
import subprocess
11+
import sys
12+
from datetime import datetime
13+
from pathlib import Path
14+
15+
# Define packages to document (module name -> source directory)
16+
# Only includes packages that are in the workspace and can be imported
17+
PACKAGES = {
18+
"pyln.client": "contrib/pyln-client",
19+
"pyln.proto": "contrib/pyln-proto",
20+
"pyln.grpc": "contrib/pyln-grpc-proto",
21+
"pyln.testing": "contrib/pyln-testing",
22+
"pyln.spec.bolt7": "contrib/pyln-spec/bolt7",
23+
}
24+
25+
INDEX_HTML_TEMPLATE = """<!DOCTYPE html>
26+
<html>
27+
<head>
28+
<title>Core Lightning Python Packages Documentation</title>
29+
<style>
30+
body {{
31+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
32+
max-width: 1200px;
33+
margin: 0 auto;
34+
padding: 40px 20px;
35+
line-height: 1.6;
36+
}}
37+
h1 {{
38+
border-bottom: 2px solid #eaecef;
39+
padding-bottom: 0.3em;
40+
}}
41+
.package-grid {{
42+
display: grid;
43+
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
44+
gap: 20px;
45+
margin-top: 30px;
46+
}}
47+
.package-card {{
48+
border: 1px solid #e1e4e8;
49+
border-radius: 6px;
50+
padding: 20px;
51+
transition: box-shadow 0.2s;
52+
}}
53+
.package-card:hover {{
54+
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
55+
}}
56+
.package-card h2 {{
57+
margin-top: 0;
58+
font-size: 1.3em;
59+
}}
60+
.package-card a {{
61+
color: #0366d6;
62+
text-decoration: none;
63+
}}
64+
.package-card a:hover {{
65+
text-decoration: underline;
66+
}}
67+
.package-description {{
68+
color: #586069;
69+
font-size: 0.9em;
70+
margin-top: 8px;
71+
}}
72+
.timestamp {{
73+
color: #586069;
74+
font-size: 0.9em;
75+
margin-top: 30px;
76+
text-align: center;
77+
}}
78+
</style>
79+
</head>
80+
<body>
81+
<h1>Core Lightning Python Packages Documentation</h1>
82+
<p>This page provides links to the API documentation for all Python packages in the Core Lightning workspace.</p>
83+
84+
<div class="package-grid">
85+
<div class="package-card">
86+
<h2><a href="pyln/client/index.html">pyln.client</a></h2>
87+
<p class="package-description">Client library and plugin library for Core Lightning</p>
88+
</div>
89+
90+
<div class="package-card">
91+
<h2><a href="pyln/proto/index.html">pyln.proto</a></h2>
92+
<p class="package-description">Lightning Network protocol implementation</p>
93+
</div>
94+
95+
<div class="package-card">
96+
<h2><a href="pyln/grpc/index.html">pyln.grpc</a></h2>
97+
<p class="package-description">gRPC protocol definitions for Core Lightning</p>
98+
</div>
99+
100+
<div class="package-card">
101+
<h2><a href="pyln/testing/index.html">pyln.testing</a></h2>
102+
<p class="package-description">Testing utilities for Core Lightning</p>
103+
</div>
104+
105+
<div class="package-card">
106+
<h2><a href="pyln/spec/bolt7/index.html">pyln.spec.bolt7</a></h2>
107+
<p class="package-description">BOLT #7 specification implementation</p>
108+
</div>
109+
</div>
110+
111+
<p class="timestamp">Generated on {timestamp}</p>
112+
</body>
113+
</html>
114+
"""
115+
116+
117+
def generate_docs(output_dir: Path, repo_root: Path):
118+
"""Generate documentation for all packages."""
119+
print(f"Generating Python documentation for all workspace packages...")
120+
print(f"Output directory: {output_dir}")
121+
122+
# Clean and create output directory
123+
if output_dir.exists():
124+
import shutil
125+
shutil.rmtree(output_dir)
126+
output_dir.mkdir(parents=True)
127+
128+
# Change to repo root for imports to work correctly
129+
os.chdir(repo_root)
130+
131+
# Generate documentation for each package
132+
for package, source_dir in PACKAGES.items():
133+
print(f"Generating docs for {package} (from {source_dir})...")
134+
135+
try:
136+
# Use pdoc3 to generate HTML documentation
137+
subprocess.run(
138+
[
139+
"uv", "run", "pdoc3",
140+
"--html",
141+
"--output-dir", str(output_dir),
142+
"--force",
143+
package
144+
],
145+
check=True,
146+
cwd=repo_root,
147+
)
148+
except subprocess.CalledProcessError as e:
149+
print(f"Warning: Failed to generate docs for {package}, skipping...")
150+
print(f"Error: {e}")
151+
continue
152+
153+
# Create index.html
154+
index_path = output_dir / "index.html"
155+
timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
156+
index_path.write_text(INDEX_HTML_TEMPLATE.format(timestamp=timestamp))
157+
158+
print("\nDocumentation generated successfully!")
159+
print(f"Open {output_dir}/index.html in your browser to view the documentation.")
160+
161+
162+
def main():
163+
"""Main entry point."""
164+
# Determine paths
165+
script_dir = Path(__file__).parent.resolve()
166+
repo_root = script_dir.parent.parent
167+
168+
# Default output directory
169+
output_dir = repo_root / "docs" / "python"
170+
171+
# Allow override via command line argument
172+
if len(sys.argv) > 1:
173+
output_dir = Path(sys.argv[1])
174+
175+
generate_docs(output_dir, repo_root)
176+
177+
178+
if __name__ == "__main__":
179+
main()

contrib/pyln-client/pyln/client/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,4 @@ def __lt__(self, other: Union[NodeVersion, str]) -> bool:
7575
return False
7676

7777

78-
__all__ = [NodeVersion]
78+
__all__ = ["NodeVersion"]

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ package-mode = false
2222
[dependency-groups]
2323
dev = [
2424
# Test dependencies and inherited dependencies belong here
25-
"crc32c>=2.2.post0", # Belongs to lnprototest
25+
"crc32c>=2.2.post0", # Belongs to lnprototest
2626
"pytest>=8.0.0",
2727
"pytest-xdist>=3.6.0",
2828
"pytest-test-groups>=1.2.0",
@@ -34,6 +34,7 @@ dev = [
3434
"flask-socketio>=5",
3535
"tqdm",
3636
"pytest-benchmark",
37+
"pdoc3>=0.11.6",
3738
]
3839

3940
[project.optional-dependencies]

uv.lock

Lines changed: 43 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)