##// END OF EJS Templates
replace 'transformer' with 'preprocessor'
Paul Ivanov -
Show More
@@ -1,7 +1,7 b''
1 1 """Utilities for converting notebooks to and from different formats."""
2 2
3 3 from .exporters import *
4 4 import filters
5 import transformers
5 import preprocessors
6 6 import post_processors
7 7 import writers
@@ -1,518 +1,518 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 import copy
24 24 import collections
25 25 import datetime
26 26
27 27 # other libs/dependencies
28 28 from jinja2 import Environment, FileSystemLoader, ChoiceLoader, TemplateNotFound
29 29
30 30 # IPython imports
31 31 from IPython.config.configurable import LoggingConfigurable
32 32 from IPython.config import Config
33 33 from IPython.nbformat import current as nbformat
34 34 from IPython.utils.traitlets import MetaHasTraits, DottedObjectName, Unicode, List, Dict, Any
35 35 from IPython.utils.importstring import import_item
36 36 from IPython.utils.text import indent
37 37 from IPython.utils import py3compat
38 38
39 from IPython.nbconvert import transformers as nbtransformers
39 from IPython.nbconvert import preprocessors as nbpreprocessors
40 40 from IPython.nbconvert import filters
41 41
42 42 #-----------------------------------------------------------------------------
43 43 # Globals and constants
44 44 #-----------------------------------------------------------------------------
45 45
46 46 #Jinja2 extensions to load.
47 47 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
48 48
49 49 default_filters = {
50 50 'indent': indent,
51 51 'markdown2html': filters.markdown2html,
52 52 'ansi2html': filters.ansi2html,
53 53 'filter_data_type': filters.DataTypeFilter,
54 54 'get_lines': filters.get_lines,
55 55 'highlight2html': filters.highlight2html,
56 56 'highlight2latex': filters.highlight2latex,
57 57 'ipython2python': filters.ipython2python,
58 58 'posix_path': filters.posix_path,
59 59 'markdown2latex': filters.markdown2latex,
60 60 'markdown2rst': filters.markdown2rst,
61 61 'comment_lines': filters.comment_lines,
62 62 'strip_ansi': filters.strip_ansi,
63 63 'strip_dollars': filters.strip_dollars,
64 64 'strip_files_prefix': filters.strip_files_prefix,
65 65 'html2text' : filters.html2text,
66 66 'add_anchor': filters.add_anchor,
67 67 'ansi2latex': filters.ansi2latex,
68 68 'strip_math_space': filters.strip_math_space,
69 69 'wrap_text': filters.wrap_text,
70 70 'escape_latex': filters.escape_latex,
71 71 }
72 72
73 73 #-----------------------------------------------------------------------------
74 74 # Class
75 75 #-----------------------------------------------------------------------------
76 76
77 77 class ResourcesDict(collections.defaultdict):
78 78 def __missing__(self, key):
79 79 return ''
80 80
81 81
82 82 class Exporter(LoggingConfigurable):
83 83 """
84 84 Exports notebooks into other file formats. Uses Jinja 2 templating engine
85 85 to output new formats. Inherit from this class if you are creating a new
86 template type along with new filters/transformers. If the filters/
87 transformers provided by default suffice, there is no need to inherit from
86 template type along with new filters/preprocessors. If the filters/
87 preprocessors provided by default suffice, there is no need to inherit from
88 88 this class. Instead, override the template_file and file_extension
89 89 traits via a config file.
90 90
91 91 {filters}
92 92 """
93 93
94 94 # finish the docstring
95 95 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
96 96
97 97
98 98 template_file = Unicode(u'default',
99 99 config=True,
100 100 help="Name of the template file to use")
101 101 def _template_file_changed(self, name, old, new):
102 102 if new=='default':
103 103 self.template_file = self.default_template
104 104 else:
105 105 self.template_file = new
106 106 self.template = None
107 107 self._load_template()
108 108
109 109 default_template = Unicode(u'')
110 110 template = Any()
111 111 environment = Any()
112 112
113 113 file_extension = Unicode(
114 114 'txt', config=True,
115 115 help="Extension of the file that should be written to disk"
116 116 )
117 117
118 118 template_path = List(['.'], config=True)
119 119 def _template_path_changed(self, name, old, new):
120 120 self._load_template()
121 121
122 122 default_template_path = Unicode(
123 123 os.path.join("..", "templates"),
124 124 help="Path where the template files are located.")
125 125
126 126 template_skeleton_path = Unicode(
127 127 os.path.join("..", "templates", "skeleton"),
128 128 help="Path where the template skeleton files are located.")
129 129
130 130 #Jinja block definitions
131 131 jinja_comment_block_start = Unicode("", config=True)
132 132 jinja_comment_block_end = Unicode("", config=True)
133 133 jinja_variable_block_start = Unicode("", config=True)
134 134 jinja_variable_block_end = Unicode("", config=True)
135 135 jinja_logic_block_start = Unicode("", config=True)
136 136 jinja_logic_block_end = Unicode("", config=True)
137 137
138 138 #Extension that the template files use.
139 139 template_extension = Unicode(".tpl", config=True)
140 140
141 #Configurability, allows the user to easily add filters and transformers.
142 transformers = List(config=True,
143 help="""List of transformers, by name or namespace, to enable.""")
141 #Configurability, allows the user to easily add filters and preprocessors.
142 preprocessors = List(config=True,
143 help="""List of preprocessors, by name or namespace, to enable.""")
144 144
145 145 filters = Dict(config=True,
146 146 help="""Dictionary of filters, by name and namespace, to add to the Jinja
147 147 environment.""")
148 148
149 default_transformers = List([nbtransformers.coalesce_streams,
150 nbtransformers.SVG2PDFTransformer,
151 nbtransformers.ExtractOutputTransformer,
152 nbtransformers.CSSHTMLHeaderTransformer,
153 nbtransformers.RevealHelpTransformer,
154 nbtransformers.LatexTransformer,
155 nbtransformers.SphinxTransformer],
149 default_preprocessors = List([nbpreprocessors.coalesce_streams,
150 nbpreprocessors.SVG2PDFPreprocessor,
151 nbpreprocessors.ExtractOutputPreprocessor,
152 nbpreprocessors.CSSHTMLHeaderPreprocessor,
153 nbpreprocessors.RevealHelpPreprocessor,
154 nbpreprocessors.LatexPreprocessor,
155 nbpreprocessors.SphinxPreprocessor],
156 156 config=True,
157 help="""List of transformers available by default, by name, namespace,
157 help="""List of preprocessors available by default, by name, namespace,
158 158 instance, or type.""")
159 159
160 160
161 161 def __init__(self, config=None, extra_loaders=None, **kw):
162 162 """
163 163 Public constructor
164 164
165 165 Parameters
166 166 ----------
167 167 config : config
168 168 User configuration instance.
169 169 extra_loaders : list[of Jinja Loaders]
170 170 ordered list of Jinja loader to find templates. Will be tried in order
171 171 before the default FileSystem ones.
172 172 template : str (optional, kw arg)
173 173 Template to use when exporting.
174 174 """
175 175 if not config:
176 176 config = self.default_config
177 177
178 178 super(Exporter, self).__init__(config=config, **kw)
179 179
180 180 #Init
181 181 self._init_template()
182 182 self._init_environment(extra_loaders=extra_loaders)
183 self._init_transformers()
183 self._init_preprocessors()
184 184 self._init_filters()
185 185
186 186
187 187 @property
188 188 def default_config(self):
189 189 return Config()
190 190
191 191 def _config_changed(self, name, old, new):
192 192 """When setting config, make sure to start with our default_config"""
193 193 c = self.default_config
194 194 if new:
195 195 c.merge(new)
196 196 if c != old:
197 197 self.config = c
198 198 super(Exporter, self)._config_changed(name, old, c)
199 199
200 200
201 201 def _load_template(self):
202 202 """Load the Jinja template object from the template file
203 203
204 204 This is a no-op if the template attribute is already defined,
205 205 or the Jinja environment is not setup yet.
206 206
207 207 This is triggered by various trait changes that would change the template.
208 208 """
209 209 if self.template is not None:
210 210 return
211 211 # called too early, do nothing
212 212 if self.environment is None:
213 213 return
214 214 # Try different template names during conversion. First try to load the
215 215 # template by name with extension added, then try loading the template
216 216 # as if the name is explicitly specified, then try the name as a
217 217 # 'flavor', and lastly just try to load the template by module name.
218 218 module_name = self.__module__.rsplit('.', 1)[-1]
219 219 try_names = []
220 220 if self.template_file:
221 221 try_names.extend([
222 222 self.template_file + self.template_extension,
223 223 self.template_file,
224 224 module_name + '_' + self.template_file + self.template_extension,
225 225 ])
226 226 try_names.append(module_name + self.template_extension)
227 227 for try_name in try_names:
228 228 self.log.debug("Attempting to load template %s", try_name)
229 229 try:
230 230 self.template = self.environment.get_template(try_name)
231 231 except (TemplateNotFound, IOError):
232 232 pass
233 233 except Exception as e:
234 234 self.log.warn("Unexpected exception loading template: %s", try_name, exc_info=True)
235 235 else:
236 236 self.log.info("Loaded template %s", try_name)
237 237 break
238 238
239 239 def from_notebook_node(self, nb, resources=None, **kw):
240 240 """
241 241 Convert a notebook from a notebook node instance.
242 242
243 243 Parameters
244 244 ----------
245 245 nb : Notebook node
246 246 resources : dict (**kw)
247 247 of additional resources that can be accessed read/write by
248 transformers and filters.
248 preprocessors and filters.
249 249 """
250 250 nb_copy = copy.deepcopy(nb)
251 251 resources = self._init_resources(resources)
252 252
253 253 # Preprocess
254 nb_copy, resources = self._transform(nb_copy, resources)
254 nb_copy, resources = self._preprocess(nb_copy, resources)
255 255
256 256 self._load_template()
257 257
258 258 if self.template is not None:
259 259 output = self.template.render(nb=nb_copy, resources=resources)
260 260 else:
261 261 raise IOError('template file "%s" could not be found' % self.template_file)
262 262 return output, resources
263 263
264 264
265 265 def from_filename(self, filename, resources=None, **kw):
266 266 """
267 267 Convert a notebook from a notebook file.
268 268
269 269 Parameters
270 270 ----------
271 271 filename : str
272 272 Full filename of the notebook file to open and convert.
273 273 """
274 274
275 275 #Pull the metadata from the filesystem.
276 276 if resources is None:
277 277 resources = ResourcesDict()
278 278 if not 'metadata' in resources or resources['metadata'] == '':
279 279 resources['metadata'] = ResourcesDict()
280 280 basename = os.path.basename(filename)
281 281 notebook_name = basename[:basename.rfind('.')]
282 282 resources['metadata']['name'] = notebook_name
283 283
284 284 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
285 285 resources['metadata']['modified_date'] = modified_date.strftime("%B %d, %Y")
286 286
287 287 with io.open(filename) as f:
288 288 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources,**kw)
289 289
290 290
291 291 def from_file(self, file_stream, resources=None, **kw):
292 292 """
293 293 Convert a notebook from a notebook file.
294 294
295 295 Parameters
296 296 ----------
297 297 file_stream : file-like object
298 298 Notebook file-like object to convert.
299 299 """
300 300 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
301 301
302 302
303 def register_transformer(self, transformer, enabled=False):
303 def register_preprocessor(self, preprocessor, enabled=False):
304 304 """
305 Register a transformer.
306 Transformers are classes that act upon the notebook before it is
307 passed into the Jinja templating engine. Transformers are also
305 Register a preprocessor.
306 Preprocessors are classes that act upon the notebook before it is
307 passed into the Jinja templating engine. Preprocessors are also
308 308 capable of passing additional information to the Jinja
309 309 templating engine.
310 310
311 311 Parameters
312 312 ----------
313 transformer : transformer
313 preprocessor : preprocessor
314 314 """
315 if transformer is None:
316 raise TypeError('transformer')
317 isclass = isinstance(transformer, type)
315 if preprocessor is None:
316 raise TypeError('preprocessor')
317 isclass = isinstance(preprocessor, type)
318 318 constructed = not isclass
319 319
320 #Handle transformer's registration based on it's type
321 if constructed and isinstance(transformer, py3compat.string_types):
322 #Transformer is a string, import the namespace and recursively call
323 #this register_transformer method
324 transformer_cls = import_item(transformer)
325 return self.register_transformer(transformer_cls, enabled)
320 #Handle preprocessor's registration based on it's type
321 if constructed and isinstance(preprocessor, py3compat.string_types):
322 #Preprocessor is a string, import the namespace and recursively call
323 #this register_preprocessor method
324 preprocessor_cls = import_item(preprocessor)
325 return self.register_preprocessor(preprocessor_cls, enabled)
326 326
327 if constructed and hasattr(transformer, '__call__'):
328 #Transformer is a function, no need to construct it.
329 #Register and return the transformer.
327 if constructed and hasattr(preprocessor, '__call__'):
328 #Preprocessor is a function, no need to construct it.
329 #Register and return the preprocessor.
330 330 if enabled:
331 transformer.enabled = True
332 self._transformers.append(transformer)
333 return transformer
331 preprocessor.enabled = True
332 self._preprocessors.append(preprocessor)
333 return preprocessor
334 334
335 elif isclass and isinstance(transformer, MetaHasTraits):
336 #Transformer is configurable. Make sure to pass in new default for
335 elif isclass and isinstance(preprocessor, MetaHasTraits):
336 #Preprocessor is configurable. Make sure to pass in new default for
337 337 #the enabled flag if one was specified.
338 self.register_transformer(transformer(parent=self), enabled)
338 self.register_preprocessor(preprocessor(parent=self), enabled)
339 339
340 340 elif isclass:
341 #Transformer is not configurable, construct it
342 self.register_transformer(transformer(), enabled)
341 #Preprocessor is not configurable, construct it
342 self.register_preprocessor(preprocessor(), enabled)
343 343
344 344 else:
345 #Transformer is an instance of something without a __call__
345 #Preprocessor is an instance of something without a __call__
346 346 #attribute.
347 raise TypeError('transformer')
347 raise TypeError('preprocessor')
348 348
349 349
350 350 def register_filter(self, name, jinja_filter):
351 351 """
352 352 Register a filter.
353 353 A filter is a function that accepts and acts on one string.
354 354 The filters are accesible within the Jinja templating engine.
355 355
356 356 Parameters
357 357 ----------
358 358 name : str
359 359 name to give the filter in the Jinja engine
360 360 filter : filter
361 361 """
362 362 if jinja_filter is None:
363 363 raise TypeError('filter')
364 364 isclass = isinstance(jinja_filter, type)
365 365 constructed = not isclass
366 366
367 367 #Handle filter's registration based on it's type
368 368 if constructed and isinstance(jinja_filter, py3compat.string_types):
369 369 #filter is a string, import the namespace and recursively call
370 370 #this register_filter method
371 371 filter_cls = import_item(jinja_filter)
372 372 return self.register_filter(name, filter_cls)
373 373
374 374 if constructed and hasattr(jinja_filter, '__call__'):
375 375 #filter is a function, no need to construct it.
376 376 self.environment.filters[name] = jinja_filter
377 377 return jinja_filter
378 378
379 379 elif isclass and isinstance(jinja_filter, MetaHasTraits):
380 380 #filter is configurable. Make sure to pass in new default for
381 381 #the enabled flag if one was specified.
382 382 filter_instance = jinja_filter(parent=self)
383 383 self.register_filter(name, filter_instance )
384 384
385 385 elif isclass:
386 386 #filter is not configurable, construct it
387 387 filter_instance = jinja_filter()
388 388 self.register_filter(name, filter_instance)
389 389
390 390 else:
391 391 #filter is an instance of something without a __call__
392 392 #attribute.
393 393 raise TypeError('filter')
394 394
395 395
396 396 def _init_template(self):
397 397 """
398 398 Make sure a template name is specified. If one isn't specified, try to
399 399 build one from the information we know.
400 400 """
401 401 self._template_file_changed('template_file', self.template_file, self.template_file)
402 402
403 403
404 404 def _init_environment(self, extra_loaders=None):
405 405 """
406 406 Create the Jinja templating environment.
407 407 """
408 408 here = os.path.dirname(os.path.realpath(__file__))
409 409 loaders = []
410 410 if extra_loaders:
411 411 loaders.extend(extra_loaders)
412 412
413 413 paths = self.template_path
414 414 paths.extend([os.path.join(here, self.default_template_path),
415 415 os.path.join(here, self.template_skeleton_path)])
416 416 loaders.append(FileSystemLoader(paths))
417 417
418 418 self.environment = Environment(
419 419 loader= ChoiceLoader(loaders),
420 420 extensions=JINJA_EXTENSIONS
421 421 )
422 422
423 423 #Set special Jinja2 syntax that will not conflict with latex.
424 424 if self.jinja_logic_block_start:
425 425 self.environment.block_start_string = self.jinja_logic_block_start
426 426 if self.jinja_logic_block_end:
427 427 self.environment.block_end_string = self.jinja_logic_block_end
428 428 if self.jinja_variable_block_start:
429 429 self.environment.variable_start_string = self.jinja_variable_block_start
430 430 if self.jinja_variable_block_end:
431 431 self.environment.variable_end_string = self.jinja_variable_block_end
432 432 if self.jinja_comment_block_start:
433 433 self.environment.comment_start_string = self.jinja_comment_block_start
434 434 if self.jinja_comment_block_end:
435 435 self.environment.comment_end_string = self.jinja_comment_block_end
436 436
437 437
438 def _init_transformers(self):
438 def _init_preprocessors(self):
439 439 """
440 Register all of the transformers needed for this exporter, disabled
440 Register all of the preprocessors needed for this exporter, disabled
441 441 unless specified explicitly.
442 442 """
443 self._transformers = []
443 self._preprocessors = []
444 444
445 #Load default transformers (not necessarly enabled by default).
446 if self.default_transformers:
447 for transformer in self.default_transformers:
448 self.register_transformer(transformer)
445 #Load default preprocessors (not necessarly enabled by default).
446 if self.default_preprocessors:
447 for preprocessor in self.default_preprocessors:
448 self.register_preprocessor(preprocessor)
449 449
450 #Load user transformers. Enable by default.
451 if self.transformers:
452 for transformer in self.transformers:
453 self.register_transformer(transformer, enabled=True)
450 #Load user preprocessors. Enable by default.
451 if self.preprocessors:
452 for preprocessor in self.preprocessors:
453 self.register_preprocessor(preprocessor, enabled=True)
454 454
455 455
456 456 def _init_filters(self):
457 457 """
458 458 Register all of the filters required for the exporter.
459 459 """
460 460
461 461 #Add default filters to the Jinja2 environment
462 462 for key, value in default_filters.items():
463 463 self.register_filter(key, value)
464 464
465 465 #Load user filters. Overwrite existing filters if need be.
466 466 if self.filters:
467 467 for key, user_filter in self.filters.items():
468 468 self.register_filter(key, user_filter)
469 469
470 470
471 471 def _init_resources(self, resources):
472 472
473 473 #Make sure the resources dict is of ResourcesDict type.
474 474 if resources is None:
475 475 resources = ResourcesDict()
476 476 if not isinstance(resources, ResourcesDict):
477 477 new_resources = ResourcesDict()
478 478 new_resources.update(resources)
479 479 resources = new_resources
480 480
481 481 #Make sure the metadata extension exists in resources
482 482 if 'metadata' in resources:
483 483 if not isinstance(resources['metadata'], ResourcesDict):
484 484 resources['metadata'] = ResourcesDict(resources['metadata'])
485 485 else:
486 486 resources['metadata'] = ResourcesDict()
487 487 if not resources['metadata']['name']:
488 488 resources['metadata']['name'] = 'Notebook'
489 489
490 490 #Set the output extension
491 491 resources['output_extension'] = self.file_extension
492 492 return resources
493 493
494 494
495 def _transform(self, nb, resources):
495 def _preprocess(self, nb, resources):
496 496 """
497 497 Preprocess the notebook before passing it into the Jinja engine.
498 498 To preprocess the notebook is to apply all of the
499 499
500 500 Parameters
501 501 ----------
502 502 nb : notebook node
503 503 notebook that is being exported.
504 504 resources : a dict of additional resources that
505 can be accessed read/write by transformers
505 can be accessed read/write by preprocessors
506 506 and filters.
507 507 """
508 508
509 509 # Do a copy.deepcopy first,
510 # we are never safe enough with what the transformers could do.
510 # we are never safe enough with what the preprocessors could do.
511 511 nbc = copy.deepcopy(nb)
512 512 resc = copy.deepcopy(resources)
513 513
514 #Run each transformer on the notebook. Carry the output along
515 #to each transformer
516 for transformer in self._transformers:
517 nbc, resc = transformer(nbc, resc)
514 #Run each preprocessor on the notebook. Carry the output along
515 #to each preprocessor
516 for preprocessor in self._preprocessors:
517 nbc, resc = preprocessor(nbc, resc)
518 518 return nbc, resc
@@ -1,52 +1,52 b''
1 1 """
2 2 Exporter that exports Basic HTML.
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 IPython.utils.traitlets import Unicode, List
18 18
19 from IPython.nbconvert import transformers
19 from IPython.nbconvert import preprocessors
20 20 from IPython.config import Config
21 21
22 22 from .exporter import Exporter
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Classes
26 26 #-----------------------------------------------------------------------------
27 27
28 28 class HTMLExporter(Exporter):
29 29 """
30 30 Exports a basic HTML document. This exporter assists with the export of
31 31 HTML. Inherit from it if you are writing your own HTML template and need
32 custom transformers/filters. If you don't need custom transformers/
32 custom preprocessors/filters. If you don't need custom preprocessors/
33 33 filters, just change the 'template_file' config option.
34 34 """
35 35
36 36 file_extension = Unicode(
37 37 'html', config=True,
38 38 help="Extension of the file that should be written to disk"
39 39 )
40 40
41 41 default_template = Unicode('full', config=True, help="""Flavor of the data
42 42 format to use. I.E. 'full' or 'basic'""")
43 43
44 44 @property
45 45 def default_config(self):
46 46 c = Config({
47 'CSSHTMLHeaderTransformer':{
47 'CSSHTMLHeaderPreprocessor':{
48 48 'enabled':True
49 49 }
50 50 })
51 51 c.merge(super(HTMLExporter,self).default_config)
52 52 return c
@@ -1,91 +1,91 b''
1 1 """
2 2 Exporter that allows Latex Jinja templates to work. Contains logic to
3 3 appropriately prepare IPYNB files for export to LaTeX. Including but
4 4 not limited to escaping LaTeX, fixing math region tags, using special
5 5 tags to circumvent Jinja/Latex syntax conflicts.
6 6 """
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (c) 2013, the IPython Development Team.
9 9 #
10 10 # Distributed under the terms of the Modified BSD License.
11 11 #
12 12 # The full license is in the file COPYING.txt, distributed with this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 # Stdlib imports
20 20 import os
21 21
22 22 # IPython imports
23 23 from IPython.utils.traitlets import Unicode, List
24 24 from IPython.config import Config
25 25
26 from IPython.nbconvert import filters, transformers
26 from IPython.nbconvert import filters, preprocessors
27 27 from .exporter import Exporter
28 28
29 29 #-----------------------------------------------------------------------------
30 30 # Classes and functions
31 31 #-----------------------------------------------------------------------------
32 32
33 33 class LatexExporter(Exporter):
34 34 """
35 35 Exports to a Latex template. Inherit from this class if your template is
36 36 LaTeX based and you need custom tranformers/filters. Inherit from it if
37 37 you are writing your own HTML template and need custom tranformers/filters.
38 38 If you don't need custom tranformers/filters, just change the
39 39 'template_file' config option. Place your template in the special "/latex"
40 40 subfolder of the "../templates" folder.
41 41 """
42 42
43 43 file_extension = Unicode(
44 44 'tex', config=True,
45 45 help="Extension of the file that should be written to disk")
46 46
47 47 default_template = Unicode('article', config=True, help="""Template of the
48 48 data format to use. I.E. 'full' or 'basic'""")
49 49
50 50 #Latex constants
51 51 default_template_path = Unicode(
52 52 os.path.join("..", "templates", "latex"), config=True,
53 53 help="Path where the template files are located.")
54 54
55 55 template_skeleton_path = Unicode(
56 56 os.path.join("..", "templates", "latex", "skeleton"), config=True,
57 57 help="Path where the template skeleton files are located.")
58 58
59 59 #Special Jinja2 syntax that will not conflict when exporting latex.
60 60 jinja_comment_block_start = Unicode("((=", config=True)
61 61 jinja_comment_block_end = Unicode("=))", config=True)
62 62 jinja_variable_block_start = Unicode("(((", config=True)
63 63 jinja_variable_block_end = Unicode(")))", config=True)
64 64 jinja_logic_block_start = Unicode("((*", config=True)
65 65 jinja_logic_block_end = Unicode("*))", config=True)
66 66
67 67 #Extension that the template files use.
68 68 template_extension = Unicode(".tplx", config=True)
69 69
70 70
71 71 @property
72 72 def default_config(self):
73 73 c = Config({
74 74 'NbConvertBase': {
75 75 'display_data_priority' : ['latex', 'pdf', 'png', 'jpg', 'svg', 'jpeg', 'text']
76 76 },
77 'ExtractOutputTransformer': {
77 'ExtractOutputPreprocessor': {
78 78 'enabled':True
79 79 },
80 'SVG2PDFTransformer': {
80 'SVG2PDFPreprocessor': {
81 81 'enabled':True
82 82 },
83 'LatexTransformer': {
83 'LatexPreprocessor': {
84 84 'enabled':True
85 85 },
86 'SphinxTransformer': {
86 'SphinxPreprocessor': {
87 87 'enabled':True
88 88 }
89 89 })
90 90 c.merge(super(LatexExporter,self).default_config)
91 91 return c
@@ -1,38 +1,38 b''
1 1 """
2 2 Exporter for exporting notebooks to restructured text.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 from IPython.utils.traitlets import Unicode
17 17 from IPython.config import Config
18 18
19 19 from .exporter import Exporter
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Classes
23 23 #-----------------------------------------------------------------------------
24 24
25 25 class RSTExporter(Exporter):
26 26 """
27 27 Exports restructured text documents.
28 28 """
29 29
30 30 file_extension = Unicode(
31 31 'rst', config=True,
32 32 help="Extension of the file that should be written to disk")
33 33
34 34 @property
35 35 def default_config(self):
36 c = Config({'ExtractOutputTransformer':{'enabled':True}})
36 c = Config({'ExtractOutputPreprocessor':{'enabled':True}})
37 37 c.merge(super(RSTExporter,self).default_config)
38 38 return c
@@ -1,52 +1,52 b''
1 1 """
2 2 Contains slide show exporter
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 IPython.utils.traitlets import Unicode
18 18
19 from IPython.nbconvert import transformers
19 from IPython.nbconvert import preprocessors
20 20 from IPython.config import Config
21 21
22 22 from .exporter import Exporter
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Classes
26 26 #-----------------------------------------------------------------------------
27 27
28 28 class SlidesExporter(Exporter):
29 29 """
30 30 Exports slides
31 31 """
32 32
33 33 file_extension = Unicode(
34 34 'slides.html', config=True,
35 35 help="Extension of the file that should be written to disk"
36 36 )
37 37
38 38 default_template = Unicode('reveal', config=True, help="""Template of the
39 39 data format to use. I.E. 'reveal'""")
40 40
41 41 @property
42 42 def default_config(self):
43 43 c = Config({
44 'CSSHTMLHeaderTransformer':{
44 'CSSHTMLHeaderPreprocessor':{
45 45 'enabled':True
46 46 },
47 'RevealHelpTransformer':{
47 'RevealHelpPreprocessor':{
48 48 'enabled':True,
49 49 },
50 50 })
51 51 c.merge(super(SlidesExporter,self).default_config)
52 52 return c
@@ -1,48 +1,48 b''
1 1 """
2 Contains CheeseTransformer
2 Contains CheesePreprocessor
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 from ...transformers.base import Transformer
16 from ...preprocessors.base import Preprocessor
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Classes
20 20 #-----------------------------------------------------------------------------
21 21
22 class CheeseTransformer(Transformer):
22 class CheesePreprocessor(Preprocessor):
23 23 """
24 24 Adds a cheese tag to the resources object
25 25 """
26 26
27 27
28 28 def __init__(self, **kw):
29 29 """
30 30 Public constructor
31 31 """
32 super(CheeseTransformer, self).__init__(**kw)
32 super(CheesePreprocessor, self).__init__(**kw)
33 33
34 34
35 def transform(self, nb, resources):
35 def preprocess(self, nb, resources):
36 36 """
37 Sphinx transformation to apply on each notebook.
37 Sphinx preprocessing to apply on each notebook.
38 38
39 39 Parameters
40 40 ----------
41 41 nb : NotebookNode
42 42 Notebook being converted
43 43 resources : dictionary
44 44 Additional resources used in the conversion process. Allows
45 transformers to pass variables into the Jinja engine.
45 preprocessors to pass variables into the Jinja engine.
46 46 """
47 47 resources['cheese'] = 'real'
48 48 return nb, resources
@@ -1,108 +1,108 b''
1 1 """
2 2 Module with tests for exporter.py
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 IPython.config import Config
18 18
19 19 from .base import ExportersTestsBase
20 from .cheese import CheeseTransformer
20 from .cheese import CheesePreprocessor
21 21 from ..exporter import Exporter
22 22
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Class
26 26 #-----------------------------------------------------------------------------
27 27
28 28 class TestExporter(ExportersTestsBase):
29 29 """Contains test functions for exporter.py"""
30 30
31 31
32 32 def test_constructor(self):
33 33 """
34 34 Can an Exporter be constructed?
35 35 """
36 36 Exporter()
37 37
38 38
39 39 def test_export(self):
40 40 """
41 41 Can an Exporter export something?
42 42 """
43 43 exporter = self._make_exporter()
44 44 (output, resources) = exporter.from_filename(self._get_notebook())
45 45 assert len(output) > 0
46 46
47 47
48 48 def test_extract_outputs(self):
49 49 """
50 If the ExtractOutputTransformer is enabled, are outputs extracted?
50 If the ExtractOutputPreprocessor is enabled, are outputs extracted?
51 51 """
52 config = Config({'ExtractOutputTransformer': {'enabled': True}})
52 config = Config({'ExtractOutputPreprocessor': {'enabled': True}})
53 53 exporter = self._make_exporter(config=config)
54 54 (output, resources) = exporter.from_filename(self._get_notebook())
55 55 assert resources is not None
56 56 assert isinstance(resources['outputs'], dict)
57 57 assert len(resources['outputs']) > 0
58 58
59 59
60 def test_transformer_class(self):
60 def test_preprocessor_class(self):
61 61 """
62 Can a transformer be added to the transformers list by class type?
62 Can a preprocessor be added to the preprocessors list by class type?
63 63 """
64 config = Config({'Exporter': {'transformers': [CheeseTransformer]}})
64 config = Config({'Exporter': {'preprocessors': [CheesePreprocessor]}})
65 65 exporter = self._make_exporter(config=config)
66 66 (output, resources) = exporter.from_filename(self._get_notebook())
67 67 assert resources is not None
68 68 assert resources['cheese'] == 'real'
69 69
70 70
71 def test_transformer_instance(self):
71 def test_preprocessor_instance(self):
72 72 """
73 Can a transformer be added to the transformers list by instance?
73 Can a preprocessor be added to the preprocessors list by instance?
74 74 """
75 config = Config({'Exporter': {'transformers': [CheeseTransformer()]}})
75 config = Config({'Exporter': {'preprocessors': [CheesePreprocessor()]}})
76 76 exporter = self._make_exporter(config=config)
77 77 (output, resources) = exporter.from_filename(self._get_notebook())
78 78 assert resources is not None
79 79 assert resources['cheese'] == 'real'
80 80
81 81
82 def test_transformer_dottedobjectname(self):
82 def test_preprocessor_dottedobjectname(self):
83 83 """
84 Can a transformer be added to the transformers list by dotted object name?
84 Can a preprocessor be added to the preprocessors list by dotted object name?
85 85 """
86 config = Config({'Exporter': {'transformers': ['IPython.nbconvert.exporters.tests.cheese.CheeseTransformer']}})
86 config = Config({'Exporter': {'preprocessors': ['IPython.nbconvert.exporters.tests.cheese.CheesePreprocessor']}})
87 87 exporter = self._make_exporter(config=config)
88 88 (output, resources) = exporter.from_filename(self._get_notebook())
89 89 assert resources is not None
90 90 assert resources['cheese'] == 'real'
91 91
92 92
93 def test_transformer_via_method(self):
93 def test_preprocessor_via_method(self):
94 94 """
95 Can a transformer be added via the Exporter convenience method?
95 Can a preprocessor be added via the Exporter convenience method?
96 96 """
97 97 exporter = self._make_exporter()
98 exporter.register_transformer(CheeseTransformer, enabled=True)
98 exporter.register_preprocessor(CheesePreprocessor, enabled=True)
99 99 (output, resources) = exporter.from_filename(self._get_notebook())
100 100 assert resources is not None
101 101 assert resources['cheese'] == 'real'
102 102
103 103
104 104 def _make_exporter(self, config=None):
105 105 #Create the exporter instance, make sure to set a template name since
106 106 #the base Exporter doesn't have a template associated with it.
107 107 exporter = Exporter(config=config, template_file='python')
108 return exporter No newline at end of file
108 return exporter
@@ -1,322 +1,322 b''
1 1 #!/usr/bin/env python
2 2 """NBConvert is a utility for conversion of .ipynb files.
3 3
4 4 Command-line interface for the NbConvert conversion utility.
5 5 """
6 6 #-----------------------------------------------------------------------------
7 7 #Copyright (c) 2013, 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 # Stdlib imports
19 19 from __future__ import print_function
20 20
21 21 import logging
22 22 import sys
23 23 import os
24 24 import glob
25 25
26 26 # From IPython
27 27 from IPython.core.application import BaseIPythonApplication, base_aliases, base_flags
28 28 from IPython.config import catch_config_error, Configurable
29 29 from IPython.utils.traitlets import (
30 30 Unicode, List, Instance, DottedObjectName, Type, CaselessStrEnum,
31 31 )
32 32 from IPython.utils.importstring import import_item
33 33 from IPython.utils.text import dedent
34 34
35 35 from .exporters.export import get_export_names, exporter_map
36 from IPython.nbconvert import exporters, transformers, writers, post_processors
36 from IPython.nbconvert import exporters, preprocessors, writers, post_processors
37 37 from .utils.base import NbConvertBase
38 38 from .utils.exceptions import ConversionException
39 39
40 40 #-----------------------------------------------------------------------------
41 41 #Classes and functions
42 42 #-----------------------------------------------------------------------------
43 43
44 44 class DottedOrNone(DottedObjectName):
45 45 """
46 46 A string holding a valid dotted object name in Python, such as A.b3._c
47 47 Also allows for None type."""
48 48
49 49 default_value = u''
50 50
51 51 def validate(self, obj, value):
52 52 if value is not None and len(value) > 0:
53 53 return super(DottedOrNone, self).validate(obj, value)
54 54 else:
55 55 return value
56 56
57 57 nbconvert_aliases = {}
58 58 nbconvert_aliases.update(base_aliases)
59 59 nbconvert_aliases.update({
60 60 'to' : 'NbConvertApp.export_format',
61 61 'template' : 'Exporter.template_file',
62 62 'writer' : 'NbConvertApp.writer_class',
63 63 'post': 'NbConvertApp.post_processor_class',
64 64 'output': 'NbConvertApp.output_base',
65 65 'offline-slides': 'RevealHelpTransformer.url_prefix',
66 66 'slide-notes': 'RevealHelpTransformer.speaker_notes'
67 67 })
68 68
69 69 nbconvert_flags = {}
70 70 nbconvert_flags.update(base_flags)
71 71 nbconvert_flags.update({
72 72 'stdout' : (
73 73 {'NbConvertApp' : {'writer_class' : "StdoutWriter"}},
74 74 "Write notebook output to stdout instead of files."
75 75 )
76 76 })
77 77
78 78
79 79 class NbConvertApp(BaseIPythonApplication):
80 80 """Application used to convert to and from notebook file type (*.ipynb)"""
81 81
82 82 name = 'ipython-nbconvert'
83 83 aliases = nbconvert_aliases
84 84 flags = nbconvert_flags
85 85
86 86 def _log_level_default(self):
87 87 return logging.INFO
88 88
89 89 def _classes_default(self):
90 90 classes = [NbConvertBase]
91 for pkg in (exporters, transformers, writers):
91 for pkg in (exporters, preprocessors, writers):
92 92 for name in dir(pkg):
93 93 cls = getattr(pkg, name)
94 94 if isinstance(cls, type) and issubclass(cls, Configurable):
95 95 classes.append(cls)
96 96 return classes
97 97
98 98 description = Unicode(
99 99 u"""This application is used to convert notebook files (*.ipynb)
100 100 to various other formats.
101 101
102 102 WARNING: THE COMMANDLINE INTERFACE MAY CHANGE IN FUTURE RELEASES.""")
103 103
104 104 output_base = Unicode('', config=True, help='''overwrite base name use for output files.
105 105 can only be use when converting one notebook at a time.
106 106 ''')
107 107
108 108 examples = Unicode(u"""
109 109 The simplest way to use nbconvert is
110 110
111 111 > ipython nbconvert mynotebook.ipynb
112 112
113 113 which will convert mynotebook.ipynb to the default format (probably HTML).
114 114
115 115 You can specify the export format with `--to`.
116 116 Options include {0}
117 117
118 118 > ipython nbconvert --to latex mynotebook.ipnynb
119 119
120 120 Both HTML and LaTeX support multiple output templates. LaTeX includes
121 121 'basic', 'book', and 'article'. HTML includes 'basic' and 'full'. You
122 122 can specify the flavor of the format used.
123 123
124 124 > ipython nbconvert --to html --template basic mynotebook.ipynb
125 125
126 126 You can also pipe the output to stdout, rather than a file
127 127
128 128 > ipython nbconvert mynotebook.ipynb --stdout
129 129
130 130 A post-processor can be used to compile a PDF
131 131
132 132 > ipython nbconvert mynotebook.ipynb --to latex --post PDF
133 133
134 134 You can get (and serve) a Reveal.js-powered slideshow
135 135
136 136 > ipython nbconvert myslides.ipynb --to slides --post serve
137 137
138 138 Multiple notebooks can be given at the command line in a couple of
139 139 different ways:
140 140
141 141 > ipython nbconvert notebook*.ipynb
142 142 > ipython nbconvert notebook1.ipynb notebook2.ipynb
143 143
144 144 or you can specify the notebooks list in a config file, containing::
145 145
146 146 c.NbConvertApp.notebooks = ["my_notebook.ipynb"]
147 147
148 148 > ipython nbconvert --config mycfg.py
149 149 """.format(get_export_names()))
150 150
151 151 # Writer specific variables
152 152 writer = Instance('IPython.nbconvert.writers.base.WriterBase',
153 153 help="""Instance of the writer class used to write the
154 154 results of the conversion.""")
155 155 writer_class = DottedObjectName('FilesWriter', config=True,
156 156 help="""Writer class used to write the
157 157 results of the conversion""")
158 158 writer_aliases = {'fileswriter': 'IPython.nbconvert.writers.files.FilesWriter',
159 159 'debugwriter': 'IPython.nbconvert.writers.debug.DebugWriter',
160 160 'stdoutwriter': 'IPython.nbconvert.writers.stdout.StdoutWriter'}
161 161 writer_factory = Type()
162 162
163 163 def _writer_class_changed(self, name, old, new):
164 164 if new.lower() in self.writer_aliases:
165 165 new = self.writer_aliases[new.lower()]
166 166 self.writer_factory = import_item(new)
167 167
168 168 # Post-processor specific variables
169 169 post_processor = Instance('IPython.nbconvert.post_processors.base.PostProcessorBase',
170 170 help="""Instance of the PostProcessor class used to write the
171 171 results of the conversion.""")
172 172
173 173 post_processor_class = DottedOrNone(config=True,
174 174 help="""PostProcessor class used to write the
175 175 results of the conversion""")
176 176 post_processor_aliases = {'pdf': 'IPython.nbconvert.post_processors.pdf.PDFPostProcessor',
177 177 'serve': 'IPython.nbconvert.post_processors.serve.ServePostProcessor'}
178 178 post_processor_factory = Type()
179 179
180 180 def _post_processor_class_changed(self, name, old, new):
181 181 if new.lower() in self.post_processor_aliases:
182 182 new = self.post_processor_aliases[new.lower()]
183 183 if new:
184 184 self.post_processor_factory = import_item(new)
185 185
186 186
187 187 # Other configurable variables
188 188 export_format = CaselessStrEnum(get_export_names(),
189 189 default_value="html",
190 190 config=True,
191 191 help="""The export format to be used."""
192 192 )
193 193
194 194 notebooks = List([], config=True, help="""List of notebooks to convert.
195 195 Wildcards are supported.
196 196 Filenames passed positionally will be added to the list.
197 197 """)
198 198
199 199 @catch_config_error
200 200 def initialize(self, argv=None):
201 201 super(NbConvertApp, self).initialize(argv)
202 202 self.init_syspath()
203 203 self.init_notebooks()
204 204 self.init_writer()
205 205 self.init_post_processor()
206 206
207 207
208 208
209 209 def init_syspath(self):
210 210 """
211 211 Add the cwd to the sys.path ($PYTHONPATH)
212 212 """
213 213 sys.path.insert(0, os.getcwd())
214 214
215 215
216 216 def init_notebooks(self):
217 217 """Construct the list of notebooks.
218 218 If notebooks are passed on the command-line,
219 219 they override notebooks specified in config files.
220 220 Glob each notebook to replace notebook patterns with filenames.
221 221 """
222 222
223 223 # Specifying notebooks on the command-line overrides (rather than adds)
224 224 # the notebook list
225 225 if self.extra_args:
226 226 patterns = self.extra_args
227 227 else:
228 228 patterns = self.notebooks
229 229
230 230 # Use glob to replace all the notebook patterns with filenames.
231 231 filenames = []
232 232 for pattern in patterns:
233 233
234 234 # Use glob to find matching filenames. Allow the user to convert
235 235 # notebooks without having to type the extension.
236 236 globbed_files = glob.glob(pattern)
237 237 globbed_files.extend(glob.glob(pattern + '.ipynb'))
238 238 if not globbed_files:
239 239 self.log.warn("pattern %r matched no files", pattern)
240 240
241 241 for filename in globbed_files:
242 242 if not filename in filenames:
243 243 filenames.append(filename)
244 244 self.notebooks = filenames
245 245
246 246 def init_writer(self):
247 247 """
248 248 Initialize the writer (which is stateless)
249 249 """
250 250 self._writer_class_changed(None, self.writer_class, self.writer_class)
251 251 self.writer = self.writer_factory(parent=self)
252 252
253 253 def init_post_processor(self):
254 254 """
255 255 Initialize the post_processor (which is stateless)
256 256 """
257 257 self._post_processor_class_changed(None, self.post_processor_class,
258 258 self.post_processor_class)
259 259 if self.post_processor_factory:
260 260 self.post_processor = self.post_processor_factory(parent=self)
261 261
262 262 def start(self):
263 263 """
264 264 Ran after initialization completed
265 265 """
266 266 super(NbConvertApp, self).start()
267 267 self.convert_notebooks()
268 268
269 269 def convert_notebooks(self):
270 270 """
271 271 Convert the notebooks in the self.notebook traitlet
272 272 """
273 273 # Export each notebook
274 274 conversion_success = 0
275 275
276 276 if self.output_base != '' and len(self.notebooks) > 1:
277 277 self.log.error(
278 278 """UsageError: --output flag or `NbConvertApp.output_base` config option
279 279 cannot be used when converting multiple notebooks.
280 280 """)
281 281 self.exit(1)
282 282
283 283 exporter = exporter_map[self.export_format](config=self.config)
284 284
285 285 for notebook_filename in self.notebooks:
286 286 self.log.info("Converting notebook %s to %s", notebook_filename, self.export_format)
287 287
288 288 # Get a unique key for the notebook and set it in the resources object.
289 289 basename = os.path.basename(notebook_filename)
290 290 notebook_name = basename[:basename.rfind('.')]
291 291 if self.output_base:
292 292 notebook_name = self.output_base
293 293 resources = {}
294 294 resources['unique_key'] = notebook_name
295 295 resources['output_files_dir'] = '%s_files' % notebook_name
296 296 self.log.info("Support files will be in %s", os.path.join(resources['output_files_dir'], ''))
297 297
298 298 # Try to export
299 299 try:
300 300 output, resources = exporter.from_filename(notebook_filename, resources=resources)
301 301 except ConversionException as e:
302 302 self.log.error("Error while converting '%s'", notebook_filename,
303 303 exc_info=True)
304 304 self.exit(1)
305 305 else:
306 306 write_resultes = self.writer.write(output, resources, notebook_name=notebook_name)
307 307
308 308 #Post-process if post processor has been defined.
309 309 if hasattr(self, 'post_processor') and self.post_processor:
310 310 self.post_processor(write_resultes)
311 311 conversion_success += 1
312 312
313 313 # If nothing was converted successfully, help the user.
314 314 if conversion_success == 0:
315 315 self.print_help()
316 316 sys.exit(-1)
317 317
318 318 #-----------------------------------------------------------------------------
319 319 # Main entry point
320 320 #-----------------------------------------------------------------------------
321 321
322 322 launch_new_instance = NbConvertApp.launch_instance
@@ -1,12 +1,12 b''
1 # Class base Transformers
2 from .base import Transformer
3 from .convertfigures import ConvertFiguresTransformer
4 from .svg2pdf import SVG2PDFTransformer
5 from .extractoutput import ExtractOutputTransformer
6 from .revealhelp import RevealHelpTransformer
7 from .latex import LatexTransformer
8 from .sphinx import SphinxTransformer
9 from .csshtmlheader import CSSHTMLHeaderTransformer
1 # Class base Preprocessors
2 from .base import Preprocessor
3 from .convertfigures import ConvertFiguresPreprocessor
4 from .svg2pdf import SVG2PDFPreprocessor
5 from .extractoutput import ExtractOutputPreprocessor
6 from .revealhelp import RevealHelpPreprocessor
7 from .latex import LatexPreprocessor
8 from .sphinx import SphinxPreprocessor
9 from .csshtmlheader import CSSHTMLHeaderPreprocessor
10 10
11 # decorated function Transformers
11 # decorated function Preprocessors
12 12 from .coalescestreams import coalesce_streams
@@ -1,110 +1,110 b''
1 1 """
2 Module that re-groups transformer that would be applied to ipynb files
2 Module that re-groups preprocessor that would be applied to ipynb files
3 3 before going through the templating machinery.
4 4
5 5 It exposes a convenient class to inherit from to access configurability.
6 6 """
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (c) 2013, the IPython Development Team.
9 9 #
10 10 # Distributed under the terms of the Modified BSD License.
11 11 #
12 12 # The full license is in the file COPYING.txt, distributed with this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 from ..utils.base import NbConvertBase
20 20 from IPython.utils.traitlets import Bool
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Classes and Functions
24 24 #-----------------------------------------------------------------------------
25 25
26 class Transformer(NbConvertBase):
27 """ A configurable transformer
26 class Preprocessor(NbConvertBase):
27 """ A configurable preprocessor
28 28
29 29 Inherit from this class if you wish to have configurability for your
30 transformer.
30 preprocessor.
31 31
32 32 Any configurable traitlets this class exposed will be configurable in profiles
33 33 using c.SubClassName.atribute=value
34 34
35 you can overwrite :meth:`transform_cell` to apply a transformation independently on each cell
36 or :meth:`transform` if you prefer your own logic. See corresponding docstring for informations.
35 you can overwrite :meth:`preprocess_cell` to apply a preprocessation independently on each cell
36 or :meth:`preprocess` if you prefer your own logic. See corresponding docstring for informations.
37 37
38 38 Disabled by default and can be enabled via the config by
39 'c.YourTransformerName.enabled = True'
39 'c.YourPreprocessorName.enabled = True'
40 40 """
41 41
42 42 enabled = Bool(False, config=True)
43 43
44 44 def __init__(self, **kw):
45 45 """
46 46 Public constructor
47 47
48 48 Parameters
49 49 ----------
50 50 config : Config
51 51 Configuration file structure
52 52 **kw : misc
53 53 Additional arguments
54 54 """
55 55
56 super(Transformer, self).__init__(**kw)
56 super(Preprocessor, self).__init__(**kw)
57 57
58 58
59 59 def __call__(self, nb, resources):
60 60 if self.enabled:
61 return self.transform(nb,resources)
61 return self.preprocess(nb,resources)
62 62 else:
63 63 return nb, resources
64 64
65 65
66 def transform(self, nb, resources):
66 def preprocess(self, nb, resources):
67 67 """
68 Transformation to apply on each notebook.
68 preprocessation to apply on each notebook.
69 69
70 70 You should return modified nb, resources.
71 If you wish to apply your transform on each cell, you might want to
72 overwrite transform_cell method instead.
71 If you wish to apply your preprocess on each cell, you might want to
72 overwrite preprocess_cell method instead.
73 73
74 74 Parameters
75 75 ----------
76 76 nb : NotebookNode
77 77 Notebook being converted
78 78 resources : dictionary
79 79 Additional resources used in the conversion process. Allows
80 transformers to pass variables into the Jinja engine.
80 preprocessors to pass variables into the Jinja engine.
81 81 """
82 self.log.debug("Applying transform: %s", self.__class__.__name__)
82 self.log.debug("Applying preprocess: %s", self.__class__.__name__)
83 83 try :
84 84 for worksheet in nb.worksheets:
85 85 for index, cell in enumerate(worksheet.cells):
86 worksheet.cells[index], resources = self.transform_cell(cell, resources, index)
86 worksheet.cells[index], resources = self.preprocess_cell(cell, resources, index)
87 87 return nb, resources
88 88 except NotImplementedError:
89 89 raise NotImplementedError('should be implemented by subclass')
90 90
91 91
92 def transform_cell(self, cell, resources, index):
92 def preprocess_cell(self, cell, resources, index):
93 93 """
94 Overwrite if you want to apply a transformation on each cell. You
94 Overwrite if you want to apply a preprocessation on each cell. You
95 95 should return modified cell and resource dictionary.
96 96
97 97 Parameters
98 98 ----------
99 99 cell : NotebookNode cell
100 100 Notebook cell being processed
101 101 resources : dictionary
102 102 Additional resources used in the conversion process. Allows
103 transformers to pass variables into the Jinja engine.
103 preprocessors to pass variables into the Jinja engine.
104 104 index : int
105 105 Index of the cell being processed
106 106 """
107 107
108 108 raise NotImplementedError('should be implemented by subclass')
109 109 return cell, resources
110 110
@@ -1,75 +1,75 b''
1 1 """Module that allows latex output notebooks to be conditioned before
2 2 they are converted. Exposes a decorator (@cell_preprocessor) in
3 3 addition to the coalesce_streams pre-proccessor.
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 # Functions
15 15 #-----------------------------------------------------------------------------
16 16
17 17 def cell_preprocessor(function):
18 18 """
19 19 Wrap a function to be executed on all cells of a notebook
20 20
21 21 Wrapped Parameters
22 22 ----------
23 23 cell : NotebookNode cell
24 24 Notebook cell being processed
25 25 resources : dictionary
26 26 Additional resources used in the conversion process. Allows
27 transformers to pass variables into the Jinja engine.
27 preprocessors to pass variables into the Jinja engine.
28 28 index : int
29 29 Index of the cell being processed
30 30 """
31 31
32 32 def wrappedfunc(nb, resources):
33 33 for worksheet in nb.worksheets :
34 34 for index, cell in enumerate(worksheet.cells):
35 35 worksheet.cells[index], resources = function(cell, resources, index)
36 36 return nb, resources
37 37 return wrappedfunc
38 38
39 39
40 40 @cell_preprocessor
41 41 def coalesce_streams(cell, resources, index):
42 42 """
43 43 Merge consecutive sequences of stream output into single stream
44 44 to prevent extra newlines inserted at flush calls
45 45
46 46 Parameters
47 47 ----------
48 48 cell : NotebookNode cell
49 49 Notebook cell being processed
50 50 resources : dictionary
51 51 Additional resources used in the conversion process. Allows
52 52 transformers to pass variables into the Jinja engine.
53 53 index : int
54 54 Index of the cell being processed
55 55 """
56 56
57 57 outputs = cell.get('outputs', [])
58 58 if not outputs:
59 59 return cell, resources
60 60
61 61 last = outputs[0]
62 62 new_outputs = [last]
63 63
64 64 for output in outputs[1:]:
65 65 if (output.output_type == 'stream' and
66 66 last.output_type == 'stream' and
67 67 last.stream == output.stream
68 68 ):
69 69 last.text += output.text
70 70 else:
71 71 new_outputs.append(output)
72 72 last = output
73 73
74 74 cell.outputs = new_outputs
75 75 return cell, resources
@@ -1,64 +1,64 b''
1 """Module containing a transformer that converts outputs in the notebook from
1 """Module containing a preprocessor that converts outputs in the notebook from
2 2 one format to another.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 from .base import Transformer
16 from .base import Preprocessor
17 17 from IPython.utils.traitlets import Unicode
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Classes
21 21 #-----------------------------------------------------------------------------
22 22
23 class ConvertFiguresTransformer(Transformer):
23 class ConvertFiguresPreprocessor(Preprocessor):
24 24 """
25 25 Converts all of the outputs in a notebook from one format to another.
26 26 """
27 27
28 28 from_format = Unicode(config=True, help='Format the converter accepts')
29 29 to_format = Unicode(config=True, help='Format the converter writes')
30 30
31 31 def __init__(self, **kw):
32 32 """
33 33 Public constructor
34 34 """
35 super(ConvertFiguresTransformer, self).__init__(**kw)
35 super(ConvertFiguresPreprocessor, self).__init__(**kw)
36 36
37 37
38 38 def convert_figure(self, data_format, data):
39 39 raise NotImplementedError()
40 40
41 41
42 def transform_cell(self, cell, resources, cell_index):
42 def preprocess_cell(self, cell, resources, cell_index):
43 43 """
44 44 Apply a transformation on each cell,
45 45
46 46 See base.py
47 47 """
48 48
49 49 # Loop through all of the datatypes of the outputs in the cell.
50 50 for index, cell_out in enumerate(cell.get('outputs', [])):
51 51 for data_type, data in cell_out.items():
52 52 # this must run *before* extract outputs,
53 53 # so figure_name and filename do not exist
54 54 self._convert_figure(cell_out, resources, data_type, data)
55 55 return cell, resources
56 56
57 57
58 58 def _convert_figure(self, cell_out, resources, data_type, data):
59 59 """
60 60 Convert a figure and output the results to the cell output
61 61 """
62 62 if not self.to_format in cell_out and data_type == self.from_format:
63 63 data = self.convert_figure(data_type, data)
64 64 cell_out[self.to_format] = data
@@ -1,106 +1,106 b''
1 1 """Module that pre-processes the notebook for export to HTML.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2013, the IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 import os
16 16 import io
17 17
18 18 from pygments.formatters import HtmlFormatter
19 19
20 20 from IPython.utils import path
21 21
22 from .base import Transformer
22 from .base import Preprocessor
23 23
24 24 from IPython.utils.traitlets import Unicode
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Classes and functions
28 28 #-----------------------------------------------------------------------------
29 29
30 class CSSHTMLHeaderTransformer(Transformer):
30 class CSSHTMLHeaderPreprocessor(Preprocessor):
31 31 """
32 Transformer used to pre-process notebook for HTML output. Adds IPython notebook
32 Preprocessor used to pre-process notebook for HTML output. Adds IPython notebook
33 33 front-end CSS and Pygments CSS to HTML output.
34 34 """
35 35
36 36 header = []
37 37
38 38 highlight_class = Unicode('.highlight', config=True,
39 39 help="CSS highlight class identifier")
40 40
41 41 def __init__(self, config=None, **kw):
42 42 """
43 43 Public constructor
44 44
45 45 Parameters
46 46 ----------
47 47 config : Config
48 48 Configuration file structure
49 49 **kw : misc
50 50 Additional arguments
51 51 """
52 52
53 super(CSSHTMLHeaderTransformer, self).__init__(config=config, **kw)
53 super(CSSHTMLHeaderPreprocessor, self).__init__(config=config, **kw)
54 54
55 55 if self.enabled :
56 56 self._regen_header()
57 57
58 58
59 def transform(self, nb, resources):
59 def preprocess(self, nb, resources):
60 60 """Fetch and add CSS to the resource dictionary
61 61
62 62 Fetch CSS from IPython and Pygments to add at the beginning
63 63 of the html files. Add this css in resources in the
64 64 "inlining.css" key
65 65
66 66 Parameters
67 67 ----------
68 68 nb : NotebookNode
69 69 Notebook being converted
70 70 resources : dictionary
71 71 Additional resources used in the conversion process. Allows
72 transformers to pass variables into the Jinja engine.
72 preprocessors to pass variables into the Jinja engine.
73 73 """
74 74
75 75 resources['inlining'] = {}
76 76 resources['inlining']['css'] = self.header
77 77
78 78 return nb, resources
79 79
80 80
81 81 def _regen_header(self):
82 82 """
83 83 Fills self.header with lines of CSS extracted from IPython
84 84 and Pygments.
85 85 """
86 86
87 87 #Clear existing header.
88 88 header = []
89 89
90 90 #Construct path to IPy CSS
91 91 sheet_filename = os.path.join(path.get_ipython_package_dir(),
92 92 'html', 'static', 'style', 'style.min.css')
93 93
94 94 #Load style CSS file.
95 95 with io.open(sheet_filename, encoding='utf-8') as file:
96 96 file_text = file.read()
97 97 header.append(file_text)
98 98
99 99 #Add pygments CSS
100 100 formatter = HtmlFormatter()
101 101 pygments_css = formatter.get_style_defs(self.highlight_class)
102 102 header.append(pygments_css)
103 103
104 104 #Set header
105 105 self.header = header
106 106
@@ -1,102 +1,102 b''
1 """Module containing a transformer that extracts all of the outputs from the
1 """Module containing a preprocessor that extracts all of the outputs from the
2 2 notebook file. The extracted outputs are returned in the 'resources' dictionary.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 import base64
17 17 import sys
18 18 import os
19 19
20 20 from IPython.utils.traitlets import Unicode
21 from .base import Transformer
21 from .base import Preprocessor
22 22 from IPython.utils import py3compat
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Classes
26 26 #-----------------------------------------------------------------------------
27 27
28 class ExtractOutputTransformer(Transformer):
28 class ExtractOutputPreprocessor(Preprocessor):
29 29 """
30 30 Extracts all of the outputs from the notebook file. The extracted
31 31 outputs are returned in the 'resources' dictionary.
32 32 """
33 33
34 34 output_filename_template = Unicode(
35 35 "{unique_key}_{cell_index}_{index}.{extension}", config=True)
36 36
37 37
38 def transform_cell(self, cell, resources, cell_index):
38 def preprocess_cell(self, cell, resources, cell_index):
39 39 """
40 40 Apply a transformation on each cell,
41 41
42 42 Parameters
43 43 ----------
44 44 cell : NotebookNode cell
45 45 Notebook cell being processed
46 46 resources : dictionary
47 47 Additional resources used in the conversion process. Allows
48 transformers to pass variables into the Jinja engine.
48 preprocessors to pass variables into the Jinja engine.
49 49 cell_index : int
50 50 Index of the cell being processed (see base.py)
51 51 """
52 52
53 53 #Get the unique key from the resource dict if it exists. If it does not
54 54 #exist, use 'output' as the default. Also, get files directory if it
55 55 #has been specified
56 56 unique_key = resources.get('unique_key', 'output')
57 57 output_files_dir = resources.get('output_files_dir', None)
58 58
59 59 #Make sure outputs key exists
60 60 if not isinstance(resources['outputs'], dict):
61 61 resources['outputs'] = {}
62 62
63 63 #Loop through all of the outputs in the cell
64 64 for index, out in enumerate(cell.get('outputs', [])):
65 65
66 66 #Get the output in data formats that the template is interested in.
67 67 for out_type in self.display_data_priority:
68 68 if out.hasattr(out_type):
69 69 data = out[out_type]
70 70
71 71 #Binary files are base64-encoded, SVG is already XML
72 72 if out_type in ('png', 'jpg', 'jpeg', 'pdf'):
73 73
74 74 # data is b64-encoded as text (str, unicode)
75 75 # decodestring only accepts bytes
76 76 data = py3compat.cast_bytes(data)
77 77 data = base64.decodestring(data)
78 78 elif sys.platform == 'win32':
79 79 data = data.replace('\n', '\r\n').encode("UTF-8")
80 80 else:
81 81 data = data.encode("UTF-8")
82 82
83 83 #Build an output name
84 84 filename = self.output_filename_template.format(
85 85 unique_key=unique_key,
86 86 cell_index=cell_index,
87 87 index=index,
88 88 extension=out_type)
89 89
90 90 #On the cell, make the figure available via
91 91 # cell.outputs[i].svg_filename ... etc (svg in example)
92 92 # Where
93 93 # cell.outputs[i].svg contains the data
94 94 if output_files_dir is not None:
95 95 filename = os.path.join(output_files_dir, filename)
96 96 out[out_type + '_filename'] = filename
97 97
98 98 #In the resources, make the figure available via
99 99 # resources['outputs']['filename'] = data
100 100 resources['outputs'][filename] = data
101 101
102 102 return cell, resources
@@ -1,53 +1,53 b''
1 1 """Module that allows latex output notebooks to be conditioned before
2 2 they are converted.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 from __future__ import print_function, absolute_import
17 17
18 18 # Our own imports
19 # Needed to override transformer
20 from .base import (Transformer)
19 # Needed to override preprocessor
20 from .base import (Preprocessor)
21 21 from IPython.nbconvert import filters
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Classes
25 25 #-----------------------------------------------------------------------------
26 26
27 class LatexTransformer(Transformer):
27 class LatexPreprocessor(Preprocessor):
28 28 """
29 29 Converter for latex destined documents.
30 30 """
31 31
32 def transform_cell(self, cell, resources, index):
32 def preprocess_cell(self, cell, resources, index):
33 33 """
34 Apply a transformation on each cell,
34 Apply a preprocessation on each cell,
35 35
36 36 Parameters
37 37 ----------
38 38 cell : NotebookNode cell
39 39 Notebook cell being processed
40 40 resources : dictionary
41 41 Additional resources used in the conversion process. Allows
42 transformers to pass variables into the Jinja engine.
42 preprocessors to pass variables into the Jinja engine.
43 43 index : int
44 44 Modified index of the cell being processed (see base.py)
45 45 """
46 46
47 47 #If the cell is a markdown cell, preprocess the ampersands used to
48 48 #remove the space between them and their contents. Latex will complain
49 49 #if spaces exist between the ampersands and the math content.
50 50 #See filters.latex.rm_math_space for more information.
51 51 if hasattr(cell, "source") and cell.cell_type == "markdown":
52 52 cell.source = filters.strip_math_space(cell.source)
53 53 return cell, resources
@@ -1,94 +1,94 b''
1 1 """Module that pre-processes the notebook for export via Reveal.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2013, the IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 import os
16 16 import urllib2
17 17
18 from .base import Transformer
18 from .base import Preprocessor
19 19 from IPython.utils.traitlets import Unicode, Bool
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Classes and functions
23 23 #-----------------------------------------------------------------------------
24 24
25 class RevealHelpTransformer(Transformer):
25 class RevealHelpPreprocessor(Preprocessor):
26 26
27 27 url_prefix = Unicode('//cdn.jsdelivr.net/reveal.js/2.4.0',
28 28 config=True,
29 29 help="""If you want to use a local reveal.js library,
30 30 use 'url_prefix':'reveal.js' in your config object.""")
31 31
32 32 speaker_notes = Bool(False,
33 33 config=True,
34 34 help="""If you want to use the speaker notes
35 35 set this to True.""")
36 36
37 def transform(self, nb, resources):
37 def preprocess(self, nb, resources):
38 38 """
39 Called once to 'transform' contents of the notebook.
39 Called once to 'preprocess' contents of the notebook.
40 40
41 41 Parameters
42 42 ----------
43 43 nb : NotebookNode
44 44 Notebook being converted
45 45 resources : dictionary
46 46 Additional resources used in the conversion process. Allows
47 transformers to pass variables into the Jinja engine.
47 preprocessors to pass variables into the Jinja engine.
48 48 """
49 49
50 50 for worksheet in nb.worksheets :
51 51 for index, cell in enumerate(worksheet.cells):
52 52
53 53 #Make sure the cell has slideshow metadata.
54 54 cell.metadata.align_type = cell.get('metadata', {}).get('slideshow', {}).get('align_type', 'Left')
55 55 cell.metadata.slide_type = cell.get('metadata', {}).get('slideshow', {}).get('slide_type', '-')
56 56
57 57 #Get the slide type. If type is start of subslide or slide,
58 58 #end the last subslide/slide.
59 59 if cell.metadata.slide_type in ['slide']:
60 60 worksheet.cells[index - 1].metadata.slide_helper = 'slide_end'
61 61 if cell.metadata.slide_type in ['subslide']:
62 62 worksheet.cells[index - 1].metadata.slide_helper = 'subslide_end'
63 63
64 64
65 65 if not isinstance(resources['reveal'], dict):
66 66 resources['reveal'] = {}
67 67 resources['reveal']['url_prefix'] = self.url_prefix
68 68 resources['reveal']['notes_prefix'] = self.url_prefix
69 69
70 70 cdn = 'http://cdn.jsdelivr.net/reveal.js/2.4.0'
71 71 local = 'local'
72 72 html_path = 'plugin/notes/notes.html'
73 73 js_path = 'plugin/notes/notes.js'
74 74
75 75 html_infile = os.path.join(cdn, html_path)
76 76 js_infile = os.path.join(cdn, js_path)
77 77 html_outfile = os.path.join(local, html_path)
78 78 js_outfile = os.path.join(local, js_path)
79 79
80 80 if self.speaker_notes:
81 81 if 'outputs' not in resources:
82 82 resources['outputs'] = {}
83 83 resources['outputs'][html_outfile] = self.notes_helper(html_infile)
84 84 resources['outputs'][js_outfile] = self.notes_helper(js_infile)
85 85 resources['reveal']['notes_prefix'] = local
86 86
87 87 return nb, resources
88 88
89 89 def notes_helper(self, infile):
90 90 """Helper function to get the content from an url."""
91 91
92 92 content = urllib2.urlopen(infile).read()
93 93
94 94 return content
@@ -1,264 +1,264 b''
1 1 """Module that allows custom Sphinx parameters to be set on the notebook and
2 2 on the 'other' object passed into Jinja. Called prior to Jinja conversion
3 3 process.
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 os.path
21 21
22 22 # Used to set the default date to today's date
23 23 from datetime import date
24 24
25 25 # Third-party imports
26 26 # Needed for Pygments latex definitions.
27 27 from pygments.formatters import LatexFormatter
28 28
29 29 # Our own imports
30 30 # Configurable traitlets
31 31 from IPython.utils.traitlets import Unicode, Bool
32 32
33 # Needed to override transformer
34 from .base import (Transformer)
33 # Needed to override preprocessor
34 from .base import (Preprocessor)
35 35
36 36 from IPython.nbconvert.utils import console
37 37
38 38 #-----------------------------------------------------------------------------
39 39 # Classes and functions
40 40 #-----------------------------------------------------------------------------
41 41
42 class SphinxTransformer(Transformer):
42 class SphinxPreprocessor(Preprocessor):
43 43 """
44 Sphinx utility transformer.
44 Sphinx utility preprocessor.
45 45
46 This transformer is used to set variables needed by the latex to build
46 This preprocessor is used to set variables needed by the latex to build
47 47 Sphinx stylized templates.
48 48 """
49 49
50 50 interactive = Bool(False, config=True, help="""
51 51 Allows you to define whether or not the Sphinx exporter will prompt
52 52 you for input during the conversion process. If this is set to false,
53 53 the author, version, release, date, and chapter_style traits should
54 54 be set.
55 55 """)
56 56
57 57 author = Unicode("Unknown Author", config=True, help="Author name")
58 58
59 59 version = Unicode("", config=True, help="""
60 60 Version number
61 61 You can leave this blank if you do not want to render a version number.
62 62 Example: "1.0.0"
63 63 """)
64 64
65 65 release = Unicode("", config=True, help="""
66 66 Release name
67 67 You can leave this blank if you do not want to render a release name.
68 68 Example: "Rough Draft"
69 69 """)
70 70
71 71 publish_date = Unicode("", config=True, help="""
72 72 Publish date
73 73 This is the date to render on the document as the publish date.
74 74 Leave this blank to default to todays date.
75 75 Example: "June 12, 1990"
76 76 """)
77 77
78 78 chapter_style = Unicode("Bjarne", config=True, help="""
79 79 Sphinx chapter style
80 80 This is the style to use for the chapter headers in the document.
81 81 You may choose one of the following:
82 82 "Bjarne" (default)
83 83 "Lenny"
84 84 "Glenn"
85 85 "Conny"
86 86 "Rejne"
87 87 "Sonny" (used for international documents)
88 88 """)
89 89
90 90 output_style = Unicode("notebook", config=True, help="""
91 91 Nbconvert Ipython
92 92 notebook input/output formatting style.
93 93 You may choose one of the following:
94 94 "simple (recommended for long code segments)"
95 95 "notebook" (default)
96 96 """)
97 97
98 98 center_output = Bool(False, config=True, help="""
99 99 Optional attempt to center all output. If this is false, no additional
100 100 formatting is applied.
101 101 """)
102 102
103 103 use_headers = Bool(True, config=True, help="""
104 104 Whether not a header should be added to the document.
105 105 """)
106 106
107 107 #Allow the user to override the title of the notebook (useful for
108 108 #fancy document titles that the file system doesn't support.)
109 109 overridetitle = Unicode("", config=True, help="")
110 110
111 111
112 def transform(self, nb, resources):
112 def preprocess(self, nb, resources):
113 113 """
114 Sphinx transformation to apply on each notebook.
114 Sphinx preprocessing to apply on each notebook.
115 115
116 116 Parameters
117 117 ----------
118 118 nb : NotebookNode
119 119 Notebook being converted
120 120 resources : dictionary
121 121 Additional resources used in the conversion process. Allows
122 transformers to pass variables into the Jinja engine.
122 preprocessors to pass variables into the Jinja engine.
123 123 """
124 124 # import sphinx here, so that sphinx is not a dependency when it's not used
125 125 import sphinx
126 126
127 127 # TODO: Add versatile method of additional notebook metadata. Include
128 128 # handling of multiple files. For now use a temporay namespace,
129 129 # '_draft' to signify that this needs to change.
130 130 if not isinstance(resources["sphinx"], dict):
131 131 resources["sphinx"] = {}
132 132
133 133 if self.interactive:
134 134
135 135 # Prompt the user for additional meta data that doesn't exist currently
136 136 # but would be usefull for Sphinx.
137 137 resources["sphinx"]["author"] = self._prompt_author()
138 138 resources["sphinx"]["version"] = self._prompt_version()
139 139 resources["sphinx"]["release"] = self._prompt_release()
140 140 resources["sphinx"]["date"] = self._prompt_date()
141 141
142 142 # Prompt the user for the document style.
143 143 resources["sphinx"]["chapterstyle"] = self._prompt_chapter_title_style()
144 144 resources["sphinx"]["outputstyle"] = self._prompt_output_style()
145 145
146 146 # Small options
147 147 resources["sphinx"]["centeroutput"] = console.prompt_boolean("Do you want to center the output? (false)", False)
148 148 resources["sphinx"]["header"] = console.prompt_boolean("Should a Sphinx document header be used? (true)", True)
149 149 else:
150 150
151 151 # Try to use the traitlets.
152 152 resources["sphinx"]["author"] = self.author
153 153 resources["sphinx"]["version"] = self.version
154 154 resources["sphinx"]["release"] = self.release
155 155
156 156 # Use todays date if none is provided.
157 157 if self.publish_date:
158 158 resources["sphinx"]["date"] = self.publish_date
159 159 elif len(resources['metadata']['modified_date'].strip()) == 0:
160 160 resources["sphinx"]["date"] = date.today().strftime("%B %-d, %Y")
161 161 else:
162 162 resources["sphinx"]["date"] = resources['metadata']['modified_date']
163 163
164 164 # Sphinx traitlets.
165 165 resources["sphinx"]["chapterstyle"] = self.chapter_style
166 166 resources["sphinx"]["outputstyle"] = self.output_style
167 167 resources["sphinx"]["centeroutput"] = self.center_output
168 168 resources["sphinx"]["header"] = self.use_headers
169 169
170 170 # Find and pass in the path to the Sphinx dependencies.
171 171 resources["sphinx"]["texinputs"] = os.path.realpath(os.path.join(sphinx.package_dir, "texinputs"))
172 172
173 173 # Generate Pygments definitions for Latex
174 174 resources["sphinx"]["pygment_definitions"] = self._generate_pygments_latex_def()
175 175
176 176 if not (self.overridetitle == None or len(self.overridetitle.strip()) == 0):
177 177 resources['metadata']['name'] = self.overridetitle
178 178
179 179 # End
180 180 return nb, resources
181 181
182 182
183 183 def _generate_pygments_latex_def(self):
184 184 """
185 185 Generate the pygments latex definitions that allows pygments
186 186 to work in latex.
187 187 """
188 188
189 189 return LatexFormatter().get_style_defs()
190 190
191 191
192 192 def _prompt_author(self):
193 193 """
194 194 Prompt the user to input an Author name
195 195 """
196 196 return console.input("Author name: ")
197 197
198 198
199 199 def _prompt_version(self):
200 200 """
201 201 prompt the user to enter a version number
202 202 """
203 203 return console.input("Version (ie ""1.0.0""): ")
204 204
205 205
206 206 def _prompt_release(self):
207 207 """
208 208 Prompt the user to input a release name
209 209 """
210 210
211 211 return console.input("Release Name (ie ""Rough draft""): ")
212 212
213 213
214 214 def _prompt_date(self, resources):
215 215 """
216 216 Prompt the user to enter a date
217 217 """
218 218
219 219 if resources['metadata']['modified_date']:
220 220 default_date = resources['metadata']['modified_date']
221 221 else:
222 222 default_date = date.today().strftime("%B %-d, %Y")
223 223
224 224 user_date = console.input("Date (deafults to \"" + default_date + "\"): ")
225 225 if len(user_date.strip()) == 0:
226 226 user_date = default_date
227 227 return user_date
228 228
229 229
230 230 def _prompt_output_style(self):
231 231 """
232 232 Prompts the user to pick an IPython output style.
233 233 """
234 234
235 235 # Dictionary of available output styles
236 236 styles = {1: "simple",
237 237 2: "notebook"}
238 238
239 239 #Append comments to the menu when displaying it to the user.
240 240 comments = {1: "(recommended for long code segments)",
241 241 2: "(default)"}
242 242
243 243 return console.prompt_dictionary(styles, default_style=2, menu_comments=comments)
244 244
245 245
246 246 def _prompt_chapter_title_style(self):
247 247 """
248 248 Prompts the user to pick a Sphinx chapter style
249 249 """
250 250
251 251 # Dictionary of available Sphinx styles
252 252 styles = {1: "Bjarne",
253 253 2: "Lenny",
254 254 3: "Glenn",
255 255 4: "Conny",
256 256 5: "Rejne",
257 257 6: "Sonny"}
258 258
259 259 #Append comments to the menu when displaying it to the user.
260 260 comments = {1: "(default)",
261 261 6: "(for international documents)"}
262 262
263 263 return console.prompt_dictionary(styles, menu_comments=comments)
264 264
@@ -1,95 +1,95 b''
1 """Module containing a transformer that converts outputs in the notebook from
1 """Module containing a preprocessor that converts outputs in the notebook from
2 2 one format to another.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 import base64
17 17 import io
18 18 import os
19 19 import sys
20 20 import subprocess
21 21
22 22 from IPython.utils.tempdir import TemporaryDirectory
23 23 from IPython.utils.traitlets import Unicode
24 24
25 from .convertfigures import ConvertFiguresTransformer
25 from .convertfigures import ConvertFiguresPreprocessor
26 26
27 27
28 28 #-----------------------------------------------------------------------------
29 29 # Constants
30 30 #-----------------------------------------------------------------------------
31 31
32 32 INKSCAPE_APP = '/Applications/Inkscape.app/Contents/Resources/bin/inkscape'
33 33
34 34 #-----------------------------------------------------------------------------
35 35 # Classes
36 36 #-----------------------------------------------------------------------------
37 37
38 class SVG2PDFTransformer(ConvertFiguresTransformer):
38 class SVG2PDFPreprocessor(ConvertFiguresPreprocessor):
39 39 """
40 40 Converts all of the outputs in a notebook from SVG to PDF.
41 41 """
42 42
43 43 from_format = Unicode('svg', config=True, help='Format the converter accepts')
44 44 to_format = Unicode('pdf', config=False, help='Format the converter writes')
45 45
46 46 command = Unicode(config=True,
47 47 help="""The command to use for converting SVG to PDF
48 48
49 49 This string is a template, which will be formatted with the keys
50 50 to_filename and from_filename.
51 51
52 52 The conversion call must read the SVG from {from_flename},
53 53 and write a PDF to {to_filename}.
54 54 """)
55 55
56 56 def _command_default(self):
57 57 return self.inkscape + \
58 58 ' --without-gui --export-pdf="{to_filename}" "{from_filename}"'
59 59
60 60 inkscape = Unicode(config=True, help="The path to Inkscape, if necessary")
61 61 def _inkscape_default(self):
62 62 if sys.platform == "darwin":
63 63 if os.path.isfile(INKSCAPE_APP):
64 64 return INKSCAPE_APP
65 65 return "inkscape"
66 66
67 67
68 68 def convert_figure(self, data_format, data):
69 69 """
70 70 Convert a single SVG figure to PDF. Returns converted data.
71 71 """
72 72
73 73 #Work in a temporary directory
74 74 with TemporaryDirectory() as tmpdir:
75 75
76 76 #Write fig to temp file
77 77 input_filename = os.path.join(tmpdir, 'figure.' + data_format)
78 78 # SVG data is unicode text
79 79 with io.open(input_filename, 'w', encoding='utf8') as f:
80 80 f.write(data)
81 81
82 82 #Call conversion application
83 83 output_filename = os.path.join(tmpdir, 'figure.pdf')
84 84 shell = self.command.format(from_filename=input_filename,
85 85 to_filename=output_filename)
86 86 subprocess.call(shell, shell=True) #Shell=True okay since input is trusted.
87 87
88 88 #Read output from drive
89 89 # return value expects a filename
90 90 if os.path.isfile(output_filename):
91 91 with open(output_filename, 'rb') as f:
92 92 # PDF is a nb supported binary, data type, so base64 encode.
93 93 return base64.encodestring(f.read())
94 94 else:
95 95 raise TypeError("Inkscape svg to png conversion failed")
@@ -1,53 +1,53 b''
1 1 """
2 Module with utility functions for transformer tests
2 Module with utility functions for preprocessor tests
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 IPython.nbformat import current as nbformat
18 18
19 19 from ...tests.base import TestsBase
20 20 from ...exporters.exporter import ResourcesDict
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Class
24 24 #-----------------------------------------------------------------------------
25 25
26 class TransformerTestsBase(TestsBase):
27 """Contains test functions transformer tests"""
26 class PreprocessorTestsBase(TestsBase):
27 """Contains test functions preprocessor tests"""
28 28
29 29
30 30 def build_notebook(self):
31 """Build a notebook in memory for use with transformer tests"""
31 """Build a notebook in memory for use with preprocessor tests"""
32 32
33 33 outputs = [nbformat.new_output(output_type="stream", stream="stdout", output_text="a"),
34 34 nbformat.new_output(output_type="text", output_text="b"),
35 35 nbformat.new_output(output_type="stream", stream="stdout", output_text="c"),
36 36 nbformat.new_output(output_type="stream", stream="stdout", output_text="d"),
37 37 nbformat.new_output(output_type="stream", stream="stderr", output_text="e"),
38 38 nbformat.new_output(output_type="stream", stream="stderr", output_text="f"),
39 39 nbformat.new_output(output_type="png", output_png=b'Zw==')] #g
40 40
41 41 cells=[nbformat.new_code_cell(input="$ e $", prompt_number=1,outputs=outputs),
42 42 nbformat.new_text_cell('markdown', source="$ e $")]
43 43 worksheets = [nbformat.new_worksheet(name="worksheet1", cells=cells)]
44 44
45 45 return nbformat.new_notebook(name="notebook1", worksheets=worksheets)
46 46
47 47
48 48 def build_resources(self):
49 49 """Build an empty resources dictionary."""
50 50
51 51 res = ResourcesDict()
52 52 res['metadata'] = ResourcesDict()
53 return res No newline at end of file
53 return res
@@ -1,38 +1,38 b''
1 1 """
2 Module with tests for the coalescestreams transformer
2 Module with tests for the coalescestreams preprocessor
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 from .base import TransformerTestsBase
17 from .base import PreprocessorTestsBase
18 18 from ..coalescestreams import coalesce_streams
19 19
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Class
23 23 #-----------------------------------------------------------------------------
24 24
25 class TestCoalesceStreams(TransformerTestsBase):
25 class TestCoalesceStreams(PreprocessorTestsBase):
26 26 """Contains test functions for coalescestreams.py"""
27 27
28 28 def test_coalesce_streams(self):
29 """coalesce_streams transformer output test"""
29 """coalesce_streams preprocessor output test"""
30 30 nb = self.build_notebook()
31 31 res = self.build_resources()
32 32 nb, res = coalesce_streams(nb, res)
33 33 outputs = nb.worksheets[0].cells[0].outputs
34 34 self.assertEqual(outputs[0].text, "a")
35 35 self.assertEqual(outputs[1].output_type, "text")
36 36 self.assertEqual(outputs[2].text, "cd")
37 37 self.assertEqual(outputs[3].text, "ef")
38 No newline at end of file
38
@@ -1,47 +1,47 b''
1 1 """
2 Module with tests for the csshtmlheader transformer
2 Module with tests for the csshtmlheader preprocessor
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 from .base import TransformerTestsBase
18 from ..csshtmlheader import CSSHTMLHeaderTransformer
17 from .base import PreprocessorTestsBase
18 from ..csshtmlheader import CSSHTMLHeaderPreprocessor
19 19
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Class
23 23 #-----------------------------------------------------------------------------
24 24
25 class TestCSSHTMLHeader(TransformerTestsBase):
25 class TestCSSHTMLHeader(PreprocessorTestsBase):
26 26 """Contains test functions for csshtmlheader.py"""
27 27
28 28
29 def build_transformer(self):
30 """Make an instance of a transformer"""
31 transformer = CSSHTMLHeaderTransformer()
32 transformer.enabled = True
33 return transformer
29 def build_preprocessor(self):
30 """Make an instance of a preprocessor"""
31 preprocessor = CSSHTMLHeaderPreprocessor()
32 preprocessor.enabled = True
33 return preprocessor
34 34
35 35
36 36 def test_constructor(self):
37 """Can a CSSHTMLHeaderTransformer be constructed?"""
38 self.build_transformer()
37 """Can a CSSHTMLHeaderPreprocessor be constructed?"""
38 self.build_preprocessor()
39 39
40 40
41 41 def test_output(self):
42 """Test the output of the CSSHTMLHeaderTransformer"""
42 """Test the output of the CSSHTMLHeaderPreprocessor"""
43 43 nb = self.build_notebook()
44 44 res = self.build_resources()
45 transformer = self.build_transformer()
46 nb, res = transformer(nb, res)
47 assert 'css' in res['inlining'] No newline at end of file
45 preprocessor = self.build_preprocessor()
46 nb, res = preprocessor(nb, res)
47 assert 'css' in res['inlining']
@@ -1,62 +1,62 b''
1 1 """
2 Module with tests for the extractoutput transformer
2 Module with tests for the extractoutput preprocessor
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 from .base import TransformerTestsBase
18 from ..extractoutput import ExtractOutputTransformer
17 from .base import PreprocessorTestsBase
18 from ..extractoutput import ExtractOutputPreprocessor
19 19
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Class
23 23 #-----------------------------------------------------------------------------
24 24
25 class TestExtractOutput(TransformerTestsBase):
25 class TestExtractOutput(PreprocessorTestsBase):
26 26 """Contains test functions for extractoutput.py"""
27 27
28 28
29 def build_transformer(self):
30 """Make an instance of a transformer"""
31 transformer = ExtractOutputTransformer()
32 transformer.enabled = True
33 return transformer
29 def build_preprocessor(self):
30 """Make an instance of a preprocessor"""
31 preprocessor = ExtractOutputPreprocessor()
32 preprocessor.enabled = True
33 return preprocessor
34 34
35 35
36 36 def test_constructor(self):
37 """Can a ExtractOutputTransformer be constructed?"""
38 self.build_transformer()
37 """Can a ExtractOutputPreprocessor be constructed?"""
38 self.build_preprocessor()
39 39
40 40
41 41 def test_output(self):
42 """Test the output of the ExtractOutputTransformer"""
42 """Test the output of the ExtractOutputPreprocessor"""
43 43 nb = self.build_notebook()
44 44 res = self.build_resources()
45 transformer = self.build_transformer()
46 nb, res = transformer(nb, res)
45 preprocessor = self.build_preprocessor()
46 nb, res = preprocessor(nb, res)
47 47
48 48 # Check if text was extracted.
49 49 assert 'text_filename' in nb.worksheets[0].cells[0].outputs[1]
50 50 text_filename = nb.worksheets[0].cells[0].outputs[1]['text_filename']
51 51
52 52 # Check if png was extracted.
53 53 assert 'png_filename' in nb.worksheets[0].cells[0].outputs[6]
54 54 png_filename = nb.worksheets[0].cells[0].outputs[6]['png_filename']
55 55
56 56 # Verify text output
57 57 assert text_filename in res['outputs']
58 58 self.assertEqual(res['outputs'][text_filename], b'b')
59 59
60 60 # Verify png output
61 61 assert png_filename in res['outputs']
62 62 self.assertEqual(res['outputs'][png_filename], b'g')
@@ -1,51 +1,51 b''
1 1 """
2 Module with tests for the latex transformer
2 Module with tests for the latex preprocessor
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 from .base import TransformerTestsBase
18 from ..latex import LatexTransformer
17 from .base import PreprocessorTestsBase
18 from ..latex import LatexPreprocessor
19 19
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Class
23 23 #-----------------------------------------------------------------------------
24 24
25 class TestLatex(TransformerTestsBase):
25 class TestLatex(PreprocessorTestsBase):
26 26 """Contains test functions for latex.py"""
27 27
28 28
29 def build_transformer(self):
30 """Make an instance of a transformer"""
31 transformer = LatexTransformer()
32 transformer.enabled = True
33 return transformer
29 def build_preprocessor(self):
30 """Make an instance of a preprocessor"""
31 preprocessor = LatexPreprocessor()
32 preprocessor.enabled = True
33 return preprocessor
34 34
35 35 def test_constructor(self):
36 """Can a LatexTransformer be constructed?"""
37 self.build_transformer()
36 """Can a LatexPreprocessor be constructed?"""
37 self.build_preprocessor()
38 38
39 39
40 40 def test_output(self):
41 """Test the output of the LatexTransformer"""
41 """Test the output of the LatexPreprocessor"""
42 42 nb = self.build_notebook()
43 43 res = self.build_resources()
44 transformer = self.build_transformer()
45 nb, res = transformer(nb, res)
44 preprocessor = self.build_preprocessor()
45 nb, res = preprocessor(nb, res)
46 46
47 47 # Make sure the code cell wasn't modified.
48 48 self.assertEqual(nb.worksheets[0].cells[0].input, '$ e $')
49 49
50 50 # Verify that the markdown cell was processed.
51 51 self.assertEqual(nb.worksheets[0].cells[1].source, '$e$')
@@ -1,94 +1,94 b''
1 1 """
2 Module with tests for the revealhelp transformer
2 Module with tests for the revealhelp preprocessor
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 IPython.nbformat import current as nbformat
18 18
19 from .base import TransformerTestsBase
20 from ..revealhelp import RevealHelpTransformer
19 from .base import PreprocessorTestsBase
20 from ..revealhelp import RevealHelpPreprocessor
21 21
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Class
25 25 #-----------------------------------------------------------------------------
26 26
27 class Testrevealhelp(TransformerTestsBase):
27 class Testrevealhelp(PreprocessorTestsBase):
28 28 """Contains test functions for revealhelp.py"""
29 29
30 30 def build_notebook(self):
31 31 """Build a reveal slides notebook in memory for use with tests.
32 Overrides base in TransformerTestsBase"""
32 Overrides base in PreprocessorTestsBase"""
33 33
34 34 outputs = [nbformat.new_output(output_type="stream", stream="stdout", output_text="a")]
35 35
36 36 slide_metadata = {'slideshow' : {'slide_type': 'slide'}}
37 37 subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}}
38 38
39 39 cells=[nbformat.new_code_cell(input="", prompt_number=1, outputs=outputs),
40 40 nbformat.new_text_cell('markdown', source="", metadata=slide_metadata),
41 41 nbformat.new_code_cell(input="", prompt_number=2, outputs=outputs),
42 42 nbformat.new_text_cell('markdown', source="", metadata=slide_metadata),
43 43 nbformat.new_text_cell('markdown', source="", metadata=subslide_metadata)]
44 44 worksheets = [nbformat.new_worksheet(name="worksheet1", cells=cells)]
45 45
46 46 return nbformat.new_notebook(name="notebook1", worksheets=worksheets)
47 47
48 48
49 def build_transformer(self):
50 """Make an instance of a transformer"""
51 transformer = RevealHelpTransformer()
52 transformer.enabled = True
53 return transformer
49 def build_preprocessor(self):
50 """Make an instance of a preprocessor"""
51 preprocessor = RevealHelpPreprocessor()
52 preprocessor.enabled = True
53 return preprocessor
54 54
55 55
56 56 def test_constructor(self):
57 """Can a RevealHelpTransformer be constructed?"""
58 self.build_transformer()
57 """Can a RevealHelpPreprocessor be constructed?"""
58 self.build_preprocessor()
59 59
60 60
61 61 def test_reveal_attribute(self):
62 62 """Make sure the reveal url_prefix resources is set"""
63 63 nb = self.build_notebook()
64 64 res = self.build_resources()
65 transformer = self.build_transformer()
66 nb, res = transformer(nb, res)
65 preprocessor = self.build_preprocessor()
66 nb, res = preprocessor(nb, res)
67 67 assert 'reveal' in res
68 68 assert 'url_prefix' in res['reveal']
69 69
70 70
71 71 def test_reveal_output(self):
72 """Make sure that the reveal transformer """
72 """Make sure that the reveal preprocessor """
73 73 nb = self.build_notebook()
74 74 res = self.build_resources()
75 transformer = self.build_transformer()
76 nb, res = transformer(nb, res)
75 preprocessor = self.build_preprocessor()
76 nb, res = preprocessor(nb, res)
77 77 cells = nb.worksheets[0].cells
78 78
79 79 # Make sure correct metadata tags are available on every cell.
80 80 for cell in cells:
81 81 assert 'slide_type' in cell.metadata
82 82 assert 'align_type' in cell.metadata
83 83
84 84 # Make sure slide end is only applied to the cells preceeding slide
85 85 # cells.
86 86 assert 'slide_helper' not in cells[1].metadata
87 87
88 88 # Verify 'slide-end'
89 89 assert 'slide_helper' in cells[0].metadata
90 90 self.assertEqual(cells[0].metadata['slide_helper'], 'slide_end')
91 91 assert 'slide_helper' in cells[2].metadata
92 92 self.assertEqual(cells[2].metadata['slide_helper'], 'slide_end')
93 93 assert 'slide_helper' in cells[3].metadata
94 94 self.assertEqual(cells[3].metadata['slide_helper'], 'subslide_end')
@@ -1,57 +1,57 b''
1 1 """
2 Module with tests for the sphinx transformer
2 Module with tests for the sphinx preprocessor
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 from .base import TransformerTestsBase
18 from ..sphinx import SphinxTransformer
17 from .base import PreprocessorTestsBase
18 from ..sphinx import SphinxPreprocessor
19 19
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Class
23 23 #-----------------------------------------------------------------------------
24 24
25 class TestSphinx(TransformerTestsBase):
25 class TestSphinx(PreprocessorTestsBase):
26 26 """Contains test functions for sphinx.py"""
27 27
28 28
29 def build_transformer(self):
30 """Make an instance of a transformer"""
31 transformer = SphinxTransformer()
32 transformer.enabled = True
33 return transformer
29 def build_preprocessor(self):
30 """Make an instance of a preprocessor"""
31 preprocessor = SphinxPreprocessor()
32 preprocessor.enabled = True
33 return preprocessor
34 34
35 35
36 36 def test_constructor(self):
37 """Can a SphinxTransformer be constructed?"""
38 self.build_transformer()
37 """Can a SphinxPreprocessor be constructed?"""
38 self.build_preprocessor()
39 39
40 40
41 41 def test_resources(self):
42 """Make sure the SphinxTransformer adds the appropriate resources to the
42 """Make sure the SphinxPreprocessor adds the appropriate resources to the
43 43 resources dict."""
44 44 nb = self.build_notebook()
45 45 res = self.build_resources()
46 transformer = self.build_transformer()
47 nb, res = transformer(nb, res)
46 preprocessor = self.build_preprocessor()
47 nb, res = preprocessor(nb, res)
48 48 assert "author" in res['sphinx']
49 49 assert "version" in res['sphinx']
50 50 assert "release" in res['sphinx']
51 51 assert "date" in res['sphinx']
52 52 assert "chapterstyle" in res['sphinx']
53 53 assert "outputstyle" in res['sphinx']
54 54 assert "centeroutput" in res['sphinx']
55 55 assert "header" in res['sphinx']
56 56 assert "texinputs" in res['sphinx']
57 57 assert "pygment_definitions" in res['sphinx']
@@ -1,90 +1,90 b''
1 1 """
2 Module with tests for the svg2pdf transformer
2 Module with tests for the svg2pdf preprocessor
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 IPython.testing import decorators as dec
18 18 from IPython.nbformat import current as nbformat
19 19
20 from .base import TransformerTestsBase
21 from ..svg2pdf import SVG2PDFTransformer
20 from .base import PreprocessorTestsBase
21 from ..svg2pdf import SVG2PDFPreprocessor
22 22
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Class
26 26 #-----------------------------------------------------------------------------
27 27
28 class Testsvg2pdf(TransformerTestsBase):
28 class Testsvg2pdf(PreprocessorTestsBase):
29 29 """Contains test functions for svg2pdf.py"""
30 30
31 31 simple_svg = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
32 32 <!-- Created with Inkscape (http://www.inkscape.org/) -->
33 33 <svg
34 34 xmlns:svg="http://www.w3.org/2000/svg"
35 35 xmlns="http://www.w3.org/2000/svg"
36 36 version="1.0"
37 37 x="0.00000000"
38 38 y="0.00000000"
39 39 width="500.00000"
40 40 height="500.00000"
41 41 id="svg2">
42 42 <defs
43 43 id="defs4" />
44 44 <g
45 45 id="layer1">
46 46 <rect
47 47 width="300.00000"
48 48 height="300.00000"
49 49 x="100.00000"
50 50 y="100.00000"
51 51 style="opacity:1.0000000;fill:none;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:8.0000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.00000000;stroke-opacity:1.0000000"
52 52 id="rect5719" />
53 53 </g>
54 54 </svg>"""
55 55
56 56 def build_notebook(self):
57 57 """Build a reveal slides notebook in memory for use with tests.
58 Overrides base in TransformerTestsBase"""
58 Overrides base in PreprocessorTestsBase"""
59 59
60 60 outputs = [nbformat.new_output(output_type="svg", output_svg=self.simple_svg)]
61 61
62 62 slide_metadata = {'slideshow' : {'slide_type': 'slide'}}
63 63 subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}}
64 64
65 65 cells=[nbformat.new_code_cell(input="", prompt_number=1, outputs=outputs)]
66 66 worksheets = [nbformat.new_worksheet(name="worksheet1", cells=cells)]
67 67
68 68 return nbformat.new_notebook(name="notebook1", worksheets=worksheets)
69 69
70 70
71 def build_transformer(self):
72 """Make an instance of a transformer"""
73 transformer = SVG2PDFTransformer()
74 transformer.enabled = True
75 return transformer
71 def build_preprocessor(self):
72 """Make an instance of a preprocessor"""
73 preprocessor = SVG2PDFPreprocessor()
74 preprocessor.enabled = True
75 return preprocessor
76 76
77 77
78 78 def test_constructor(self):
79 """Can a SVG2PDFTransformer be constructed?"""
80 self.build_transformer()
79 """Can a SVG2PDFPreprocessor be constructed?"""
80 self.build_preprocessor()
81 81
82 82
83 83 @dec.onlyif_cmds_exist('inkscape')
84 84 def test_output(self):
85 """Test the output of the SVG2PDFTransformer"""
85 """Test the output of the SVG2PDFPreprocessor"""
86 86 nb = self.build_notebook()
87 87 res = self.build_resources()
88 transformer = self.build_transformer()
89 nb, res = transformer(nb, res)
88 preprocessor = self.build_preprocessor()
89 nb, res = preprocessor(nb, res)
90 90 assert 'svg' in nb.worksheets[0].cells[0].outputs[0]
@@ -1,115 +1,115 b''
1 1 """
2 2 Contains writer for writing nbconvert output to filesystem.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 #Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 #Distributed under the terms of the Modified BSD License.
8 8 #
9 9 #The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 import io
17 17 import os
18 18 import glob
19 19
20 20 from IPython.utils.traitlets import Unicode
21 21 from IPython.utils.path import link_or_copy
22 22
23 23 from .base import WriterBase
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Classes
27 27 #-----------------------------------------------------------------------------
28 28
29 29 class FilesWriter(WriterBase):
30 30 """Consumes nbconvert output and produces files."""
31 31
32 32
33 33 build_directory = Unicode("", config=True,
34 34 help="""Directory to write output to. Leave blank
35 35 to output to the current directory""")
36 36
37 37
38 38 # Make sure that the output directory exists.
39 39 def _build_directory_changed(self, name, old, new):
40 40 if new and not os.path.isdir(new):
41 41 os.makedirs(new)
42 42
43 43
44 44 def __init__(self, **kw):
45 45 super(FilesWriter, self).__init__(**kw)
46 46 self._build_directory_changed('build_directory', self.build_directory,
47 47 self.build_directory)
48 48
49 49 def _makedir(self, path):
50 50 """Make a directory if it doesn't already exist"""
51 51 if path and not os.path.isdir(path):
52 52 self.log.info("Making directory %s", path)
53 53 os.makedirs(path)
54 54
55 55 def write(self, output, resources, notebook_name=None, **kw):
56 56 """
57 57 Consume and write Jinja output to the file system. Output directory
58 58 is set via the 'build_directory' variable of this instance (a
59 59 configurable).
60 60
61 61 See base for more...
62 62 """
63 63
64 64 # Verify that a notebook name is provided.
65 65 if notebook_name is None:
66 66 raise TypeError('notebook_name')
67 67
68 68 # Pull the extension and subdir from the resources dict.
69 69 output_extension = resources.get('output_extension', None)
70 70
71 71 # Write all of the extracted resources to the destination directory.
72 72 # NOTE: WE WRITE EVERYTHING AS-IF IT'S BINARY. THE EXTRACT FIG
73 # TRANSFORMER SHOULD HANDLE UNIX/WINDOWS LINE ENDINGS...
73 # PREPROCESSOR SHOULD HANDLE UNIX/WINDOWS LINE ENDINGS...
74 74 for filename, data in resources.get('outputs', {}).items():
75 75
76 76 # Determine where to write the file to
77 77 dest = os.path.join(self.build_directory, filename)
78 78 path = os.path.dirname(dest)
79 79 self._makedir(path)
80 80
81 81 # Write file
82 82 self.log.debug("Writing %i bytes to support file %s", len(data), dest)
83 83 with io.open(dest, 'wb') as f:
84 84 f.write(data)
85 85
86 86 # Copy referenced files to output directory
87 87 if self.build_directory:
88 88 for filename in self.files:
89 89
90 90 # Copy files that match search pattern
91 91 for matching_filename in glob.glob(filename):
92 92
93 93 # Make sure folder exists.
94 94 dest = os.path.join(self.build_directory, filename)
95 95 path = os.path.dirname(dest)
96 96 self._makedir(path)
97 97
98 98 # Copy if destination is different.
99 99 if not os.path.normpath(dest) == os.path.normpath(matching_filename):
100 100 self.log.info("Linking %s -> %s", matching_filename, dest)
101 101 link_or_copy(matching_filename, dest)
102 102
103 103 # Determine where to write conversion results.
104 104 if output_extension is not None:
105 105 dest = notebook_name + '.' + output_extension
106 106 else:
107 107 dest = notebook_name
108 108 if self.build_directory:
109 109 dest = os.path.join(self.build_directory, dest)
110 110
111 111 # Write conversion results.
112 112 self.log.info("Writing %i bytes to %s", len(output), dest)
113 113 with io.open(dest, 'w', encoding='utf-8') as f:
114 114 f.write(output)
115 return dest No newline at end of file
115 return dest
@@ -1,16 +1,16 b''
1 1 =====================
2 2 Development version
3 3 =====================
4 4
5 5 This document describes in-flight development work.
6 6
7 7
8 8 Backwards incompatible changes
9 9 ------------------------------
10 10
11 11 * Python 2.6 and 3.2 are no longer supported: the minimum required
12 12 Python versions are now 2.7 and 3.3.
13 * The `call` methods for nbconvert transformers has been renamed to
14 `transform`.
13 * The Transformer classes have been renamed to Preprocessor in nbconvert and
14 their `call` methods for them have been renamed to `preprocess`.
15 15 * The `call` methods of nbconvert post-processsors have been renamed to
16 16 `postprocess`.
General Comments 0
You need to be logged in to leave comments. Login now