##// END OF EJS Templates
move transformer in separate file
Matthias BUSSONNIER -
Show More
@@ -0,0 +1,50 b''
1 """
2
3 """
4
5 def cell_preprocessor(function):
6 """ wrap a function to be executed on all cells of a notebook
7
8 wrapped function parameters :
9 cell : the cell
10 other : external resources
11 index : index of the cell
12 """
13 def wrappedfunc(nb,other):
14 for worksheet in nb.worksheets :
15 for index, cell in enumerate(worksheet.cells):
16 worksheet.cells[index],other= function(cell,other,index)
17 return nb,other
18 return wrappedfunc
19
20
21 @cell_preprocessor
22 def haspyout_transformer(cell, other, count):
23 """
24 Add a haspyout flag to cell that have it
25
26 Easier for templating, where you can't know in advance
27 wether to write the out prompt
28
29 """
30 cell.type = cell.cell_type
31 cell.haspyout = False
32 for out in cell.get('outputs', []):
33 if out.output_type == 'pyout':
34 cell.haspyout = True
35 break
36 return cell,other
37
38
39 @cell_preprocessor
40 def extract_figure_transformer(cell,other,count):
41 for i,out in enumerate(cell.get('outputs', [])):
42 for type in ['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg']:
43 if out.hasattr(type):
44 figname,data = _new_figure(out[type], type, count)
45 cell.outputs[i][type] = figname
46 out['key_'+type] = figname
47 other[figname] = data
48 count = count+1
49 return cell,other
50
@@ -1,301 +1,274 b''
1 1 """Base classes for the notebook conversion pipeline.
2 2
3 3 This module defines Converter, from which all objects designed to implement
4 4 a conversion of IPython notebooks to some other format should inherit.
5 5 """
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (c) 2012, the IPython Development Team.
8 8 #
9 9 # Distributed under the terms of the Modified BSD License.
10 10 #
11 11 # The full license is in the file COPYING.txt, distributed with this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 from __future__ import print_function, absolute_import
19 from .transformers import extract_figure_transformer
20 import converters.transformers as trans
21
19 22
20 23 # Stdlib imports
21 24 import io
22 25 import os
23 26 import re
24 27 from IPython.utils import path
25 28
26 29 from jinja2 import Environment, FileSystemLoader
27 30 env = Environment(
28 31 loader=FileSystemLoader([
29 32 './templates/',
30 33 './templates/skeleton/',
31 34 ]),
32 35 extensions=['jinja2.ext.loopcontrols']
33 36 )
34 37
35 38 texenv = Environment(
36 39 loader=FileSystemLoader([
37 40 './templates/tex/',
38 41 './templates/skeleton/tex/',
39 42 ]),
40 43 extensions=['jinja2.ext.loopcontrols']
41 44 )
42 45
43 46 # IPython imports
44 47 from IPython.nbformat import current as nbformat
45 48 from IPython.config.configurable import Configurable
46 49 from IPython.utils.traitlets import ( Unicode, Any, List, Bool)
47 50
48 51 # Our own imports
49 52 from IPython.utils.text import indent
50 53 from .utils import remove_ansi
51 54 from markdown import markdown
52 55 from .utils import highlight, ansi2html
53 56 from .utils import markdown2latex
54 57 #-----------------------------------------------------------------------------
55 58 # Class declarations
56 59 #-----------------------------------------------------------------------------
57 60 def rm_fake(strng):
58 61 return strng.replace('/files/', '')
59 62
60 63 class ConversionException(Exception):
61 64 pass
62 65
63 66
64 67 def python_comment(string):
65 68 return '# '+'\n# '.join(string.split('\n'))
66 69
67 70
68 71
69 72 def header_body():
70 73 """Return the body of the header as a list of strings."""
71 74
72 75 from pygments.formatters import HtmlFormatter
73 76
74 77 header = []
75 78 static = os.path.join(path.get_ipython_package_dir(),
76 79 'frontend', 'html', 'notebook', 'static',
77 80 )
78 81 here = os.path.split(os.path.realpath(__file__))[0]
79 82 css = os.path.join(static, 'css')
80 83 for sheet in [
81 84 # do we need jquery and prettify?
82 85 # os.path.join(static, 'jquery', 'css', 'themes', 'base',
83 86 # 'jquery-ui.min.css'),
84 87 # os.path.join(static, 'prettify', 'prettify.css'),
85 88 os.path.join(css, 'boilerplate.css'),
86 89 os.path.join(css, 'fbm.css'),
87 90 os.path.join(css, 'notebook.css'),
88 91 os.path.join(css, 'renderedhtml.css'),
89 92 # our overrides:
90 93 os.path.join(here, '..', 'css', 'static_html.css'),
91 94 ]:
92 95
93 96 with io.open(sheet, encoding='utf-8') as f:
94 97 s = f.read()
95 98 header.append(s)
96 99
97 100 pygments_css = HtmlFormatter().get_style_defs('.highlight')
98 101 header.append(pygments_css)
99 102 return header
100 103
101 104 # todo, make the key part configurable.
102 105 def _new_figure(data, fmt, count):
103 106 """Create a new figure file in the given format.
104 107
105 108 Returns a path relative to the input file.
106 109 """
107 110 figname = '_fig_%02i.%s' % (count, fmt)
108 111
109 112 # Binary files are base64-encoded, SVG is already XML
110 113 if fmt in ('png', 'jpg', 'pdf'):
111 114 data = data.decode('base64')
112 115
113 116 return figname,data
114 117
115 118
116 119
117 120
118 121 inlining = {}
119 122 inlining['css'] = header_body()
120 123
121 124 LATEX_SUBS = (
122 125 (re.compile(r'\\'), r'\\textbackslash'),
123 126 (re.compile(r'([{}_#%&$])'), r'\\\1'),
124 127 (re.compile(r'~'), r'\~{}'),
125 128 (re.compile(r'\^'), r'\^{}'),
126 129 (re.compile(r'"'), r"''"),
127 130 (re.compile(r'\.\.\.+'), r'\\ldots'),
128 131 )
129 132
130 133 def escape_tex(value):
131 134 newval = value
132 135 for pattern, replacement in LATEX_SUBS:
133 136 newval = pattern.sub(replacement, newval)
134 137 return newval
135 138
136 139 texenv.block_start_string = '((*'
137 140 texenv.block_end_string = '*))'
138 141 texenv.variable_start_string = '((('
139 142 texenv.variable_end_string = ')))'
140 143 texenv.comment_start_string = '((='
141 144 texenv.comment_end_string = '=))'
142 145 texenv.filters['escape_tex'] = escape_tex
143 146
144 147 def cell_preprocessor(function):
145 148 """ wrap a function to be executed on all cells of a notebook
146 149
147 150 wrapped function parameters :
148 151 cell : the cell
149 152 other : external resources
150 153 index : index of the cell
151 154 """
152 155 def wrappedfunc(nb,other):
153 156 for worksheet in nb.worksheets :
154 157 for index, cell in enumerate(worksheet.cells):
155 158 worksheet.cells[index],other= function(cell,other,index)
156 159 return nb,other
157 160 return wrappedfunc
158 161
159 162
160 163
161 @cell_preprocessor
162 def haspyout_transformer(cell, other, count):
163 """
164 Add a haspyout flag to cell that have it
165
166 Easier for templating, where you can't know in advance
167 wether to write the out prompt
168
169 """
170 cell.type = cell.cell_type
171 cell.haspyout = False
172 for out in cell.get('outputs', []):
173 if out.output_type == 'pyout':
174 cell.haspyout = True
175 break
176 return cell,other
177
178
179 @cell_preprocessor
180 def extract_figure_transformer(cell,other,count):
181 for i,out in enumerate(cell.get('outputs', [])):
182 for type in ['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg']:
183 if out.hasattr(type):
184 figname,data = _new_figure(out[type], type,count)
185 cell.outputs[i][type] = figname
186 out['key_'+type] = figname
187 other[figname] = data
188 count = count+1
189 return cell,other
190
191 164
192 165 class ConverterTemplate(Configurable):
193 166 """ A Jinja2 base converter templates"""
194 167
195 168 display_data_priority = List(['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg' , 'text'],
196 169 config=True,
197 170 help= """
198 171 An ordered list of prefered output type, the firs encounterd will usually be
199 172 used when converting discarding the others.
200 173 """
201 174 )
202 175
203 pre_transformer_order = List([],
176 pre_transformer_order = List(['haspyout_transformer'],
204 177 config=True,
205 178 help= """ An ordered list of pretransformer to apply to the ipynb file befor running through templates
206 179 """
207 180 )
208 181
209 182 extract_figures = Bool(False,
210 183 config=True,
211 184 help= """
212 185 wether to remove figure data from ipynb and store them in auxiliary
213 186 dictionnary
214 187 """
215 188 )
216 189
217 190 tex_environement = Bool(False,
218 191 config=True,
219 192 help=""" is this a tex environment or not """)
220 193
221 194 template_file = Unicode('',
222 195 config=True,
223 196 help=""" whetever """ )
224 197 #-------------------------------------------------------------------------
225 198 # Instance-level attributes that are set in the constructor for this
226 199 # class.
227 200 #-------------------------------------------------------------------------
228 201 infile = Any()
229 202
230 203
231 204 infile_dir = Unicode()
232 205
233 206 def filter_data_type(self,output):
234 207 for fmt in self.display_data_priority:
235 208 if fmt in output:
236 209 return [fmt]
237 210
238 211 def __init__(self, preprocessors=[], config=None, **kw):
239 212 """
240 213 tplfile : jinja template file to process.
241 214
242 215 config: the Configurable confg object to pass around
243 216
244 217 preprocessors: list of function to run on ipynb json data before conversion
245 218 to extract/inline file,
246 219
247 220 """
248 221 super(ConverterTemplate, self).__init__(config=config, **kw)
249 222 self.env = texenv if self.tex_environement else env
250 223 self.ext = '.tplx' if self.tex_environement else '.tpl'
251 224 self.nb = None
252 225 self.preprocessors = preprocessors
253 self.preprocessors.append(haspyout_transformer)
226 for name in self.pre_transformer_order:
227 self.preprocessors.append(getattr(trans,'haspyout_transformer'))
254 228 if self.extract_figures:
255 229 self.preprocessors.append(extract_figure_transformer)
256 230
257 231 self.env.filters['filter_data_type'] = self.filter_data_type
258 232 self.env.filters['pycomment'] = python_comment
259 233 self.env.filters['indent'] = indent
260 234 self.env.filters['rm_fake'] = rm_fake
261 235 self.env.filters['rm_ansi'] = remove_ansi
262 236 self.env.filters['markdown'] = markdown
263 237 self.env.filters['highlight'] = highlight
264 238 self.env.filters['ansi2html'] = ansi2html
265 239 self.env.filters['markdown2latex'] = markdown2latex
266 240
267 241 self.template = self.env.get_template(self.template_file+self.ext)
268 242
269 243
270
271 244 def process(self):
272 245 """
273 246 preprocess the notebook json for easier use with the templates.
274 247 will call all the `preprocessor`s in order before returning it.
275 248 """
276 249 nb = self.nb
277 250
278 251 # dict of 'resources' that could be made by the preprocessors
279 252 # like key/value data to extract files from ipynb like in latex conversion
280 253 resources = {}
281 254
282 255 for preprocessor in self.preprocessors:
283 256 nb,resources = preprocessor(nb,resources)
284 257
285 258 return nb, resources
286 259
287 260 def convert(self):
288 261 """ convert the ipynb file
289 262
290 263 return both the converted ipynb file and a dict containing potential
291 264 other resources
292 265 """
293 266 nb,resources = self.process()
294 267 return self.template.render(nb=nb, inlining=inlining), resources
295 268
296 269
297 270 def read(self, filename):
298 271 "read and parse notebook into NotebookNode called self.nb"
299 272 with io.open(filename) as f:
300 273 self.nb = nbformat.read(f, 'json')
301 274
General Comments 0
You need to be logged in to leave comments. Login now