##// END OF EJS Templates
corrected small exporter bug
jakobgager -
Show More
@@ -1,349 +1,349 b''
1 1 """This module defines Exporter, a highly configurable converter
2 2 that uses Jinja2 to export notebook files into different formats.
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 from __future__ import print_function, absolute_import
18 18
19 19 # Stdlib imports
20 20 import io
21 21 import os
22 22 import inspect
23 23 from copy import deepcopy
24 24
25 25 # IPython imports
26 26 from IPython.config.configurable import Configurable
27 27 from IPython.config import Config
28 28 from IPython.nbformat import current as nbformat
29 29 from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Bool
30 30 from IPython.utils.text import indent
31 31
32 32 # other libs/dependencies
33 33 from jinja2 import Environment, FileSystemLoader
34 34 from markdown import markdown
35 35
36 36 # local import
37 37 import nbconvert.filters.strings
38 38 import nbconvert.filters.markdown
39 39 import nbconvert.filters.latex
40 40 import nbconvert.filters.datatypefilter
41 41 import nbconvert.filters.highlight
42 42 import nbconvert.filters.ansi
43 43
44 44 import nbconvert.transformers.extractfigure
45 45 import nbconvert.transformers.coalescestreams
46 46
47 47 #-----------------------------------------------------------------------------
48 48 # Globals and constants
49 49 #-----------------------------------------------------------------------------
50 50
51 51 #Jinja2 extensions to load.
52 52 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
53 53
54 54 default_filters = {
55 55 'indent': indent,
56 56 'markdown': markdown,
57 57 'ansi2html': nbconvert.filters.ansi.ansi2html,
58 58 'filter_data_type': nbconvert.filters.datatypefilter.DataTypeFilter,
59 59 'get_lines': nbconvert.filters.strings.get_lines,
60 60 'highlight': nbconvert.filters.highlight.highlight,
61 61 'highlight2html': nbconvert.filters.highlight.highlight,
62 62 'highlight2latex': nbconvert.filters.highlight.highlight2latex,
63 63 'markdown2latex': nbconvert.filters.markdown.markdown2latex,
64 64 'markdown2rst': nbconvert.filters.markdown.markdown2rst,
65 65 'pycomment': nbconvert.filters.strings.python_comment,
66 66 'rm_ansi': nbconvert.filters.ansi.remove_ansi,
67 67 'rm_dollars': nbconvert.filters.strings.strip_dollars,
68 68 'rm_fake': nbconvert.filters.strings.rm_fake,
69 'ansi2latex': nbconvert.filters.strings.ansi2latex,
69 'ansi2latex': nbconvert.filters.ansi.ansi2latex,
70 70 'rm_math_space': nbconvert.filters.latex.rm_math_space,
71 71 'wrap': nbconvert.filters.strings.wrap
72 72 }
73 73
74 74 #-----------------------------------------------------------------------------
75 75 # Class
76 76 #-----------------------------------------------------------------------------
77 77
78 78 class Exporter(Configurable):
79 79 """
80 80 Exports notebooks into other file formats. Uses Jinja 2 templating engine
81 81 to output new formats. Inherit from this class if you are creating a new
82 82 template type along with new filters/transformers. If the filters/
83 83 transformers provided by default suffice, there is no need to inherit from
84 84 this class. Instead, override the template_file and file_extension
85 85 traits via a config file.
86 86
87 87 {filters}
88 88 """
89 89
90 90 # finish the docstring
91 91 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
92 92
93 93
94 94 template_file = Unicode(
95 95 '', config=True,
96 96 help="Name of the template file to use")
97 97
98 98 file_extension = Unicode(
99 99 'txt', config=True,
100 100 help="Extension of the file that should be written to disk"
101 101 )
102 102
103 103 template_path = Unicode(
104 104 "/../templates/", config=True,
105 105 help="Path where the template files are located.")
106 106
107 107 template_skeleton_path = Unicode(
108 108 "/../templates/skeleton/", config=True,
109 109 help="Path where the template skeleton files are located.")
110 110
111 111 #Jinja block definitions
112 112 jinja_comment_block_start = Unicode("", config=True)
113 113 jinja_comment_block_end = Unicode("", config=True)
114 114 jinja_variable_block_start = Unicode("", config=True)
115 115 jinja_variable_block_end = Unicode("", config=True)
116 116 jinja_logic_block_start = Unicode("", config=True)
117 117 jinja_logic_block_end = Unicode("", config=True)
118 118
119 119 #Extension that the template files use.
120 120 template_extension = Unicode(".tpl", config=True)
121 121
122 122 #Processors that process the input data prior to the export, set in the
123 123 #constructor for this class.
124 124 transformers = None
125 125
126 126 _default_config = Config()
127 127
128 128
129 129 def __init__(self, transformers=None, filters=None, config=None, **kw):
130 130 """
131 131 Public constructor
132 132
133 133 Parameters
134 134 ----------
135 135 transformers : list[of transformer]
136 136 Custom transformers to apply to the notebook prior to engaging
137 137 the Jinja template engine. Any transformers specified here
138 138 will override existing transformers if a naming conflict
139 139 occurs.
140 140 filters : dict[of filter]
141 141 filters specified here will override existing filters if a naming
142 142 conflict occurs. Filters are availlable in jinja template through
143 143 the name of the corresponding key. Cf class docstring for
144 144 availlable default filters.
145 145 config : config
146 146 User configuration instance.
147 147 """
148 148
149 149 #Call the base class constructor
150 150 super(Exporter, self).__init__(config=config, **kw)
151 151
152 152 #Standard environment
153 153 self._init_environment()
154 154
155 155 #Add transformers
156 156 self._register_transformers()
157 157
158 158 #Add filters to the Jinja2 environment
159 159 self._register_filters()
160 160
161 161 #Load user transformers. Overwrite existing transformers if need be.
162 162 if transformers :
163 163 for transformer in transformers:
164 164 self.register_transformer(transformer)
165 165
166 166 #Load user filters. Overwrite existing filters if need be.
167 167 if not filters is None:
168 168 for key, user_filter in filters.iteritems():
169 169 if issubclass(user_filter, MetaHasTraits):
170 170 self.environment.filters[key] = user_filter(config=config)
171 171 else:
172 172 self.environment.filters[key] = user_filter
173 173
174 174 @property
175 175 def default_config(self):
176 176 if self._default_config:
177 177 return Config(deepcopy(self._default_config))
178 178 else :
179 179 return Config()
180 180
181 181
182 182 def from_notebook_node(self, nb, resources=None):
183 183 """
184 184 Convert a notebook from a notebook node instance.
185 185
186 186 Parameters
187 187 ----------
188 188 nb : Notebook node
189 189 resources : a dict of additional resources that
190 190 can be accessed read/write by transformers
191 191 and filters.
192 192 """
193 193 if resources is None:
194 194 resources = {}
195 195 nb, resources = self._preprocess(nb, resources)
196 196
197 197 #Load the template file.
198 198 self.template = self.environment.get_template(self.template_file+self.template_extension)
199 199
200 200 return self.template.render(nb=nb, resources=resources), resources
201 201
202 202
203 203 def from_filename(self, filename):
204 204 """
205 205 Convert a notebook from a notebook file.
206 206
207 207 Parameters
208 208 ----------
209 209 filename : str
210 210 Full filename of the notebook file to open and convert.
211 211 """
212 212
213 213 with io.open(filename) as f:
214 214 return self.from_notebook_node(nbformat.read(f, 'json'))
215 215
216 216
217 217 def from_file(self, file_stream):
218 218 """
219 219 Convert a notebook from a notebook file.
220 220
221 221 Parameters
222 222 ----------
223 223 file_stream : file-like object
224 224 Notebook file-like object to convert.
225 225 """
226 226 return self.from_notebook_node(nbformat.read(file_stream, 'json'))
227 227
228 228
229 229 def register_transformer(self, transformer):
230 230 """
231 231 Register a transformer.
232 232 Transformers are classes that act upon the notebook before it is
233 233 passed into the Jinja templating engine. Transformers are also
234 234 capable of passing additional information to the Jinja
235 235 templating engine.
236 236
237 237 Parameters
238 238 ----------
239 239 transformer : transformer
240 240 """
241 241 if self.transformers is None:
242 242 self.transformers = []
243 243
244 244 if inspect.isfunction(transformer):
245 245 self.transformers.append(transformer)
246 246 return transformer
247 247 elif isinstance(transformer, MetaHasTraits):
248 248 transformer_instance = transformer(config=self.config)
249 249 self.transformers.append(transformer_instance)
250 250 return transformer_instance
251 251 else:
252 252 transformer_instance = transformer()
253 253 self.transformers.append(transformer_instance)
254 254 return transformer_instance
255 255
256 256
257 257 def register_filter(self, name, filter):
258 258 """
259 259 Register a filter.
260 260 A filter is a function that accepts and acts on one string.
261 261 The filters are accesible within the Jinja templating engine.
262 262
263 263 Parameters
264 264 ----------
265 265 name : str
266 266 name to give the filter in the Jinja engine
267 267 filter : filter
268 268 """
269 269 if inspect.isfunction(filter):
270 270 self.environment.filters[name] = filter
271 271 elif isinstance(filter, MetaHasTraits):
272 272 self.environment.filters[name] = filter(config=self.config)
273 273 else:
274 274 self.environment.filters[name] = filter()
275 275 return self.environment.filters[name]
276 276
277 277
278 278 def _register_transformers(self):
279 279 """
280 280 Register all of the transformers needed for this exporter.
281 281 """
282 282
283 283 self.register_transformer(nbconvert.transformers.coalescestreams.coalesce_streams)
284 284
285 285 #Remember the figure extraction transformer so it can be enabled and
286 286 #disabled easily later.
287 287 self.extract_figure_transformer = self.register_transformer(nbconvert.transformers.extractfigure.ExtractFigureTransformer)
288 288
289 289
290 290 def _register_filters(self):
291 291 """
292 292 Register all of the filters required for the exporter.
293 293 """
294 294 for k, v in default_filters.iteritems():
295 295 self.register_filter(k, v)
296 296
297 297
298 298 def _init_environment(self):
299 299 """
300 300 Create the Jinja templating environment.
301 301 """
302 302
303 303 self.environment = Environment(
304 304 loader=FileSystemLoader([
305 305 os.path.dirname(os.path.realpath(__file__)) + self.template_path,
306 306 os.path.dirname(os.path.realpath(__file__)) + self.template_skeleton_path,
307 307 ]),
308 308 extensions=JINJA_EXTENSIONS
309 309 )
310 310
311 311 #Set special Jinja2 syntax that will not conflict with latex.
312 312 if self.jinja_logic_block_start:
313 313 self.environment.block_start_string = self.jinja_logic_block_start
314 314 if self.jinja_logic_block_end:
315 315 self.environment.block_end_string = self.jinja_logic_block_end
316 316 if self.jinja_variable_block_start:
317 317 self.environment.variable_start_string = self.jinja_variable_block_start
318 318 if self.jinja_variable_block_end:
319 319 self.environment.variable_end_string = self.jinja_variable_block_end
320 320 if self.jinja_comment_block_start:
321 321 self.environment.comment_start_string = self.jinja_comment_block_start
322 322 if self.jinja_comment_block_end:
323 323 self.environment.comment_end_string = self.jinja_comment_block_end
324 324
325 325
326 326 def _preprocess(self, nb, resources):
327 327 """
328 328 Preprocess the notebook before passing it into the Jinja engine.
329 329 To preprocess the notebook is to apply all of the
330 330
331 331 Parameters
332 332 ----------
333 333 nb : notebook node
334 334 notebook that is being exported.
335 335 resources : a dict of additional resources that
336 336 can be accessed read/write by transformers
337 337 and filters.
338 338 """
339 339
340 340 # Do a deepcopy first,
341 341 # we are never safe enough with what the transformers could do.
342 342 nbc = deepcopy(nb)
343 343 resc = deepcopy(resources)
344 344 #Run each transformer on the notebook. Carry the output along
345 345 #to each transformer
346 346 for transformer in self.transformers:
347 347 nb, resources = transformer(nbc, resc)
348 348 return nb, resources
349 349
General Comments 0
You need to be logged in to leave comments. Login now