# -*- coding: utf-8 -*-
"""
Utilities for IPython/Jupyter Notebooks
CommandLine:
# to connect to a notebook on a remote machine that does not have the
# appropriate port exposed you must start an SSH tunnel.
# Typically a jupyter-notebook runs on port 8888.
# Run this command on your local machine.
ssh -N -f -L localhost:8888:localhost:8889 <remote_user>@<remote_host>
"""
from __future__ import absolute_import, division, print_function, unicode_literals
import sys
from utool import util_inject
from collections import namedtuple
print, rrr, profile = util_inject.inject2(__name__)
IPYNBCell = namedtuple('IPYNBCell', ['header', 'code', 'footer'])
[docs]def make_autogen_str():
r"""
Returns:
str:
CommandLine:
python -m utool.util_ipynb --exec-make_autogen_str --show
Example:
>>> # DISABLE_DOCTEST
>>> from utool.util_ipynb import * # NOQA
>>> import utool as ut
>>> result = make_autogen_str()
>>> print(result)
"""
import utool as ut
def get_regen_cmd():
try:
if len(sys.argv) > 0 and ut.checkpath(sys.argv[0]):
# Check if running python command
if ut.is_python_module(sys.argv[0]):
python_exe = ut.python_executable(check=False)
modname = ut.get_modname_from_modpath(sys.argv[0])
new_argv = [python_exe, '-m', modname] + sys.argv[1:]
return ' '.join(new_argv)
except Exception as ex:
ut.printex(ex, iswarning=True)
return ' '.join(sys.argv)
autogenkw = dict(
stamp=ut.timestamp('printable'),
regen_cmd=get_regen_cmd()
#' '.join(sys.argv)
)
return ut.codeblock(
"""
# Autogenerated on {stamp}
# Regen Command:
# {regen_cmd}
#
"""
).format(**autogenkw)
[docs]def export_notebook(run_nb, fname):
import IPython.nbconvert.exporters
import codecs
# exporter = IPython.nbconvert.exporters.PDFExporter()
exporter = IPython.nbconvert.exporters.HTMLExporter()
output, resources = exporter.from_notebook_node(run_nb)
ext = resources['output_extension']
output_fpath = fname + ext
# codecs.open(output_fname, 'w', encoding='utf-8').write(output)
codecs.open(output_fpath, 'w').write(output)
return output_fpath
# IPython.nbconvert.exporters.export_python(runner.nb)
[docs]def run_ipython_notebook(notebook_str):
"""
References:
https://github.com/paulgb/runipy
>>> from utool.util_ipynb import * # NOQA
"""
from runipy.notebook_runner import NotebookRunner
import nbformat
import logging
log_format = '%(asctime)s %(levelname)s: %(message)s'
log_datefmt = '%m/%d/%Y %I:%M:%S %p'
logging.basicConfig(level=logging.INFO, format=log_format, datefmt=log_datefmt)
# fpath = 'tmp.ipynb'
# notebook_str = ut.readfrom(fpath)
# nb3 = IPython.nbformat.reads(notebook_str, 3)
# cell = nb4.cells[1]
# self = runner
# runner = NotebookRunner(nb3, mpl_inline=True)
print('Executing IPython notebook')
nb4 = nbformat.reads(notebook_str, 4)
runner = NotebookRunner(nb4)
runner.run_notebook(skip_exceptions=False)
run_nb = runner.nb
return run_nb
[docs]def normalize_cells(block):
if isinstance(block, (tuple, list)):
if len(block) == 2:
header, code = block
footer = None
elif len(block) == 3:
header, code, footer = block
else:
assert False
else:
header = None
footer = None
code = block
return IPYNBCell(header, code, footer)
[docs]def code_cell(sourcecode):
r"""
Args:
sourcecode (str):
Returns:
str: json formatted ipython notebook code cell
CommandLine:
python -m wbia.templates.generate_notebook --exec-code_cell
Example:
>>> # DISABLE_DOCTEST
>>> from wbia.templates.generate_notebook import * # NOQA
>>> sourcecode = notebook_cells.timestamp_distribution[1]
>>> sourcecode = notebook_cells.initialize[1]
>>> result = code_cell(sourcecode)
>>> print(result)
"""
import utool as ut
sourcecode = ut.remove_codeblock_syntax_sentinals(sourcecode)
cell_header = ut.codeblock(
"""
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source":
"""
)
cell_footer = ut.codeblock(
"""
}
"""
)
if sourcecode is None:
source_line_repr = ' []\n'
else:
lines = sourcecode.split('\n')
line_list = [
line + '\n' if count < len(lines) else line
for count, line in enumerate(lines, start=1)
]
# repr_line_list = [repr_single_for_md(line) for line in line_list]
repr_line_list = [repr_single_for_md(line) for line in line_list]
source_line_repr = ut.indent(',\n'.join(repr_line_list), ' ' * 2)
source_line_repr = ' [\n' + source_line_repr + '\n ]\n'
return cell_header + source_line_repr + cell_footer
[docs]def markdown_cell(markdown):
r"""
Args:
markdown (str):
Returns:
str: json formatted ipython notebook markdown cell
CommandLine:
python -m wbia.templates.generate_notebook --exec-markdown_cell
Example:
>>> # DISABLE_DOCTEST
>>> from wbia.templates.generate_notebook import * # NOQA
>>> markdown = '# Title'
>>> result = markdown_cell(markdown)
>>> print(result)
"""
import utool as ut
markdown_header = ut.codeblock(
"""
{
"cell_type": "markdown",
"metadata": {},
"source": [
"""
)
markdown_footer = ut.codeblock(
"""
]
}
"""
)
return (
markdown_header
+ '\n'
+ ut.indent(repr_single_for_md(markdown), ' ' * 2)
+ '\n'
+ markdown_footer
)
[docs]def make_notebook(cell_list):
"""
References:
# Change cell width
http://stackoverflow.com/questions/21971449/how-do-i-increase-the-cell-width-of-the-ipython-notebook-in-my-browser/24207353#24207353
"""
import utool as ut
header = ut.codeblock(
"""
{
"cells": [
"""
)
footer = ut.codeblock(
"""
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
"""
)
cell_body = ut.indent(',\n'.join(cell_list), ' ')
notebook_str = header + '\n' + cell_body + '\n' + footer
try:
import json
json.loads(notebook_str)
except ValueError as ex:
ut.printex(ex, 'Invalid notebook JSON')
raise
return notebook_str
[docs]def repr_single_for_md(s):
r"""
Args:
s (str):
Returns:
str: str_repr
CommandLine:
python -m wbia.templates.generate_notebook --exec-repr_single_for_md --show
Example:
>>> # DISABLE_DOCTEST
>>> from wbia.templates.generate_notebook import * # NOQA
>>> s = '#HTML(\'<iframe src="%s" width=700 height=350></iframe>\' % pdf_fpath)'
>>> result = repr_single_for_md(s)
>>> print(result)
"""
import utool as ut
if True:
str_repr = ut.reprfunc(s)
import re
if str_repr.startswith("'"):
dq = ut.DOUBLE_QUOTE
sq = ut.SINGLE_QUOTE
bs = ut.BACKSLASH
dq_, sq_, bs_ = list(map(re.escape, [dq, sq, bs]))
no_bs = ut.negative_lookbehind(bs_)
# no_sq = ut.negative_lookbehind(sq)
# no_dq = ut.negative_lookbehind(dq)
# inside = str_repr[1:-1]
# inside = re.sub(no_bs + dq, bs + dq, inside)
# inside = re.sub(no_bs + bs + sq, r"\\'", r"'", inside)
# str_repr = '"' + inside + '"'
# inside = re.sub(r'"', r'\\"', inside)
# inside = re.sub(ut.negative_lookbehind(r"'") + r"\\'", r"'", inside)
inside = str_repr[1:-1]
# Escape double quotes
inside = re.sub(no_bs + r'"', r'\\"', inside)
# Unescape single quotes
inside = re.sub(no_bs + bs_ + r"'", r"'", inside)
# Append external double quotes
str_repr = '"' + inside + '"'
return str_repr
else:
return '"' + ut.reprfunc("'" + s)[2:]
if __name__ == '__main__':
r"""
CommandLine:
python -m utool.util_ipynb
python -m utool.util_ipynb --allexamples
"""
import multiprocessing
multiprocessing.freeze_support() # for win32
import utool as ut # NOQA
ut.doctest_funcs()