Skip to content

Commit 16f2cd4

Browse files
committed
feat: building example pages
1 parent 48c70af commit 16f2cd4

File tree

9 files changed

+155
-47
lines changed

9 files changed

+155
-47
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
node_modules
22
_site
33

4+
__pycache__
5+
46
build/*
57
!build/plotcss.js
68
!build/README.md

docs/Makefile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,17 @@ build:
1515
cp ${SCHEMA_SRC} ${SCHEMA_DST}
1616
${JEKYLL} build
1717

18+
## examples: build example documentation in ./tmp
19+
examples:
20+
@rm -rf tmp
21+
@mkdir -p tmp
22+
${RUN} bin/example_pages.py --indir _posts/plotly_js --outdir tmp/javascript --verbose 1
23+
1824
## reference: build reference documentation in ./tmp
1925
reference:
2026
@rm -rf tmp
2127
@mkdir -p tmp
22-
${RUN} bin/make_reference_pages.py --schema ${SCHEMA_SRC} --outdir tmp _posts/reference_pages/javascript/*.html
28+
${RUN} bin/reference_pages.py --schema ${SCHEMA_SRC} --outdir tmp/reference _posts/reference_pages/javascript/*.html
2329

2430
## serve: display documentation
2531
serve:

docs/_posts/reference_pages/javascript/2020-07-20-heatmapgl.html

Lines changed: 0 additions & 18 deletions
This file was deleted.

docs/_posts/reference_pages/javascript/2020-07-20-pointcloud.html

Lines changed: 0 additions & 18 deletions
This file was deleted.

docs/bin/example_pages.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
"""Rebuild plotly.js example pages from Jekyll HTML."""
2+
3+
import argparse
4+
import frontmatter
5+
from pathlib import Path
6+
import re
7+
8+
from utils import _log, _str
9+
10+
11+
SUITE_RE = re.compile(r'where:"suite","(.+?)"')
12+
13+
14+
def main():
15+
"""Main driver."""
16+
args = _parse_args()
17+
index_files, example_files = _get_source_files(args)
18+
for path, record in index_files.items():
19+
_process(args, path, record, example_files)
20+
21+
22+
def _get_source_files(args):
23+
"""Load and classify source files."""
24+
index_files = {}
25+
example_files = {}
26+
for filepath in args.indir.glob("**/*.html"):
27+
page = frontmatter.load(filepath)
28+
record = {"header": page.metadata, "content": page.content}
29+
if not str(filepath).endswith("index.html"):
30+
example_files[filepath] = record
31+
elif "posts/auto_examples.html" in page.content:
32+
index_files[filepath] = record
33+
return index_files, example_files
34+
35+
36+
def _get_suite(path, content):
37+
"""Get suite specification from index file."""
38+
m = SUITE_RE.search(content)
39+
if _log(not m, f"cannot find 'suite' in index file {path}"):
40+
return None
41+
return m.group(1)
42+
43+
44+
def _parse_args():
45+
"""Parse command-line arguments."""
46+
parser = argparse.ArgumentParser(description="Generate HTML example documentation")
47+
parser.add_argument("--indir", type=Path, help="Input directory")
48+
parser.add_argument("--schema", type=Path, help="Path to plot schema JSON file")
49+
parser.add_argument("--outdir", type=Path, help="Output directory")
50+
parser.add_argument("--verbose", type=int, default=0, help="Integer verbosity level")
51+
return parser.parse_args()
52+
53+
54+
def _process(args, path, record, example_files):
55+
"""Process a section."""
56+
if (suite := _get_suite(path, record["content"])) is None:
57+
return
58+
59+
children = [
60+
p for p, r in example_files.items()
61+
if r["header"].get("suite", None) == suite
62+
]
63+
children.sort(key=lambda p: (example_files[p]["header"]["order"], str(p)))
64+
65+
section = record["header"]["permalink"].strip("/").split("/")[-1]
66+
_log(args.verbose > 0, f"...{section}: {len(children)}")
67+
68+
output_path = args.outdir / section / "index.html"
69+
output_path.parent.mkdir(parents=True, exist_ok=True)
70+
output_path.write_text(record["header"]["name"])
71+
72+
73+
if __name__ == "__main__":
74+
main()

docs/bin/make_reference_pages.py renamed to docs/bin/reference_pages.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import re
88
import sys
99

10+
from utils import _log, _str
11+
1012

1113
INCLUDE_BLOCK_RE = re.compile(
1214
r'{%\s*include\s+posts/reference-block.html\s+parentlink="(.+?)"\s+block="(.+?)"\s+parentpath="(.+?)"\s+mustmatch="(.+?)"\s*%}'
@@ -114,7 +116,7 @@ def main():
114116
_log(not m, f"failed to match include in {src_path}")
115117
continue
116118

117-
output_path = args.outdir / "reference" / title.replace(".", "/") / "index.html"
119+
output_path = args.outdir / title.replace(".", "/") / "index.html"
118120
output_path.parent.mkdir(parents=True, exist_ok=True)
119121
output_path.write_text(html)
120122

@@ -140,13 +142,6 @@ def _get(value, key, default=None):
140142
return value.get(key, default)
141143

142144

143-
def _log(condition, msg):
144-
"""Conditionally report progress."""
145-
if condition:
146-
print(msg, file=sys.stderr)
147-
return condition
148-
149-
150145
def _parse_args():
151146
"""Parse command-line arguments."""
152147
parser = argparse.ArgumentParser(description="Generate HTML reference documentation")
@@ -237,7 +232,7 @@ def _reference_block_valtype(src_path, accum, key, value):
237232
accum.append(f"{inner}<em>Type:</em> {_get(value, 'valType')} string.\n\n")
238233
flags = _get(value, "flags")
239234
if not flags:
240-
print(f"no flags for flaglist in {src_path}", file=sys.stderr)
235+
print(f"no flags for flaglist {key} in {src_path}", file=sys.stderr)
241236
return
242237

243238
accum.append(f"{inner}Any combination of ")

docs/bin/utils.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""Documentation generation utilities."""
2+
3+
import sys
4+
5+
6+
def _log(condition, msg):
7+
"""Conditionally report progress."""
8+
if condition:
9+
print(msg, file=sys.stderr)
10+
return condition
11+
12+
13+
def _str(val):
14+
"""Hacky string conversion."""
15+
if isinstance(val, str):
16+
return val
17+
if isinstance(val, bool):
18+
return str(val).lower()
19+
if isinstance(val, int):
20+
return str(val)
21+
return str(val)

pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@ name = "plotly.js"
33
description = "Plotly JavaScript charting library"
44
version = "3.1.0"
55
requires-python = ">=3.12"
6-
dependencies = []
6+
dependencies = [
7+
"python-frontmatter"
8+
]

uv.lock

Lines changed: 44 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)