From df9dfe46ffa1d261f7e6bb3fb79d1d8fafc7a333 2013-02-13 19:30:09 From: Matthias BUSSONNIER Date: 2013-02-13 19:30:09 Subject: [PATCH] create configurable preprocessors --- diff --git a/converters/template.py b/converters/template.py index 28fab60..5239173 100755 --- a/converters/template.py +++ b/converters/template.py @@ -16,17 +16,18 @@ a conversion of IPython notebooks to some other format should inherit. #----------------------------------------------------------------------------- from __future__ import print_function, absolute_import -from .transformers import extract_figure_transformer import converters.transformers as trans from converters.jinja_filters import (python_comment, indent, rm_fake, remove_ansi, markdown, highlight, ansi2html, markdown2latex, escape_tex) + # Stdlib imports import io import os from IPython.utils import path +from IPython.utils.traitlets import MetaHasTraits from jinja2 import Environment, FileSystemLoader env = Environment( @@ -118,8 +119,8 @@ class ConverterTemplate(Configurable): the others. """ ) - - pre_transformer_order = List(['haspyout_transformer'], + + pre_transformer_order = List(['haspyout_transformer', 'Foobar'], config=True, help= """ An ordered list of pre transformer to apply to the ipynb @@ -169,10 +170,14 @@ class ConverterTemplate(Configurable): self.ext = '.tplx' if self.tex_environement else '.tpl' self.nb = None self.preprocessors = preprocessors + for name in self.pre_transformer_order: - self.preprocessors.append(getattr(trans, name)) + tr = getattr(trans, name) + if isinstance(tr, MetaHasTraits): + tr = tr(config=config) + self.preprocessors.append(tr) if self.extract_figures: - self.preprocessors.append(extract_figure_transformer) + self.preprocessors.append(trans.ExtractFigureTransformer(config=config)) self.env.filters['filter_data_type'] = self.filter_data_type self.env.filters['pycomment'] = python_comment @@ -218,3 +223,5 @@ class ConverterTemplate(Configurable): with io.open(filename) as f: self.nb = nbformat.read(f, 'json') + + diff --git a/converters/transformers.py b/converters/transformers.py index d79b2eb..7b6018f 100755 --- a/converters/transformers.py +++ b/converters/transformers.py @@ -2,6 +2,41 @@ """ +from __future__ import print_function + +from IPython.config.configurable import Configurable +from IPython.utils.traitlets import Unicode, Bool, Dict + +class ConfigurableTransformers(Configurable): + """ A configurable transformer """ + + def __init__(self, config=None, **kw): + super(ConfigurableTransformers, self).__init__(config=config, **kw) + + def __call__(self, nb, other): + try : + for worksheet in nb.worksheets : + for index, cell in enumerate(worksheet.cells): + worksheet.cells[index], other = self.cell_transform(cell, other, index) + return nb, other + except NotImplementedError as error : + raise NotImplementedError('should be implemented by subclass') + + def cell_transform(self, cell, other, index): + """ + Overwrite if you want to apply a transformation on each cell + """ + raise NotImplementedError('should be implemented by subclass') + + +class Foobar(ConfigurableTransformers): + message = Unicode('-- nothing', config=True) + + + def cell_transform(self, cell, other, index): + return cell, other + + def cell_preprocessor(function): """ wrap a function to be executed on all cells of a notebook @@ -22,7 +57,7 @@ def cell_preprocessor(function): 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 @@ -37,28 +72,54 @@ def haspyout_transformer(cell, other, count): # todo, make the key part configurable. -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) +class ExtractFigureTransformer(ConfigurableTransformers): + enabled = Bool(False, + config=True, + help=""" If set to false, this transformer will be no-op """ + ) - # Binary files are base64-encoded, SVG is already XML - if fmt in ('png', 'jpg', 'pdf'): - data = data.decode('base64') + extra_ext_map = Dict({}, + config=True, + help="""extra map to override extension based on type. + Usefull for latex where svg will be converted to pdf before inclusion + """ + ) - return figname, data -@cell_preprocessor -def extract_figure_transformer(cell, other, count): - 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 - return cell, other + #to do change this to .format {} syntax + key_tpl = Unicode('_fig_%02i.%s', config=True) + + def _get_ext(self, ext): + if ext in self.extra_ext_map : + return self.extra_ext_map[ext] + return ext + + def _new_figure(self, data, fmt, count): + """Create a new figure file in the given format. + + Returns a path relative to the input file. + """ + figname = self.key_tpl % (count, self._get_ext(fmt)) + key = self.key_tpl % (count, fmt) + + # Binary files are base64-encoded, SVG is already XML + if fmt in ('png', 'jpg', 'pdf'): + data = data.decode('base64') + + return figname, key, data + + + def cell_transform(self, cell, other, count): + if not self.enabled: + return cell, other + for i, out in enumerate(cell.get('outputs', [])): + for type in ['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg']: + if out.hasattr(type): + figname, key, data = self._new_figure(out[type], type, count) + cell.outputs[i][type] = figname + out['key_'+type] = figname + other[key] = data + count = count+1 + return cell, other diff --git a/profile/full_html.nbcv b/profile/full_html.nbcv index fce99c9..a07445e 100644 --- a/profile/full_html.nbcv +++ b/profile/full_html.nbcv @@ -1,5 +1,8 @@ c = get_config() + c.ConverterTemplate.extract_figures=False c.ConverterTemplate.template_file='fullhtml' c.ConverterTemplate.tex_environement=False + +c.ExtractFigureTransformer.enabled = False diff --git a/profile/latex_base.nbcv b/profile/latex_base.nbcv index 8a16e9c..a6d41ec 100644 --- a/profile/latex_base.nbcv +++ b/profile/latex_base.nbcv @@ -1,5 +1,7 @@ c = get_config() -c.ConverterTemplate.extract_figures=False +c.ConverterTemplate.extract_figures=True c.ConverterTemplate.template_file='latex_base' c.ConverterTemplate.tex_environement=True + +c.ExtractFigureTransformer.extra_ext_map={'svg':'pdf'} diff --git a/runme.py b/runme.py index e7e1d32..6f3b6ce 100755 --- a/runme.py +++ b/runme.py @@ -17,6 +17,8 @@ from IPython.config.application import Application from IPython.config.loader import ConfigFileNotFound from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, CaselessStrEnum +from converters.transformers import (ConfigurableTransformers,Foobar,ExtractFigureTransformer) + class NbconvertApp(Application): @@ -24,6 +26,9 @@ class NbconvertApp(Application): def __init__(self, **kwargs): super(NbconvertApp, self).__init__(**kwargs) self.classes.insert(0,ConverterTemplate) + # register class here to have help with help all + self.classes.insert(0,ExtractFigureTransformer) + self.classes.insert(0,Foobar) # ensure those are registerd def load_config_file(self, profile_name): @@ -54,11 +59,6 @@ class NbconvertApp(Application): template_file = sys.argv[1] - if template_file.startswith('latex'): - tex_environement=True - else: - tex_environement=False - C = ConverterTemplate(tplfile=sys.argv[1], config=self.config) C.read(ipynb_file) diff --git a/templates/tex/latex_base.tplx b/templates/tex/latex_base.tplx index 302762e..95ced8f 100644 --- a/templates/tex/latex_base.tplx +++ b/templates/tex/latex_base.tplx @@ -37,7 +37,14 @@ it introduces a new line ((*- block data_png -*)) \begin{center} -\includegraphics[width=0.7\textwidth]{(((output.png)))} +\includegraphics[width=0.7\textwidth]{(((output.key_png)))} +\par +\end{center} +((*- endblock -*)) + +((*- block data_svg -*)) +\begin{center} +\includegraphics[width=0.7\textwidth]{(((output.key_svg)))} \par \end{center} ((*- endblock -*))