1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
"""
examples.py
------------
Convert `ipynb` to a web-renderable format from the contents
of `../examples/*.ipynb`
"""
import logging
import os
import sys
log = logging.getLogger("trimesh")
log.addHandler(logging.StreamHandler(sys.stdout))
log.setLevel(logging.DEBUG)
# current working directory
pwd = os.path.abspath(os.path.expanduser(os.path.dirname(__file__)))
def extract_docstring(loaded):
"""
Given a loaded JSON `ipynb` notebook extract
the docstring from the first cell and error
if the first cell doesn't have a docstring.
Parameters
------------
loaded : dict
Loaded ipynb format.
Returns
----------
doc : str
Cleaned up docstring.
"""
source = loaded["cells"][0]["source"]
assert source[0].strip() == '"""'
assert source[-1].strip() == '"""'
return " ".join(i.strip() for i in source[1:-1])
base = """
{title} </{file_name}.html>
"""
def generate_index(source: str, target: str) -> str:
"""
Go through a directory of source `ipynb` files and write
an RST index with a toctree.
Also postprocesses the results of `jupyter nbconvert`
"""
lines = [
"Examples",
"===========",
"Several examples are available as rendered IPython notebooks.",
"",
".. toctree::",
" :maxdepth: 2",
"",
]
target_dir = os.path.dirname(target)
for fn in os.listdir(source):
if not fn.lower().endswith(".ipynb"):
continue
name = fn.rsplit(".")[0]
title = name.replace("_", " ").title()
# notebook converted to RST
convert = os.path.join(target_dir, f"{name}.rst")
if not os.path.exists(convert):
print(f"no RST for {name}.rst")
continue
with open(convert) as f:
doc, post = postprocess(f.read(), title=title)
with open(convert, "w") as f:
f.write(post)
lines.append(f" {name}")
# lines.append(doc)
lines.append("")
return "\n".join(lines)
def postprocess(text: str, title: str) -> str:
"""
Postprocess an RST generated from `jupyter nbconvert`
"""
lines = str.splitlines(text)
# already has a title so exit
if "===" in "".join(lines[:4]):
return "", text
head = []
index = 0
ready = False
for i, L in enumerate(lines):
if "parsed-literal" in L:
ready = True
continue
if ready:
if "code::" in L:
index = i
break
else:
head.append(L)
# clean up the "parsed literal"
docstring = (
" ".join(" ".join(head).replace("\\n", " ").split()).strip().strip("'").strip()
)
# add a title and the docstring as a header
clip = f"{title}\n=============\n{docstring}\n\n" + "\n".join(lines[index:])
return docstring, clip
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument(
"--source", type=str, help="a directory containing `ipynb` files", required=True
)
parser.add_argument(
"--target", type=str, help="Where the generated .rst file goes", required=True
)
args = parser.parse_args()
source = os.path.abspath(args.source)
target = os.path.abspath(args.target)
with open(target, "w") as f:
f.write(generate_index(source=source, target=target))
|