##// END OF EJS Templates
Add argument parsing, and ability to convert an HTML file from command line
Add argument parsing, and ability to convert an HTML file from command line

File last commit:

r6261:0e8f2cf0
r6261:0e8f2cf0
Show More
nbconvert.py
270 lines | 7.7 KiB | text/x-python | PythonLexer
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220 #!/usr/bin/env python
"""A really simple notebook to rst/html exporter.
Usage
./nb2html.py file.ipynb
Produces 'file.rst' and 'file.html', along with auto-generated figure files
called nb_figure_NN.png.
"""
import os
import subprocess
import sys
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261 import argparse
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220 from IPython.nbformat import current as nbformat
Paul Ivanov
remove unused import
r6257 from IPython.utils.text import indent
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
# Cell converters
def unknown_cell(cell):
"""Default converter for cells of unknown type.
"""
Fernando Perez
improve rst_directive and fix bug in unknown_cell
r6222 return rst_directive('.. warning:: Unknown cell') + \
[repr(cell)]
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Fernando Perez
improve rst_directive and fix bug in unknown_cell
r6222 def rst_directive(directive, text=''):
out = [directive, '']
if text:
out.extend([indent(text), ''])
return out
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
# Converters for parts of a cell.
Anton I. Sipos
PEP 8 fixes.
r6253
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 class ConversionException(Exception):
pass
Anton I. Sipos
PEP 8 fixes.
r6253
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 class Converter(object):
default_encoding = 'utf-8'
Anton I. Sipos
PEP 8 fixes.
r6253
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261 def __init__(self, infile):
self.infile = infile
self.dirpath = os.path.dirname(infile)
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239
@property
def extension(self):
raise ConversionException("""extension must be defined in Converter
subclass""")
Anton I. Sipos
PEP 8 fixes.
r6253 def dispatch(self, cell_type):
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 """return cell_type dependent render method, for example render_code
"""
Anton I. Sipos
PEP 8 fixes.
r6253 return getattr(self, 'render_' + cell_type, unknown_cell)
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239
def convert(self):
lines = []
for cell in self.nb.worksheets[0].cells:
conv_fn = self.dispatch(cell.cell_type)
lines.extend(conv_fn(cell))
lines.append('')
return '\n'.join(lines)
def render(self):
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261 "read, convert, and save self.infile"
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 self.read()
self.output = self.convert()
return self.save()
def read(self):
"read and parse notebook into NotebookNode called self.nb"
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261 with open(self.infile) as f:
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 self.nb = nbformat.read(f, 'json')
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261 def save(self, infile=None, encoding=None):
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 "read and parse notebook into self.nb"
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261 if infile is None:
infile = os.path.splitext(self.infile)[0] + '.' + self.extension
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 if encoding is None:
encoding = self.default_encoding
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261 with open(infile, 'w') as f:
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 f.write(self.output.encode(encoding))
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261 return infile
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Anton I. Sipos
PEP 8 fixes.
r6253 def render_heading(self, cell):
raise NotImplementedError
def render_code(self, cell):
raise NotImplementedError
Paul Ivanov
added stream cells for stdin and stdout
r6249
Anton I. Sipos
PEP 8 fixes.
r6253 def render_markdown(self, cell):
raise NotImplementedError
Paul Ivanov
added stream cells for stdin and stdout
r6249
Anton I. Sipos
PEP 8 fixes.
r6253 def render_pyout(self, cell):
raise NotImplementedError
Paul Ivanov
added stream cells for stdin and stdout
r6249
Anton I. Sipos
PEP 8 fixes.
r6253 def render_display_data(self, cell):
raise NotImplementedError
Paul Ivanov
added stream cells for stdin and stdout
r6249
Anton I. Sipos
PEP 8 fixes.
r6253 def render_stream(self, cell):
raise NotImplementedError
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Paul Ivanov
added stream cells for stdin and stdout
r6249
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 class ConverterRST(Converter):
extension = 'rst'
Paul Ivanov
figures_counter no longer global
r6254 figures_counter = 0
Anton I. Sipos
PEP 8 fixes.
r6253
def render_heading(self, cell):
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 """convert a heading cell to rst
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 Returns list."""
Anton I. Sipos
PEP 8 fixes.
r6253 heading_level = {1: '=', 2: '-', 3: '`', 4: '\'', 5: '.', 6: '~'}
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 marker = heading_level[cell.level]
Anton I. Sipos
PEP 8 fixes.
r6253 return ['{0}\n{1}\n'.format(cell.source, marker * len(cell.source))]
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Anton I. Sipos
PEP 8 fixes.
r6253 def render_code(self, cell):
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 """Convert a code cell to rst
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 Returns list."""
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 if not cell.input:
return []
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 lines = ['In[%s]:' % cell.prompt_number, '']
lines.extend(rst_directive('.. code:: python', cell.input))
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 for output in cell.outputs:
conv_fn = self.dispatch(output.output_type)
lines.extend(conv_fn(output))
Paul Ivanov
figures_counter no longer global
r6254
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 return lines
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Anton I. Sipos
PEP 8 fixes.
r6253 def render_markdown(self, cell):
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 """convert a markdown cell to rst
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 Returns list."""
return [cell.source]
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Anton I. Sipos
Add a plain text cell renderer.
r6256 def render_plaintext(self, cell):
"""convert plain text to rst
Returns list."""
return [cell.source]
Anton I. Sipos
PEP 8 fixes.
r6253 def render_pyout(self, output):
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 """convert pyout part of a code cell to rst
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 Returns list."""
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 lines = ['Out[%s]:' % output.prompt_number, '']
Paul Ivanov
added stream cells for stdin and stdout
r6249
Anton I. Sipos
Fix main() function to use new object based converters, and add a test
r6252 # output is a dictionary like object with type as a key
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 if 'latex' in output:
lines.extend(rst_directive('.. math::', output.latex))
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 if 'text' in output:
lines.extend(rst_directive('.. parsed-literal::', output.text))
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 return lines
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Anton I. Sipos
PEP 8 fixes.
r6253 def render_display_data(self, output):
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 """convert display data from the output of a code cell to rst.
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 Returns list.
"""
lines = []
if 'png' in output:
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261 infile = 'nb_figure_%s.png' % self.figures_counter
fullname = os.path.join(self.dirpath, infile)
Paul Ivanov
figures_counter no longer global
r6254 with open(fullname, 'w') as f:
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 f.write(output.png.decode('base64'))
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Paul Ivanov
figures_counter no longer global
r6254 self.figures_counter += 1
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261 lines.append('.. image:: %s' % infile)
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 lines.append('')
Paul Ivanov
added stream cells for stdin and stdout
r6249
return lines
Anton I. Sipos
PEP 8 fixes.
r6253 def render_stream(self, output):
Paul Ivanov
added stream cells for stdin and stdout
r6249 """convert stream part of a code cell to rst
Returns list."""
lines = []
if 'text' in output:
lines.extend(rst_directive('.. parsed-literal::', output.text))
Paul Ivanov
refactored nbconvert, nosetest pass...
r6239 return lines
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
Anton I. Sipos
PEP 8 fixes.
r6253
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261 def rst2simplehtml(infile):
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220 """Convert a rst file to simplified html suitable for blogger.
This just runs rst2html with certain parameters to produce really simple
html and strips the document header, so the resulting file can be easily
pasted into a blogger edit window.
"""
# This is the template for the rst2html call that produces the cleanest,
# simplest html I could find. This should help in making it easier to
# paste into the blogspot html window, though I'm still having problems
# with linebreaks there...
smithj1
Reverted call to "rst2html.py" to "rst2html".
r6229 cmd_template = ("rst2html --link-stylesheet --no-xml-declaration "
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220 "--no-generator --no-datestamp --no-source-link "
"--no-toc-backlinks --no-section-numbering "
"--strip-comments ")
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261 cmd = "%s %s" % (cmd_template, infile)
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220 proc = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True)
html, stderr = proc.communicate()
if stderr:
raise IOError(stderr)
# Make an iterator so breaking out holds state. Our implementation of
# searching for the html body below is basically a trivial little state
# machine, so we need this.
walker = iter(html.splitlines())
# Find start of main text, break out to then print until we find end /div.
# This may only work if there's a real title defined so we get a 'div class'
# tag, I haven't really tried.
for line in walker:
smithj1
Added heading cell converter. Also changed the down-parser for output to html (from looking for <div> and </div> to <body> and </body>.
r6228 if line.startswith('<body>'):
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220 break
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261 newfname = os.path.splitext(infile)[0] + '.html'
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220 with open(newfname, 'w') as f:
for line in walker:
smithj1
Added heading cell converter. Also changed the down-parser for output to html (from looking for <div> and </div> to <body> and </body>.
r6228 if line.startswith('</body>'):
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220 break
f.write(line)
f.write('\n')
Anton I. Sipos
PEP 8 fixes.
r6253
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220 return newfname
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261 def main(infile, format='rst'):
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220 """Convert a notebook to html in one step"""
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261 if format == 'rst':
converter = ConverterRST(infile)
converter.render()
elif format == 'html':
#Currently, conversion to html is a 2 step process, nb->rst->html
converter = ConverterRST(infile)
rstfname = converter.render()
rst2simplehtml(rstfname)
Fernando Perez
Initial checkin - note that in this state, it's producing an ipython...
r6220
if __name__ == '__main__':
Anton I. Sipos
Add argument parsing, and ability to convert an HTML file from command line
r6261 parser = argparse.ArgumentParser(description='nbconvert: Convert IPython notebooks to other formats')
# TODO: consider passing file like object around, rather than filenames
# would allow us to process stdin, or even http streams
#parser.add_argument('infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin)
#Require a filename as a positional argument
parser.add_argument('infile', nargs=1)
parser.add_argument('-f', '--format', default='rst')
args = parser.parse_args()
main(infile=args.infile[0], format=args.format)