Skip to content

Commit 8add57b

Browse files
committed
WIP replace with image
1 parent c087cf0 commit 8add57b

File tree

2 files changed

+107
-26
lines changed

2 files changed

+107
-26
lines changed

scripts/nb2doc/convert.sh

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,5 @@
11
#!/bin/bash
22

3-
DOC_DIR=doc/modules/ROOT/pages/tutorials
4-
NB_DIR=examples
5-
6-
for notebook in ${NB_DIR}/*.ipynb
7-
do
8-
docfile=$(basename ${notebook} | cut -d. -f1)
9-
echo "${notebook} -> ${DOC_DIR}/${docfile}.adoc"
10-
11-
# --noprompt
12-
#  Skips the "In/Out" lines before each cell
13-
# --ClearMetadataPreprocessor.enabled=True
14-
#  Cleans the "ipython3" language replacing it with "Python"
15-
# (for Asciidoc code cells)
16-
# --ASCIIDocExporter.file_extension=.adoc
17-
# If not set, the extension is .asciidoc
18-
19-
jupyter nbconvert \
20-
--to asciidoc \
21-
--template=scripts/nb2doc/asciidoc-template \
22-
--output-dir ${DOC_DIR} \
23-
--ASCIIDocExporter.file_extension=.adoc \
24-
--no-prompt \
25-
--ClearMetadataPreprocessor.enabled=True \
26-
${notebook}
27-
done
28-
3+
python ./scripts/nb2doc/convert_notebooks.py \
4+
-o "doc/modules/ROOT/pages/tutorials" \
5+
-i "examples/"

scripts/nb2doc/convert_notebooks.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# reasons for not using nbconvert cli tool:
2+
# * cannot keep output based on a given tag
3+
4+
import argparse
5+
import logging.config
6+
import re
7+
import sys
8+
from pathlib import Path
9+
10+
import nbconvert
11+
from nbconvert.preprocessors import Preprocessor
12+
13+
REPLACE_CELL_OUTPUT_TAG_PATTTERN = r"replace-output-with\:(.*)"
14+
METADATA_TAG_KEY = "tags"
15+
16+
TEMPLATE_DIR = Path("scripts/nb2doc/asciidoc-template")
17+
18+
logging.basicConfig()
19+
handler = logging.StreamHandler(sys.stdout)
20+
handler.setLevel(logging.DEBUG)
21+
logger = logging.getLogger()
22+
23+
24+
class OutputReplacerPreprocessor(Preprocessor):
25+
"""
26+
Replaces the output from tagged code cell in a notebook.
27+
Expected Tag format `replace-with:images/some.png`
28+
"""
29+
30+
def __init__(self, replace_base_dir: Path, **kw):
31+
self._replace_base_dir = replace_base_dir
32+
super().__init__(**kw)
33+
34+
def preprocess_cell(self, cell, resources, cell_index):
35+
"""
36+
Apply a transformation on each cell. See base.py for details.
37+
"""
38+
39+
if replace_tags := [
40+
tag for tag in cell["metadata"].get(METADATA_TAG_KEY, []) if re.match(REPLACE_CELL_OUTPUT_TAG_PATTTERN, tag)
41+
]:
42+
if len(replace_tags) > 1:
43+
raise ValueError(
44+
f"Expected one or zero tags matching `{REPLACE_CELL_OUTPUT_TAG_PATTTERN}`. But got `{replace_tags}`"
45+
)
46+
new_output_file_name = replace_tags[0].split(":")[1].strip()
47+
new_ouput_file = self._replace_base_dir.joinpath(new_output_file_name)
48+
logger.info(f"Replace output with content from: {new_ouput_file}")
49+
with new_ouput_file.open("r") as new_output:
50+
# TODO: figure-out schema of cell outputs
51+
# TODO Implement according to https://nbformat.readthedocs.io/en/latest/format_description.html#display-data
52+
cell.outputs = [
53+
{
54+
"output_type": "display_data",
55+
"data": {"text/plain": str(new_output)},
56+
"metadata": {},
57+
}
58+
]
59+
cell.execution_count = None
60+
return cell, resources
61+
62+
63+
def to_output_file(input_file: Path, output_dir: Path) -> Path:
64+
return output_dir.joinpath(input_file.name.replace(".ipynb", ".adoc"))
65+
66+
67+
def main(input_path: Path, output_dir: Path) -> None:
68+
if input_path.is_file():
69+
notebooks = [input_path]
70+
else:
71+
notebooks = [f for f in input_path.iterdir() if f.is_file() and f.suffix == ".ipynb"]
72+
73+
exporter = nbconvert.ASCIIDocExporter(template_file=str(TEMPLATE_DIR.joinpath("index.adoc.j2")))
74+
# Skips the "In/Out" lines before each cell
75+
exporter.exclude_input_prompt = True
76+
exporter.exclude_output_prompt = True
77+
78+
metadata_cleaner = nbconvert.preprocessors.ClearMetadataPreprocessor(preserve_cell_metadata_mask=METADATA_TAG_KEY)
79+
output_replacer = OutputReplacerPreprocessor(replace_base_dir=input_path)
80+
81+
exporter.register_preprocessor(metadata_cleaner, enabled=True)
82+
exporter.register_preprocessor(output_replacer, enabled=True)
83+
84+
logger.info(f"Converting {len(notebooks)} notebooks.")
85+
86+
for notebook in notebooks:
87+
output_file = to_output_file(notebook, output_dir)
88+
logger.info(f"Converting notebook from `{input_path}` to: `{output_file}`")
89+
output = exporter.from_filename(notebook)
90+
91+
converted = output[0]
92+
93+
with output_file.open(mode="w") as out:
94+
out.write(converted)
95+
96+
97+
if __name__ == "__main__":
98+
parser = argparse.ArgumentParser()
99+
parser.add_argument("-o", "--output", required=True, help="directory to write the result to")
100+
parser.add_argument("-i", "--input", required=True, help="path to the notebook file")
101+
102+
args = parser.parse_args()
103+
104+
main(Path(args.input), Path(args.output))

0 commit comments

Comments
 (0)