Skip to content

Commit 88f5851

Browse files
DOC: Use nbsphinx for notebook doc build (#15581)
Adds a new doc-dependency nbsphinx for converting jupyter notebooks to ReST, which works better with the sphinx conversion process. Remvoes the hacky notebook -> HTML -> raw include we had before.
1 parent 84de51c commit 88f5851

File tree

10 files changed

+118
-174
lines changed

10 files changed

+118
-174
lines changed

ci/requirements-3.5_DOC.run

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ nbconvert
55
nbformat
66
notebook
77
matplotlib
8+
seaborn
89
scipy
910
lxml
1011
beautifulsoup4

ci/requirements-3.5_DOC.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ echo "[install DOC_BUILD deps]"
66

77
pip install pandas-gbq
88

9-
conda install -n pandas -c conda-forge feather-format
9+
conda install -n pandas -c conda-forge feather-format nbsphinx pandoc
1010

1111
conda install -n pandas -c r r rpy2 --yes

ci/requirements_all.txt

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pytest-cov
33
pytest-xdist
44
flake8
55
sphinx
6+
nbsphinx
67
ipython
78
python-dateutil
89
pytz
@@ -19,6 +20,7 @@ scipy
1920
numexpr
2021
pytables
2122
matplotlib
23+
seaborn
2224
lxml
2325
sqlalchemy
2426
bottleneck

doc/README.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ have ``sphinx`` and ``ipython`` installed. `numpydoc
8181
<https://github.com/numpy/numpydoc>`_ is used to parse the docstrings that
8282
follow the Numpy Docstring Standard (see above), but you don't need to install
8383
this because a local copy of ``numpydoc`` is included in the pandas source
84-
code.
84+
code. `nbsphinx <https://nbsphinx.readthedocs.io/>`_ is used to convert
85+
Jupyter notebooks. You will need to install it if you intend to modify any of
86+
the notebooks included in the documentation.
8587

8688
Furthermore, it is recommended to have all `optional dependencies
8789
<http://pandas.pydata.org/pandas-docs/dev/install.html#optional-dependencies>`_

doc/make.py

+29-93
Original file line numberDiff line numberDiff line change
@@ -106,106 +106,42 @@ def clean():
106106

107107

108108
@contextmanager
109-
def cleanup_nb(nb):
110-
try:
111-
yield
112-
finally:
113-
try:
114-
os.remove(nb + '.executed')
115-
except OSError:
116-
pass
117-
118-
119-
def get_kernel():
120-
"""Find the kernel name for your python version"""
121-
return 'python%s' % sys.version_info.major
122-
123-
124-
def execute_nb(src, dst, allow_errors=False, timeout=1000, kernel_name=''):
125-
"""
126-
Execute notebook in `src` and write the output to `dst`
127-
128-
Parameters
129-
----------
130-
src, dst: str
131-
path to notebook
132-
allow_errors: bool
133-
timeout: int
134-
kernel_name: str
135-
defualts to value set in notebook metadata
136-
137-
Returns
138-
-------
139-
dst: str
140-
"""
141-
import nbformat
142-
from nbconvert.preprocessors import ExecutePreprocessor
143-
144-
with io.open(src, encoding='utf-8') as f:
145-
nb = nbformat.read(f, as_version=4)
146-
147-
ep = ExecutePreprocessor(allow_errors=allow_errors,
148-
timeout=timeout,
149-
kernel_name=kernel_name)
150-
ep.preprocess(nb, resources={})
151-
152-
with io.open(dst, 'wt', encoding='utf-8') as f:
153-
nbformat.write(nb, f)
154-
return dst
155-
156-
157-
def convert_nb(src, dst, to='html', template_file='basic'):
109+
def maybe_exclude_notebooks():
158110
"""
159-
Convert a notebook `src`.
160-
161-
Parameters
162-
----------
163-
src, dst: str
164-
filepaths
165-
to: {'rst', 'html'}
166-
format to export to
167-
template_file: str
168-
name of template file to use. Default 'basic'
111+
Skip building the notebooks if pandoc is not installed.
112+
This assumes that nbsphinx is installed.
169113
"""
170-
from nbconvert import HTMLExporter, RSTExporter
171-
172-
dispatch = {'rst': RSTExporter, 'html': HTMLExporter}
173-
exporter = dispatch[to.lower()](template_file=template_file)
174-
175-
(body, resources) = exporter.from_filename(src)
176-
with io.open(dst, 'wt', encoding='utf-8') as f:
177-
f.write(body)
178-
return dst
114+
base = os.path.dirname(__file__)
115+
notebooks = [os.path.join(base, 'source', nb)
116+
for nb in ['style.ipynb']]
117+
contents = {}
118+
try:
119+
import nbconvert
120+
nbconvert.utils.pandoc.get_pandoc_version()
121+
except (ImportError, nbconvert.utils.pandoc.PandocMissing):
122+
print("Warning: Pandoc is not installed. Skipping Notebooks.")
123+
for nb in notebooks:
124+
with open(nb, 'rt') as f:
125+
contents[nb] = f.read()
126+
os.remove(nb)
127+
yield
128+
for nb, content in contents.items():
129+
with open(nb, 'wt') as f:
130+
f.write(content)
179131

180132

181133
def html():
182134
check_build()
183135

184-
notebooks = [
185-
'source/html-styling.ipynb',
186-
]
187-
188-
for nb in notebooks:
189-
with cleanup_nb(nb):
190-
try:
191-
print("Converting %s" % nb)
192-
kernel_name = get_kernel()
193-
executed = execute_nb(nb, nb + '.executed', allow_errors=True,
194-
kernel_name=kernel_name)
195-
convert_nb(executed, nb.rstrip('.ipynb') + '.html')
196-
except (ImportError, IndexError) as e:
197-
print(e)
198-
print("Failed to convert %s" % nb)
199-
200-
if os.system('sphinx-build -P -b html -d build/doctrees '
201-
'source build/html'):
202-
raise SystemExit("Building HTML failed.")
203-
try:
204-
# remove stale file
205-
os.remove('source/html-styling.html')
206-
os.remove('build/html/pandas.zip')
207-
except:
208-
pass
136+
with maybe_exclude_notebooks():
137+
if os.system('sphinx-build -P -b html -d build/doctrees '
138+
'source build/html'):
139+
raise SystemExit("Building HTML failed.")
140+
try:
141+
# remove stale file
142+
os.remove('build/html/pandas.zip')
143+
except:
144+
pass
209145

210146

211147
def zip_html():

doc/source/conf.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,16 @@
5252
'numpydoc', # used to parse numpy-style docstrings for autodoc
5353
'ipython_sphinxext.ipython_directive',
5454
'ipython_sphinxext.ipython_console_highlighting',
55+
'IPython.sphinxext.ipython_console_highlighting', # lowercase didn't work
5556
'sphinx.ext.intersphinx',
5657
'sphinx.ext.coverage',
5758
'sphinx.ext.mathjax',
5859
'sphinx.ext.ifconfig',
5960
'sphinx.ext.linkcode',
61+
'nbsphinx',
6062
]
6163

