##// END OF EJS Templates
Added datetime access to Jinja
Added datetime access to Jinja

File last commit:

r9768:b0bae6ce
r9768:b0bae6ce
Show More
template.py
261 lines | 8.9 KiB | text/x-python | PythonLexer
Matthias BUSSONNIER
starting templates
r9578 """Base classes for the notebook conversion pipeline.
Matthias BUSSONNIER
document
r9665 This module defines ConverterTemplate, a highly configurable converter
that uses Jinja2 to convert notebook files into different format.
You can register both pre-transformers that will act on the notebook format
befor conversion and jinja filter that would then be availlable in the templates
Matthias BUSSONNIER
starting templates
r9578 """
#-----------------------------------------------------------------------------
Matthias BUSSONNIER
document
r9665 # Copyright (c) 2013, the IPython Development Team.
Matthias BUSSONNIER
starting templates
r9578 #
# 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
Matthias BUSSONNIER
document
r9665
# Stdlib imports
import io
# IPython imports
from IPython.utils.traitlets import MetaHasTraits
from IPython.utils.traitlets import (Unicode, List, Bool)
from IPython.config.configurable import Configurable
from IPython.nbformat import current as nbformat
Matthias BUSSONNIER
do a markdown converter
r9701
Matthias BUSSONNIER
document
r9665 # other libs/dependencies
from jinja2 import Environment, FileSystemLoader
# local import (pre-transformers)
Matthias BUSSONNIER
move transformer in separate file
r9621 import converters.transformers as trans
Matthias BUSSONNIER
document
r9665
# some jinja filters
Matthias BUSSONNIER
mofe filter in separate file
r9622 from converters.jinja_filters import (python_comment, indent,
rm_fake, remove_ansi, markdown, highlight,
Matthias BUSSONNIER
allow configurable filters
r9650 ansi2html, markdown2latex, escape_tex, FilterDataType)
Matthias BUSSONNIER
move transformer in separate file
r9621
Matthias BUSSONNIER
start rst converter
r9641 from converters.utils import markdown2rst
Matthias BUSSONNIER
starting templates
r9578
Matthias BUSSONNIER
do a markdown converter
r9701 import textwrap
def wrap(text, width=100):
""" try to detect and wrap paragraph"""
splitt = text.split('\n')
wrp = map(lambda x:textwrap.wrap(x,width),splitt)
wrpd = map('\n'.join, wrp)
return '\n'.join(wrpd)
Matthias BUSSONNIER
create configurable preprocessors
r9624
Matthias BUSSONNIER
move html header out
r9654
Matthias BUSSONNIER
document
r9665 # define differents environemnt with different
# delimiters not to conflict with languages inside
Matthias BUSSONNIER
starting templates
r9578
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']
)
texenv.block_start_string = '((*'
texenv.block_end_string = '*))'
Matthias BUSSONNIER
allow configurable filters
r9650
Matthias BUSSONNIER
multiple env
r9609 texenv.variable_start_string = '((('
texenv.variable_end_string = ')))'
Matthias BUSSONNIER
allow configurable filters
r9650
Matthias BUSSONNIER
multiple env
r9609 texenv.comment_start_string = '((='
texenv.comment_end_string = '=))'
Matthias BUSSONNIER
allow configurable filters
r9650
Matthias BUSSONNIER
multiple env
r9609 texenv.filters['escape_tex'] = escape_tex
Matthias BUSSONNIER
document
r9665 #-----------------------------------------------------------------------------
# Class declarations
#-----------------------------------------------------------------------------
class ConversionException(Exception):
pass
Matthias BUSSONNIER
some improvement
r9614
Matthias BUSSONNIER
starting templates
r9578 class ConverterTemplate(Configurable):
Matthias BUSSONNIER
stateless converter
r9640 """ A Jinja2 base converter templates
Preprocess the ipynb files, feed it throug jinja templates,
and spit an converted files and a data object with other data
shoudl be mostly configurable
"""
Matthias BUSSONNIER
starting templates
r9578
Jonathan Frederic
Added datetime access to Jinja
r9768 display_data_priority = List(['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg' , 'text'],
config=True,
help= """
An ordered list of prefered output type, the first
encounterd will usually be used when converting discarding
the others.
"""
)
Matthias BUSSONNIER
stateless converter
r9640 pre_transformer_order = List(['haspyout_transformer'],
Matthias BUSSONNIER
pretransformer configurables
r9619 config=True,
Matthias BUSSONNIER
cleaning
r9623 help= """
An ordered list of pre transformer to apply to the ipynb
file befor running through templates
Matthias BUSSONNIER
lots of modification for latex
r9611 """
)
Matthias BUSSONNIER
some improvement
r9614
Jonathan Frederic
Added datetime access to Jinja
r9768 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,
Matthias BUSSONNIER
stateless converter
r9640 help=""" Name of the template file to use """ )
Matthias BUSSONNIER
starting templates
r9578 #-------------------------------------------------------------------------
# Instance-level attributes that are set in the constructor for this
# class.
#-------------------------------------------------------------------------
Jonathan Frederic
Added datetime access to Jinja
r9768 infile = Any()
Matthias BUSSONNIER
lots of modification for latex
r9611
Matthias BUSSONNIER
starting templates
r9578
Jonathan Frederic
Added datetime access to Jinja
r9768 infile_dir = Unicode()
#todo: move to filter
def filter_data_type(self, output):
""" return the first availlable format in priority """
for fmt in self.display_data_priority:
if fmt in output:
return [fmt]
raise Exception("did not found any format I can extract in output, shoudl at lest have one")
Matthias BUSSONNIER
stateless converter
r9640 preprocessors = []
def __init__(self, preprocessors={}, jinja_filters={}, config=None, **kw):
Jonathan Frederic
Added datetime access to Jinja
r9768 """
config: the Configurable config object to pass around.
Matthias BUSSONNIER
add possibility to preprocess ipynb files
r9603
Matthias BUSSONNIER
allow configurable filters
r9650 preprocessors: dict of **availlable** key/value function to run on
Matthias BUSSONNIER
document
r9665 ipynb json data before conversion to extract/inline file.
See `transformer.py` and `ConfigurableTransformers`
Matthias BUSSONNIER
allow configurable filters
r9650
Matthias BUSSONNIER
document
r9665 set the order in which the transformers should apply
with the `pre_transformer_order` trait of this class
Matthias BUSSONNIER
add possibility to preprocess ipynb files
r9603
Matthias BUSSONNIER
document
r9665 transformers registerd by this key will take precedence on
default one.
jinja_filters: dict of supplementary jinja filter that should be made
availlable in template. If those are of Configurable Class type,
they will be instanciated with the config object as argument.
user defined filter will overwrite the one availlable by default.
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
document
r9665
# variable parameters depending on the pype of jinja environement
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
create configurable preprocessors
r9624
Matthias BUSSONNIER
move transformer in separate file
r9621 for name in self.pre_transformer_order:
Matthias BUSSONNIER
document
r9665 # get the user-defined transformer first
Matthias BUSSONNIER
stateless converter
r9640 transformer = getattr(preprocessors, name, getattr(trans, name, None))
if isinstance(transformer, MetaHasTraits):
transformer = transformer(config=config)
self.preprocessors.append(transformer)
## for compat, remove later
Matthias BUSSONNIER
add a coalesce stream transformer
r9656 self.preprocessors.append(trans.coalesce_streams)
Matthias BUSSONNIER
allow configurable filters
r9650 self.preprocessors.append(trans.ExtractFigureTransformer(config=config))
Matthias BUSSONNIER
reveal converter
r9644 self.preprocessors.append(trans.RevealHelpTransformer(config=config))
Matthias BUSSONNIER
move html header out
r9654 self.preprocessors.append(trans.CSSHtmlHeaderTransformer(config=config))
Matthias BUSSONNIER
flag for extracting figure
r9615
Matthias BUSSONNIER
stateless converter
r9640 ##
Matthias BUSSONNIER
allow configurable filters
r9650 self.env.filters['filter_data_type'] = FilterDataType(config=config)
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
start rst converter
r9641 self.env.filters['markdown2rst'] = markdown2rst
Matthias BUSSONNIER
do a markdown converter
r9701 self.env.filters['wrap'] = wrap
Matthias BUSSONNIER
document
r9665
## user filter will overwrite
Matthias BUSSONNIER
allow configurable filters
r9650 for key, filtr in jinja_filters.iteritems():
if isinstance(filtr, MetaHasTraits):
self.env.filters[key] = filtr(config=config)
else :
self.env.filters[key] = filtr
Matthias BUSSONNIER
flag for extracting figure
r9615
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
stateless converter
r9640 def process(self, nb):
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
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
mofe filter in separate file
r9622 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
stateless converter
r9640 def convert(self, nb):
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
stateless converter
r9640 nb, resources = self.process(nb)
Matthias BUSSONNIER
move html header out
r9654 return self.template.render(nb=nb, resources=resources), resources
Matthias BUSSONNIER
starting templates
r9578
Matthias BUSSONNIER
stateless converter
r9640 def from_filename(self, filename):
Matthias BUSSONNIER
more doc and future API
r9666 """read and convert a notebook from a file name"""
Matthias BUSSONNIER
fix utf8
r9589 with io.open(filename) as f:
Matthias BUSSONNIER
stateless converter
r9640 return self.convert(nbformat.read(f, 'json'))
Matthias BUSSONNIER
create configurable preprocessors
r9624
Matthias BUSSONNIER
more doc and future API
r9666 def from_file(self, filelike):
"""read and convert a notebook from a filelike object
Matthias BUSSONNIER
allow configurable filters
r9650
Matthias BUSSONNIER
more doc and future API
r9666 filelike object will just be "read" and should be json format..
"""
return self.convert(nbformat.read(filelike, 'json'))
def from_json(self, json):
""" not implemented
Should convert from a json object
"""
raise NotImplementedError('not implemented (yet?)')
Matthias BUSSONNIER
move html header out
r9654