##// END OF EJS Templates
pretransformer configurables
pretransformer configurables

File last commit:

r9619:656282c8
r9619:656282c8
Show More
template.py
301 lines | 9.2 KiB | text/x-python | PythonLexer
Matthias BUSSONNIER
starting templates
r9578 """Base classes for the notebook conversion pipeline.
This module defines Converter, from which all objects designed to implement
a conversion of IPython notebooks to some other format should inherit.
"""
#-----------------------------------------------------------------------------
# Copyright (c) 2012, the IPython Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
from __future__ import print_function, absolute_import
# Stdlib imports
import io
import os
Matthias BUSSONNIER
multiple env
r9609 import re
Matthias BUSSONNIER
read css from ipython dir
r9593 from IPython.utils import path
Matthias BUSSONNIER
starting templates
r9578
Matthias BUSSONNIER
remove and clean code
r9602 from jinja2 import Environment, FileSystemLoader
Matthias BUSSONNIER
try to play with data display priority
r9599 env = Environment(
Matthias BUSSONNIER
Start to organize template folder
r9616 loader=FileSystemLoader([
'./templates/',
'./templates/skeleton/',
]),
Matthias BUSSONNIER
try to play with data display priority
r9599 extensions=['jinja2.ext.loopcontrols']
)
Matthias BUSSONNIER
starting templates
r9578
Matthias BUSSONNIER
multiple env
r9609 texenv = Environment(
Matthias BUSSONNIER
Start to organize template folder
r9616 loader=FileSystemLoader([
'./templates/tex/',
'./templates/skeleton/tex/',
]),
Matthias BUSSONNIER
multiple env
r9609 extensions=['jinja2.ext.loopcontrols']
)
Matthias BUSSONNIER
starting templates
r9578 # IPython imports
from IPython.nbformat import current as nbformat
Matthias BUSSONNIER
remove and clean code
r9602 from IPython.config.configurable import Configurable
Matthias BUSSONNIER
flag for extracting figure
r9615 from IPython.utils.traitlets import ( Unicode, Any, List, Bool)
Matthias BUSSONNIER
starting templates
r9578
# Our own imports
from IPython.utils.text import indent
from .utils import remove_ansi
Matthias BUSSONNIER
null template
r9580 from markdown import markdown
Matthias BUSSONNIER
remove and clean code
r9602 from .utils import highlight, ansi2html
Matthias BUSSONNIER
start tex template
r9610 from .utils import markdown2latex
Matthias BUSSONNIER
starting templates
r9578 #-----------------------------------------------------------------------------
# Class declarations
#-----------------------------------------------------------------------------
def rm_fake(strng):
return strng.replace('/files/', '')
class ConversionException(Exception):
pass
def python_comment(string):
return '# '+'\n# '.join(string.split('\n'))
Matthias BUSSONNIER
read css from ipython dir
r9593
def header_body():
Matthias BUSSONNIER
remove and clean code
r9602 """Return the body of the header as a list of strings."""
from pygments.formatters import HtmlFormatter
header = []
static = os.path.join(path.get_ipython_package_dir(),
'frontend', 'html', 'notebook', 'static',
)
here = os.path.split(os.path.realpath(__file__))[0]
css = os.path.join(static, 'css')
for sheet in [
# do we need jquery and prettify?
# os.path.join(static, 'jquery', 'css', 'themes', 'base',
# 'jquery-ui.min.css'),
# os.path.join(static, 'prettify', 'prettify.css'),
os.path.join(css, 'boilerplate.css'),
os.path.join(css, 'fbm.css'),
os.path.join(css, 'notebook.css'),
os.path.join(css, 'renderedhtml.css'),
# our overrides:
os.path.join(here, '..', 'css', 'static_html.css'),
]:
with io.open(sheet, encoding='utf-8') as f:
s = f.read()
header.append(s)
pygments_css = HtmlFormatter().get_style_defs('.highlight')
header.append(pygments_css)
return header
Matthias BUSSONNIER
some improvement
r9614 # todo, make the key part configurable.
Matthias BUSSONNIER
test_file extractor
r9613 def _new_figure(data, fmt, count):
"""Create a new figure file in the given format.
Returns a path relative to the input file.
"""
figname = '_fig_%02i.%s' % (count, fmt)
# Binary files are base64-encoded, SVG is already XML
if fmt in ('png', 'jpg', 'pdf'):
data = data.decode('base64')
return figname,data
Matthias BUSSONNIER
remove and clean code
r9602 inlining = {}
Matthias BUSSONNIER
modularize inlining
r9598 inlining['css'] = header_body()
Matthias BUSSONNIER
read css from ipython dir
r9593
Matthias BUSSONNIER
multiple env
r9609 LATEX_SUBS = (
(re.compile(r'\\'), r'\\textbackslash'),
(re.compile(r'([{}_#%&$])'), r'\\\1'),
(re.compile(r'~'), r'\~{}'),
(re.compile(r'\^'), r'\^{}'),
(re.compile(r'"'), r"''"),
(re.compile(r'\.\.\.+'), r'\\ldots'),
)
def escape_tex(value):
newval = value
for pattern, replacement in LATEX_SUBS:
newval = pattern.sub(replacement, newval)
return newval
texenv.block_start_string = '((*'
texenv.block_end_string = '*))'
texenv.variable_start_string = '((('
texenv.variable_end_string = ')))'
texenv.comment_start_string = '((='
texenv.comment_end_string = '=))'
texenv.filters['escape_tex'] = escape_tex
Matthias BUSSONNIER
some improvement
r9614 def cell_preprocessor(function):
""" wrap a function to be executed on all cells of a notebook
wrapped function parameters :
cell : the cell
other : external resources
index : index of the cell
"""
def wrappedfunc(nb,other):
for worksheet in nb.worksheets :
for index, cell in enumerate(worksheet.cells):
worksheet.cells[index],other= function(cell,other,index)
return nb,other
return wrappedfunc
@cell_preprocessor
def haspyout_transformer(cell, other, count):
"""
Add a haspyout flag to cell that have it
Easier for templating, where you can't know in advance
wether to write the out prompt
Matthias BUSSONNIER
test_file extractor
r9613
Matthias BUSSONNIER
some improvement
r9614 """
cell.type = cell.cell_type
cell.haspyout = False
for out in cell.get('outputs', []):
if out.output_type == 'pyout':
cell.haspyout = True
break
return cell,other
@cell_preprocessor
Matthias BUSSONNIER
flag for extracting figure
r9615 def extract_figure_transformer(cell,other,count):
Matthias BUSSONNIER
some improvement
r9614 for i,out in enumerate(cell.get('outputs', [])):
for type in ['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg']:
if out.hasattr(type):
figname,data = _new_figure(out[type], type,count)
cell.outputs[i][type] = figname
out['key_'+type] = figname
other[figname] = data
count = count+1
Matthias BUSSONNIER
flag for extracting figure
r9615 return cell,other
Matthias BUSSONNIER
preprocessing and namespace fix...
r9604
Matthias BUSSONNIER
some improvement
r9614
Matthias BUSSONNIER
starting templates
r9578 class ConverterTemplate(Configurable):
Matthias BUSSONNIER
add docstring
r9607 """ A Jinja2 base converter templates"""
Matthias BUSSONNIER
starting templates
r9578
Matthias BUSSONNIER
lots of modification for latex
r9611 display_data_priority = List(['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg' , 'text'],
config=True,
help= """
Matthias BUSSONNIER
pretransformer configurables
r9619 An ordered list of prefered output type, the firs encounterd will usually be
used when converting discarding the others.
"""
)
pre_transformer_order = List([],
config=True,
help= """ An ordered list of pretransformer to apply to the ipynb file befor running through templates
Matthias BUSSONNIER
lots of modification for latex
r9611 """
)
Matthias BUSSONNIER
some improvement
r9614
extract_figures = Bool(False,
config=True,
help= """
wether to remove figure data from ipynb and store them in auxiliary
dictionnary
"""
)
Matthias BUSSONNIER
use configuration file to do nice stuff
r9618
tex_environement = Bool(False,
config=True,
help=""" is this a tex environment or not """)
template_file = Unicode('',
config=True,
help=""" whetever """ )
Matthias BUSSONNIER
starting templates
r9578 #-------------------------------------------------------------------------
# Instance-level attributes that are set in the constructor for this
# class.
#-------------------------------------------------------------------------
infile = Any()
Matthias BUSSONNIER
deal with worksheets
r9585
Matthias BUSSONNIER
starting templates
r9578 infile_dir = Unicode()
Matthias BUSSONNIER
lots of modification for latex
r9611
def filter_data_type(self,output):
for fmt in self.display_data_priority:
if fmt in output:
return [fmt]
Matthias BUSSONNIER
starting templates
r9578
Matthias BUSSONNIER
use configuration file to do nice stuff
r9618 def __init__(self, preprocessors=[], config=None, **kw):
Matthias BUSSONNIER
add possibility to preprocess ipynb files
r9603 """
Matthias BUSSONNIER
add docstring
r9607 tplfile : jinja template file to process.
Matthias BUSSONNIER
add possibility to preprocess ipynb files
r9603
Matthias BUSSONNIER
add docstring
r9607 config: the Configurable confg object to pass around
Matthias BUSSONNIER
add possibility to preprocess ipynb files
r9603
Matthias BUSSONNIER
add docstring
r9607 preprocessors: list of function to run on ipynb json data before conversion
to extract/inline file,
Matthias BUSSONNIER
add possibility to preprocess ipynb files
r9603
"""
Matthias BUSSONNIER
flag for extracting figure
r9615 super(ConverterTemplate, self).__init__(config=config, **kw)
Matthias BUSSONNIER
use configuration file to do nice stuff
r9618 self.env = texenv if self.tex_environement else env
self.ext = '.tplx' if self.tex_environement else '.tpl'
Matthias BUSSONNIER
remove and clean code
r9602 self.nb = None
Matthias BUSSONNIER
add possibility to preprocess ipynb files
r9603 self.preprocessors = preprocessors
Matthias BUSSONNIER
preprocessing and namespace fix...
r9604 self.preprocessors.append(haspyout_transformer)
Matthias BUSSONNIER
flag for extracting figure
r9615 if self.extract_figures:
self.preprocessors.append(extract_figure_transformer)
Matthias BUSSONNIER
lots of modification for latex
r9611 self.env.filters['filter_data_type'] = self.filter_data_type
Matthias BUSSONNIER
flag for extracting figure
r9615 self.env.filters['pycomment'] = python_comment
self.env.filters['indent'] = indent
self.env.filters['rm_fake'] = rm_fake
self.env.filters['rm_ansi'] = remove_ansi
self.env.filters['markdown'] = markdown
self.env.filters['highlight'] = highlight
self.env.filters['ansi2html'] = ansi2html
self.env.filters['markdown2latex'] = markdown2latex
Matthias BUSSONNIER
use configuration file to do nice stuff
r9618 self.template = self.env.get_template(self.template_file+self.ext)
Matthias BUSSONNIER
lots of modification for latex
r9611
Matthias BUSSONNIER
starting templates
r9578
Matthias BUSSONNIER
preprocessing and namespace fix...
r9604
Matthias BUSSONNIER
starting templates
r9578 def process(self):
Matthias BUSSONNIER
add docstring
r9607 """
Matthias BUSSONNIER
some improvement
r9614 preprocess the notebook json for easier use with the templates.
will call all the `preprocessor`s in order before returning it.
Matthias BUSSONNIER
add docstring
r9607 """
Matthias BUSSONNIER
add possibility to preprocess ipynb files
r9603 nb = self.nb
Matthias BUSSONNIER
flag for extracting figure
r9615 # dict of 'resources' that could be made by the preprocessors
# like key/value data to extract files from ipynb like in latex conversion
resources = {}
Matthias BUSSONNIER
add possibility to preprocess ipynb files
r9603 for preprocessor in self.preprocessors:
Matthias BUSSONNIER
flag for extracting figure
r9615 nb,resources = preprocessor(nb,resources)
Matthias BUSSONNIER
add possibility to preprocess ipynb files
r9603
Matthias BUSSONNIER
flag for extracting figure
r9615 return nb, resources
Matthias BUSSONNIER
starting templates
r9578
Matthias BUSSONNIER
remove and clean code
r9602 def convert(self):
Matthias BUSSONNIER
Start to think on api...
r9601 """ convert the ipynb file
return both the converted ipynb file and a dict containing potential
other resources
"""
Matthias BUSSONNIER
flag for extracting figure
r9615 nb,resources = self.process()
return self.template.render(nb=nb, inlining=inlining), resources
Matthias BUSSONNIER
starting templates
r9578
def read(self, filename):
"read and parse notebook into NotebookNode called self.nb"
Matthias BUSSONNIER
fix utf8
r9589 with io.open(filename) as f:
Matthias BUSSONNIER
starting templates
r9578 self.nb = nbformat.read(f, 'json')