62-
64+
exclude_patterns = ['**.ipynb_checkpoints']
6365

6466
with open("index.rst") as f:
6567
index_rst_lines = f.readlines()
@@ -70,15 +72,16 @@
7072
# JP: added from sphinxdocs
7173
autosummary_generate = False
7274

73-
if any([re.match("\s*api\s*",l) for l in index_rst_lines]):
75+
if any([re.match("\s*api\s*", l) for l in index_rst_lines]):
7476
autosummary_generate = True
7577

7678
files_to_delete = []
7779
for f in os.listdir(os.path.dirname(__file__)):
78-
if not f.endswith('.rst') or f.startswith('.') or os.path.basename(f) == 'index.rst':
80+
if (not f.endswith(('.ipynb', '.rst')) or
81+
f.startswith('.') or os.path.basename(f) == 'index.rst'):
7982
continue
8083

81-
_file_basename = f.split('.rst')[0]
84+
_file_basename = os.path.splitext(f)[0]
8285
_regex_to_match = "\s*{}\s*$".format(_file_basename)
8386
if not any([re.match(_regex_to_match, line) for line in index_rst_lines]):
8487
files_to_delete.append(f)
@@ -261,6 +264,9 @@
261264
# Output file base name for HTML help builder.
262265
htmlhelp_basename = 'pandas'
263266

267+
# -- Options for nbsphinx ------------------------------------------------
268+
269+
nbsphinx_allow_errors = True
264270

265271
# -- Options for LaTeX output --------------------------------------------
266272

doc/source/contributing.rst

+2-3
Original file line numberDiff line numberDiff line change
@@ -347,15 +347,14 @@ have ``sphinx`` and ``ipython`` installed. `numpydoc
347347
<https://github.com/numpy/numpydoc>`_ is used to parse the docstrings that
348348
follow the Numpy Docstring Standard (see above), but you don't need to install
349349
this because a local copy of numpydoc is included in the *pandas* source
350-
code.
351-
`nbconvert <https://nbconvert.readthedocs.io/en/latest/>`_ and
352-
`nbformat <https://nbformat.readthedocs.io/en/latest/>`_ are required to build
350+
code. `nbsphinx <https://nbsphinx.readthedocs.io/>`_ is required to build
353351
the Jupyter notebooks included in the documentation.
354352

355353
If you have a conda environment named ``pandas_dev``, you can install the extra
356354
requirements with::
357355

358356
conda install -n pandas_dev sphinx ipython nbconvert nbformat
357+
conda install -n pandas_dev -c conda-forge nbsphinx
359358

360359
Furthermore, it is recommended to have all :ref:`optional dependencies <install.optional_dependencies>`.
361360
installed. This is not strictly necessary, but be aware that you will see some error

0 commit comments

Comments
 (0)